Commit 322c9502a32ebc9aeee8179c5eac890ca876211c

Authored by Julien Cartigny
1 parent 88ff471f

Ad Spring security support and validation

Showing 31 changed files with 309 additions and 492 deletions   Show diff stats
@@ -36,15 +36,15 @@ @@ -36,15 +36,15 @@
36 <groupId>org.springframework.boot</groupId> 36 <groupId>org.springframework.boot</groupId>
37 <artifactId>spring-boot-starter-web</artifactId> 37 <artifactId>spring-boot-starter-web</artifactId>
38 </dependency> 38 </dependency>
39 - <!--dependency>  
40 - <groupId>org.springframework.boot</groupId>  
41 - <artifactId>spring-boot-starter-security</artifactId>  
42 - </dependency-->  
43 <dependency> 39 <dependency>
44 <groupId>org.springframework.boot</groupId> 40 <groupId>org.springframework.boot</groupId>
45 <artifactId>spring-boot-starter-tomcat</artifactId> 41 <artifactId>spring-boot-starter-tomcat</artifactId>
46 <scope>provided</scope> 42 <scope>provided</scope>
47 </dependency> 43 </dependency>
  44 + <dependency>
  45 + <groupId>org.springframework.boot</groupId>
  46 + <artifactId>spring-boot-starter-security</artifactId>
  47 + </dependency>
48 <dependency> 48 <dependency>
49 <groupId>org.springframework.boot</groupId> 49 <groupId>org.springframework.boot</groupId>
50 <artifactId>spring-boot-starter-test</artifactId> 50 <artifactId>spring-boot-starter-test</artifactId>
src/main/java/fr/plil/sio/web/mvc/Application.java
@@ -2,11 +2,18 @@ package fr.plil.sio.web.mvc; @@ -2,11 +2,18 @@ package fr.plil.sio.web.mvc;
2 2
3 import org.springframework.boot.SpringApplication; 3 import org.springframework.boot.SpringApplication;
4 import org.springframework.boot.autoconfigure.SpringBootApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
  5 +import org.springframework.boot.builder.SpringApplicationBuilder;
  6 +import org.springframework.boot.web.support.SpringBootServletInitializer;
5 7
6 8
7 @SpringBootApplication 9 @SpringBootApplication
8 -public class Application { 10 +public class Application extends SpringBootServletInitializer {
9 public static void main(String[] args) { 11 public static void main(String[] args) {
10 SpringApplication.run(Application.class, args); 12 SpringApplication.run(Application.class, args);
11 } 13 }
  14 +
  15 + @Override
  16 + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
  17 + return application.sources(Application.class);
  18 + }
12 } 19 }
src/main/java/fr/plil/sio/web/mvc/ApplicationMvcConfiguration.java
1 package fr.plil.sio.web.mvc; 1 package fr.plil.sio.web.mvc;
2 2
3 3
4 -import org.slf4j.Logger;  
5 -import org.slf4j.LoggerFactory;  
6 import org.springframework.boot.SpringBootConfiguration; 4 import org.springframework.boot.SpringBootConfiguration;
7 import org.springframework.context.annotation.Bean; 5 import org.springframework.context.annotation.Bean;
8 -import org.springframework.context.annotation.Scope;  
9 -import org.springframework.context.annotation.ScopedProxyMode;  
10 -import org.springframework.web.context.WebApplicationContext; 6 +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  7 +import org.springframework.security.crypto.password.PasswordEncoder;
11 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 8 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
12 9
13 @SpringBootConfiguration 10 @SpringBootConfiguration
14 public class ApplicationMvcConfiguration extends WebMvcConfigurerAdapter { 11 public class ApplicationMvcConfiguration extends WebMvcConfigurerAdapter {
15 12
16 - private static final Logger logger = LoggerFactory.getLogger(ApplicationMvcConfiguration.class);  
17 -  
18 - @Bean  
19 - @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode. TARGET_CLASS)  
20 - public UserSession userSession() {  
21 - logger.debug("new user session bean");  
22 - return new UserSession();  
23 - }  
24 -  
25 -/*  
26 @Bean 13 @Bean
27 - public CheckUserInterceptor checkUserInterceptor() {  
28 - return new CheckUserInterceptor();  
29 - }  
30 -  
31 - @Override  
32 - public void addInterceptors(InterceptorRegistry registry) {  
33 - CheckUserInterceptor interceptor = checkUserInterceptor();  
34 - interceptor.setUserSession(userSession());  
35 - registry.addInterceptor(interceptor); 14 + public PasswordEncoder passwordEncoder() {
  15 + return new BCryptPasswordEncoder();
36 } 16 }
37 -*/  
38 } 17 }
src/main/java/fr/plil/sio/web/mvc/ApplicationSecurityConfiguration.java 0 โ†’ 100644
@@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
  1 +package fr.plil.sio.web.mvc;
  2 +
  3 +import org.springframework.beans.factory.annotation.Autowired;
  4 +import org.springframework.context.annotation.Configuration;
  5 +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  6 +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  7 +import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  8 +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  9 +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  10 +import org.springframework.security.core.userdetails.UserDetailsService;
  11 +import org.springframework.security.crypto.password.PasswordEncoder;
  12 +
  13 +import javax.annotation.Resource;
  14 +
  15 +@Configuration
  16 +@EnableWebSecurity
  17 +@EnableGlobalMethodSecurity(prePostEnabled = true)
  18 +public class ApplicationSecurityConfiguration extends WebSecurityConfigurerAdapter {
  19 +
  20 + @Resource
  21 + private PasswordEncoder passwordEncoder;
  22 +
  23 + @Resource
  24 + private UserDetailsService userDetailsService;
  25 +
  26 + @Override
  27 + protected void configure(HttpSecurity http) throws Exception {
  28 + http
  29 + .authorizeRequests()
  30 + .anyRequest().authenticated()
  31 + .and()
  32 + .formLogin()
  33 + .loginPage("/login")
  34 + .permitAll()
  35 + .and()
  36 + .logout()
  37 + .permitAll();
  38 + }
  39 +
  40 + @Autowired
  41 + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
  42 + auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
  43 + }
  44 +}
0 \ No newline at end of file 45 \ No newline at end of file
src/main/java/fr/plil/sio/web/mvc/CheckUserInterceptor.java deleted
@@ -1,45 +0,0 @@ @@ -1,45 +0,0 @@
1 -package fr.plil.sio.web.mvc;  
2 -  
3 -import org.slf4j.Logger;  
4 -import org.slf4j.LoggerFactory;  
5 -import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;  
6 -  
7 -import javax.annotation.Resource;  
8 -import javax.servlet.http.HttpServletRequest;  
9 -import javax.servlet.http.HttpServletResponse;  
10 -import java.io.IOException;  
11 -  
12 -public class CheckUserInterceptor extends HandlerInterceptorAdapter {  
13 -  
14 - private static final Logger logger = LoggerFactory.getLogger(CheckUserInterceptor.class);  
15 -  
16 - @Resource  
17 - private UserSession userSession;  
18 -  
19 - @Override  
20 - public boolean preHandle(HttpServletRequest request, HttpServletResponse response,  
21 - Object handler) throws IOException {  
22 -  
23 - logger.debug("servlet path: " + request.getServletPath());  
24 -  
25 - if (request.getServletPath().equals("/login")) {  
26 - logger.debug("access granted as path is /login");  
27 - return true;  
28 - }  
29 -  
30 - String username = userSession.getUsername();  
31 -  
32 - if (username != null) {  
33 - logger.debug("authenticated");  
34 - return true;  
35 - } else {  
36 - logger.debug("not authenticated");  
37 - response.sendRedirect("login");  
38 - return false;  
39 - }  
40 - }  
41 -  
42 - void setUserSession(UserSession userSession) {  
43 - this.userSession = userSession;  
44 - }  
45 -}  
src/main/java/fr/plil/sio/web/mvc/LoginController.java
1 package fr.plil.sio.web.mvc; 1 package fr.plil.sio.web.mvc;
2 2
3 import org.springframework.stereotype.Controller; 3 import org.springframework.stereotype.Controller;
4 -import org.springframework.validation.BindingResult;  
5 import org.springframework.web.bind.annotation.RequestMapping; 4 import org.springframework.web.bind.annotation.RequestMapping;
6 import org.springframework.web.bind.annotation.RequestMethod; 5 import org.springframework.web.bind.annotation.RequestMethod;
7 import org.springframework.web.servlet.ModelAndView; 6 import org.springframework.web.servlet.ModelAndView;
8 7
9 -import javax.annotation.Resource;  
10 -  
11 @Controller 8 @Controller
12 -@RequestMapping(value = "/login")  
13 public class LoginController { 9 public class LoginController {
14 10
15 - @Resource  
16 - private UserRepository userRepository;  
17 -  
18 - @Resource  
19 - private UserSession userSession;  
20 -  
21 - @RequestMapping(method = RequestMethod.GET)  
22 - public ModelAndView getLoginForm() {  
23 - return new ModelAndView("login", "user", new User());  
24 - } 11 + @RequestMapping(value = "/login", method = RequestMethod.GET)
  12 + public ModelAndView login(String error, String logout) {
25 13
26 - @RequestMapping(method = RequestMethod.POST)  
27 - public String postLoginCheck(User user, BindingResult result) { 14 + ModelAndView modelAndView = new ModelAndView("login");
28 15
29 - User userFromRepository = userRepository.findByUsername(user.getUsername());  
30 -  
31 - if (userFromRepository == null) {  
32 - result.rejectValue("username","login.form.invalid");  
33 - return "login"; 16 + if (error != null) {
  17 + modelAndView.addObject("error", "Your username and password is invalid.");
34 } 18 }
35 19
36 - if (!userFromRepository.getPassword().equals(user.getPassword())) {  
37 - result.rejectValue("username","login.form.invalid");  
38 - return "login"; 20 + if (logout != null) {
  21 + modelAndView.addObject("message", "You have been logged out successfully.");
39 } 22 }
40 23
41 - userSession.setUsername(userFromRepository.getUsername());  
42 -  
43 - return "redirect:/";  
44 - }  
45 -  
46 - public void setUserRepository(UserRepository userRepository) {  
47 - this.userRepository = userRepository;  
48 - }  
49 -  
50 - public void setUserSession(UserSession userSession) {  
51 - this.userSession = userSession; 24 + return modelAndView;
52 } 25 }
53 -}  
54 \ No newline at end of file 26 \ No newline at end of file
  27 +}
src/main/java/fr/plil/sio/web/mvc/LogoutController.java deleted
@@ -1,23 +0,0 @@ @@ -1,23 +0,0 @@
1 -package fr.plil.sio.web.mvc;  
2 -  
3 -import javax.annotation.Resource;  
4 -import org.springframework.stereotype.Controller;  
5 -import org.springframework.web.bind.annotation.RequestMapping;  
6 -import org.springframework.web.bind.annotation.RequestMethod;  
7 -  
8 -@Controller  
9 -public class LogoutController {  
10 -  
11 - @Resource  
12 - private UserSession userSession;  
13 -  
14 - @RequestMapping(value = {"/logout"}, method = RequestMethod.GET)  
15 - public String getLogout() {  
16 - userSession.setUsername(null);  
17 - return "redirect:/";  
18 - }  
19 -  
20 - public void setUserSession(UserSession userSession) {  
21 - this.userSession = userSession;  
22 - }  
23 -}  
src/main/java/fr/plil/sio/web/mvc/NewUserController.java
1 package fr.plil.sio.web.mvc; 1 package fr.plil.sio.web.mvc;
2 2
  3 +import org.springframework.security.access.prepost.PreAuthorize;
3 import org.springframework.stereotype.Controller; 4 import org.springframework.stereotype.Controller;
4 import org.springframework.validation.BindingResult; 5 import org.springframework.validation.BindingResult;
5 -import org.springframework.web.bind.annotation.ModelAttribute;  
6 import org.springframework.web.bind.annotation.RequestMapping; 6 import org.springframework.web.bind.annotation.RequestMapping;
7 import org.springframework.web.bind.annotation.RequestMethod; 7 import org.springframework.web.bind.annotation.RequestMethod;
8 import org.springframework.web.servlet.ModelAndView; 8 import org.springframework.web.servlet.ModelAndView;
9 9
10 import javax.annotation.Resource; 10 import javax.annotation.Resource;
  11 +import javax.validation.Valid;
11 12
12 @Controller 13 @Controller
  14 +@RequestMapping(value = {"/newUser"})
13 public class NewUserController { 15 public class NewUserController {
14 16
15 @Resource 17 @Resource
16 - private UserRepository userRepository;  
17 -  
18 - @Resource  
19 private UserService userService; 18 private UserService userService;
20 19
21 - @Resource  
22 - private UserSession userSession;  
23 -  
24 - @Resource  
25 - private UserFormValidator userFormValidator;  
26 -  
27 - @RequestMapping(value = {"/newUser"}, method = RequestMethod.GET) 20 + @RequestMapping(method = RequestMethod.GET)
28 public ModelAndView getNewUserForm() { 21 public ModelAndView getNewUserForm() {
29 - return new ModelAndView("newUser", "user", new User()); 22 + return new ModelAndView("newUser", "userForm", new UserForm());
30 } 23 }
31 24
32 - @RequestMapping(value = {"/newUser"}, method = RequestMethod.POST)  
33 - public String postNewUser(@ModelAttribute("userForm") UserForm user,  
34 - BindingResult result) {  
35 -  
36 - if (!userSession.getUsername().equals("admin")) {  
37 - result.rejectValue("username", "new.user.only.admin");  
38 - } 25 + @PreAuthorize("hasRole('ROLE_ADMIN')")
  26 + @RequestMapping(method = RequestMethod.POST)
  27 + public String postNewUser(@Valid UserForm userForm, BindingResult result) {
39 28
40 - userFormValidator.validate(user, result);  
41 -  
42 - boolean present = (userRepository.findByUsername(user.getUsername()) != null); 29 + boolean present = (userService.findByUsername(userForm.getUsername()) != null);
43 30
44 if (present) { 31 if (present) {
45 result.rejectValue("username", "new.user.form.present"); 32 result.rejectValue("username", "new.user.form.present");
@@ -49,23 +36,11 @@ public class NewUserController { @@ -49,23 +36,11 @@ public class NewUserController {
49 return "newUser"; 36 return "newUser";
50 } 37 }
51 38
52 - userService.createUser(user.getUsername(), user.getPassword()); 39 + userService.createUser(userForm.getUsername(), userForm.getPassword());
53 40
54 return "redirect:/"; 41 return "redirect:/";
55 } 42 }
56 43
57 - public void setUserRepository(UserRepository userRepository) {  
58 - this.userRepository = userRepository;  
59 - }  
60 -  
61 - public void setUserSession(UserSession userSession) {  
62 - this.userSession = userSession;  
63 - }  
64 -  
65 - public void setUserFormValidator(UserFormValidator userFormValidator) {  
66 - this.userFormValidator = userFormValidator;  
67 - }  
68 -  
69 public void setUserService(UserService userService) { 44 public void setUserService(UserService userService) {
70 this.userService = userService; 45 this.userService = userService;
71 } 46 }
src/main/java/fr/plil/sio/web/mvc/Role.java 0 โ†’ 100644
@@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
  1 +package fr.plil.sio.web.mvc;
  2 +
  3 +import org.springframework.security.core.GrantedAuthority;
  4 +
  5 +import javax.persistence.*;
  6 +import java.util.Set;
  7 +import java.util.TreeSet;
  8 +
  9 +@Entity
  10 +@Table(name = "ROLE_T")
  11 +public class Role implements GrantedAuthority {
  12 +
  13 + @Id
  14 + @Column(name = "ROLE_ID")
  15 + @GeneratedValue(strategy = GenerationType.AUTO)
  16 + private Long id;
  17 +
  18 + @Column(name = "NAME_F")
  19 + private String name;
  20 +
  21 + @ManyToMany
  22 + @JoinTable(
  23 + name = "USER_ROLE_T",
  24 + joinColumns = @JoinColumn(name = "ROLE_ID", referencedColumnName = "ROLE_ID"),
  25 + inverseJoinColumns = @JoinColumn(name = "USER_ID", referencedColumnName = "USER_ID"))
  26 + private Set<User> users = new TreeSet<>();
  27 +
  28 + public Long getId() {
  29 + return id;
  30 + }
  31 +
  32 + public void setId(Long id) {
  33 + this.id = id;
  34 + }
  35 +
  36 + public String getName() {
  37 + return name;
  38 + }
  39 +
  40 + public void setName(String name) {
  41 + this.name = name;
  42 + }
  43 +
  44 + public Set<User> getUsers() {
  45 + return users;
  46 + }
  47 +
  48 + public void setUsers(Set<User> users) {
  49 + this.users = users;
  50 + }
  51 +
  52 + @Override
  53 + public String getAuthority() {
  54 + return name;
  55 + }
  56 +}
src/main/java/fr/plil/sio/web/mvc/RoleRepository.java 0 โ†’ 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +package fr.plil.sio.web.mvc;
  2 +
  3 +import org.springframework.data.jpa.repository.JpaRepository;
  4 +
  5 +public interface RoleRepository extends JpaRepository<Role, Long> {
  6 +
  7 + Role findByName(String name);
  8 +}
src/main/java/fr/plil/sio/web/mvc/User.java
1 package fr.plil.sio.web.mvc; 1 package fr.plil.sio.web.mvc;
2 2
3 3
  4 +import org.springframework.security.core.GrantedAuthority;
  5 +import org.springframework.security.core.userdetails.UserDetails;
  6 +
4 import javax.persistence.*; 7 import javax.persistence.*;
  8 +import java.util.Collection;
  9 +import java.util.Set;
  10 +import java.util.TreeSet;
5 11
6 @Entity 12 @Entity
7 -public class User { 13 +@Table(name = "USER_T")
  14 +public class User implements UserDetails {
8 15
9 @Id 16 @Id
  17 + @Column(name = "USER_ID")
10 @GeneratedValue(strategy = GenerationType.AUTO) 18 @GeneratedValue(strategy = GenerationType.AUTO)
11 private Long id; 19 private Long id;
12 20
13 - @Column 21 + @Column(name = "USERNAME_F")
14 private String username; 22 private String username;
15 23
16 - @Column 24 + @Column(name = "PASSWORD_F")
17 private String password; 25 private String password;
18 26
19 - public User() { 27 + @ManyToMany(mappedBy = "users", fetch = FetchType.EAGER)
  28 + private Set<Role> roles = new TreeSet<>();
  29 +
  30 + public Set<Role> getRoles() {
  31 + return roles;
20 } 32 }
21 33
22 - public User(String username, String password) {  
23 - this.username = username;  
24 - this.password = password; 34 + public void setRoles(Set<Role> roles) {
  35 + this.roles = roles;
  36 + }
  37 +
  38 +
  39 + @Override
  40 + public Collection<? extends GrantedAuthority> getAuthorities() {
  41 + return roles;
25 } 42 }
26 43
27 public String getUsername() { 44 public String getUsername() {
@@ -32,6 +49,26 @@ public class User { @@ -32,6 +49,26 @@ public class User {
32 this.username = username; 49 this.username = username;
33 } 50 }
34 51
  52 + @Override
  53 + public boolean isAccountNonExpired() {
  54 + return true;
  55 + }
  56 +
  57 + @Override
  58 + public boolean isAccountNonLocked() {
  59 + return true;
  60 + }
  61 +
  62 + @Override
  63 + public boolean isCredentialsNonExpired() {
  64 + return true;
  65 + }
  66 +
  67 + @Override
  68 + public boolean isEnabled() {
  69 + return true;
  70 + }
  71 +
35 public String getPassword() { 72 public String getPassword() {
36 return password; 73 return password;
37 } 74 }
src/main/java/fr/plil/sio/web/mvc/UserDetailsServiceImpl.java 0 โ†’ 100644
@@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
  1 +package fr.plil.sio.web.mvc;
  2 +
  3 +import org.springframework.security.core.userdetails.UserDetails;
  4 +import org.springframework.security.core.userdetails.UserDetailsService;
  5 +import org.springframework.security.core.userdetails.UsernameNotFoundException;
  6 +import org.springframework.stereotype.Service;
  7 +
  8 +import javax.annotation.Resource;
  9 +
  10 +@Service
  11 +public class UserDetailsServiceImpl implements UserDetailsService {
  12 +
  13 + @Resource
  14 + private UserService userService;
  15 +
  16 + @Override
  17 + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  18 + User user = userService.findByUsername(username);
  19 +
  20 + if (user == null) {
  21 + throw new UsernameNotFoundException("cannot found user " + username);
  22 + }
  23 +
  24 + return user;
  25 + }
  26 +}
0 \ No newline at end of file 27 \ No newline at end of file
src/main/java/fr/plil/sio/web/mvc/UserForm.java
1 package fr.plil.sio.web.mvc; 1 package fr.plil.sio.web.mvc;
2 2
3 -import javax.validation.constraints.Max;  
4 -import javax.validation.constraints.Min;  
5 import javax.validation.constraints.NotNull; 3 import javax.validation.constraints.NotNull;
  4 +import javax.validation.constraints.Size;
6 5
7 public class UserForm { 6 public class UserForm {
8 7
9 - @Min(3)  
10 - @Max(16) 8 + @NotNull
  9 + @Size(min = 3, max = 16)
11 private String username; 10 private String username;
12 11
13 @NotNull 12 @NotNull
  13 + @Size(min = 4)
14 private String password; 14 private String password;
15 15
16 public String getUsername() { 16 public String getUsername() {
src/main/java/fr/plil/sio/web/mvc/UserFormValidator.java deleted
@@ -1,41 +0,0 @@ @@ -1,41 +0,0 @@
1 -package fr.plil.sio.web.mvc;  
2 -  
3 -import org.springframework.stereotype.Component;  
4 -import org.springframework.validation.Errors;  
5 -import org.springframework.validation.Validator;  
6 -  
7 -@Component  
8 -public class UserFormValidator implements Validator {  
9 -  
10 - @Override  
11 - public boolean supports(Class<?> clazz) {  
12 - return UserForm.class.equals(clazz);  
13 - }  
14 -  
15 - private void checkUsername(String username, Errors errors) {  
16 -  
17 - }  
18 -  
19 - private void checkPassword(String password, Errors errors) {  
20 - boolean hasUppercase = !password.equals(password.toLowerCase());  
21 - boolean hasLowercase = !password.equals(password.toUpperCase());  
22 - boolean hasSpecial = !password.matches("[A-Za-z0-9 ]*");  
23 -  
24 - if (!hasUppercase) {  
25 - errors.rejectValue("password", "validator.user.form.must.contains.uppercase");  
26 - }  
27 - if (!hasLowercase) {  
28 - errors.rejectValue("password", "validator.user.form.must.contains.lowercase");  
29 - }  
30 - if (!hasSpecial) {  
31 - errors.rejectValue("password", "validator.user.form.must.contains.special.char");  
32 - }  
33 - }  
34 -  
35 - @Override  
36 - public void validate(Object target, Errors errors) {  
37 - UserForm user = (UserForm) target;  
38 - checkUsername(user.getUsername(), errors);  
39 - checkPassword(user.getPassword(), errors);  
40 - }  
41 -}  
42 \ No newline at end of file 0 \ No newline at end of file
src/main/java/fr/plil/sio/web/mvc/UserService.java
@@ -3,4 +3,6 @@ package fr.plil.sio.web.mvc; @@ -3,4 +3,6 @@ package fr.plil.sio.web.mvc;
3 public interface UserService { 3 public interface UserService {
4 4
5 User createUser(String username, String password); 5 User createUser(String username, String password);
  6 +
  7 + User findByUsername(String username);
6 } 8 }
src/main/java/fr/plil/sio/web/mvc/UserServiceImpl.java
1 package fr.plil.sio.web.mvc; 1 package fr.plil.sio.web.mvc;
2 2
  3 +import org.springframework.security.crypto.password.PasswordEncoder;
3 import org.springframework.stereotype.Service; 4 import org.springframework.stereotype.Service;
4 import org.springframework.transaction.annotation.Transactional; 5 import org.springframework.transaction.annotation.Transactional;
5 6
6 import javax.annotation.Resource; 7 import javax.annotation.Resource;
  8 +import java.util.HashSet;
  9 +import java.util.Set;
7 10
8 @Service("userService") 11 @Service("userService")
9 public class UserServiceImpl implements UserService { 12 public class UserServiceImpl implements UserService {
@@ -11,13 +14,27 @@ public class UserServiceImpl implements UserService { @@ -11,13 +14,27 @@ public class UserServiceImpl implements UserService {
11 @Resource 14 @Resource
12 private UserRepository userRepository; 15 private UserRepository userRepository;
13 16
  17 + @Resource
  18 + private RoleRepository roleRepository;
  19 +
  20 + @Resource
  21 + private PasswordEncoder passwordEncoder;
  22 +
14 @Override 23 @Override
15 @Transactional 24 @Transactional
16 public User createUser(String username, String password) { 25 public User createUser(String username, String password) {
17 User user = new User(); 26 User user = new User();
18 user.setUsername(username); 27 user.setUsername(username);
19 - user.setPassword(password); 28 + user.setPassword(passwordEncoder.encode(password));
  29 + Set<Role> roles = new HashSet<>();
  30 + roles.add(roleRepository.findByName("ROLE_USER"));
  31 + user.setRoles(roles);
20 userRepository.save(user); 32 userRepository.save(user);
21 return user; 33 return user;
22 } 34 }
  35 +
  36 + @Override
  37 + public User findByUsername(String username) {
  38 + return userRepository.findByUsername(username);
  39 + }
23 } 40 }
src/main/java/fr/plil/sio/web/mvc/UserSession.java deleted
@@ -1,16 +0,0 @@ @@ -1,16 +0,0 @@
1 -package fr.plil.sio.web.mvc;  
2 -  
3 -import java.io.Serializable;  
4 -  
5 -public class UserSession implements Serializable {  
6 -  
7 - private String username;  
8 -  
9 - public String getUsername() {  
10 - return username;  
11 - }  
12 -  
13 - public void setUsername(String username) {  
14 - this.username = username;  
15 - }  
16 -}  
src/main/java/fr/plil/sio/web/mvc/ViewUsersController.java
@@ -14,19 +14,11 @@ public class ViewUsersController { @@ -14,19 +14,11 @@ public class ViewUsersController {
14 @Resource 14 @Resource
15 private UserRepository userRepository; 15 private UserRepository userRepository;
16 16
17 - @Resource  
18 - private UserSession userSession;  
19 -  
20 @ModelAttribute("users") 17 @ModelAttribute("users")
21 public List<User> populateUsers() { 18 public List<User> populateUsers() {
22 return userRepository.findAll(); 19 return userRepository.findAll();
23 } 20 }
24 21
25 - @ModelAttribute("userSession")  
26 - public UserSession populateUser() {  
27 - return userSession;  
28 - }  
29 -  
30 @RequestMapping(value={"/"},method=RequestMethod.GET) 22 @RequestMapping(value={"/"},method=RequestMethod.GET)
31 public String getViewUsers() { 23 public String getViewUsers() {
32 return "viewUsers"; 24 return "viewUsers";
@@ -35,8 +27,4 @@ public class ViewUsersController { @@ -35,8 +27,4 @@ public class ViewUsersController {
35 public void setUserRepository(UserRepository userRepository) { 27 public void setUserRepository(UserRepository userRepository) {
36 this.userRepository = userRepository; 28 this.userRepository = userRepository;
37 } 29 }
38 -  
39 - public void setUserSession(UserSession userSession) {  
40 - this.userSession = userSession;  
41 - }  
42 } 30 }
src/main/resources/application.properties
@@ -2,6 +2,6 @@ logging.level.fr.plil.sio.web.mvc=DEBUG @@ -2,6 +2,6 @@ logging.level.fr.plil.sio.web.mvc=DEBUG
2 logging.level.org.hibernate=INFO 2 logging.level.org.hibernate=INFO
3 3
4 spring.jpa.hibernate.ddl-auto=create-drop 4 spring.jpa.hibernate.ddl-auto=create-drop
5 -  
6 -spring.view.prefix=/WEB-INF/views/  
7 -spring.view.suffix=.jsp 5 +spring.mvc.view.prefix=/WEB-INF/pages/
  6 +spring.mvc.view.suffix=.jsp
  7 +security.enable-csrf=false
8 \ No newline at end of file 8 \ No newline at end of file
src/main/resources/import.sql
1 -INSERT INTO USER (username,password) VALUES ('admin','admin')  
2 \ No newline at end of file 1 \ No newline at end of file
  2 +INSERT INTO USER_T (USERNAME_F, PASSWORD_F)
  3 +VALUES ('admin', '$2a$04$/87gxfQlNqMNRvI/ILyZ/.F8Bk2/t2RuWoZXE1upQHeUglbjTYIIa');
  4 +INSERT INTO ROLE_T (NAME_F) VALUES ('ROLE_ADMIN');
  5 +INSERT INTO ROLE_T (NAME_F) VALUES ('ROLE_USER');
  6 +INSERT INTO USER_ROLE_T (USER_ID, ROLE_ID) VALUES ((SELECT USER_ID
  7 + FROM USER_T
  8 + WHERE USERNAME_F = 'admin'), (SELECT ROLE_ID
  9 + FROM ROLE_T
  10 + WHERE NAME_F = 'ROLE_ADMIN'));
3 \ No newline at end of file 11 \ No newline at end of file
src/main/resources/messages.properties
1 domain.user.username=Username 1 domain.user.username=Username
2 domain.user.password=Password 2 domain.user.password=Password
3 3
4 -validator.user.username.minimal.size=Username must be at least 3 characters  
5 -validator.user.password.minimal.size=Password must be at least 3 characters  
6 -  
7 -login.page.title=Login Page  
8 -login.main.header=Please login...  
9 -login.form.submit=login  
10 -login.form.invalid=Invalid username and/or password  
11 -  
12 view.users.page.title=User List 4 view.users.page.title=User List
13 view.users.main.header=List of users 5 view.users.main.header=List of users
14 view.users.greetings=Hello 6 view.users.greetings=Hello
@@ -17,5 +9,4 @@ view.users.main.logout=Logout @@ -17,5 +9,4 @@ view.users.main.logout=Logout
17 new.user.page.title=New user 9 new.user.page.title=New user
18 new.user.main.header=Add a new user 10 new.user.main.header=Add a new user
19 new.user.form.submit=Add the user 11 new.user.form.submit=Add the user
20 -new.user.only.admin=Only administrator user can do it  
21 new.user.form.present=user already present 12 new.user.form.present=user already present
22 \ No newline at end of file 13 \ No newline at end of file
src/main/webapp/WEB-INF/pages/login.jsp 0 โ†’ 100644
@@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
  1 +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  2 +<%@ page contentType="text/html;charset=UTF-8" language="java" %>
  3 +<html>
  4 +<head>
  5 + <title>Title</title>
  6 +</head>
  7 +<body>
  8 +<c:url value="/login" var="loginUrl"/>
  9 +<form action="${loginUrl}" method="post">
  10 + <c:if test="${param.error != null}">
  11 + <p>
  12 + Invalid username and password.
  13 + </p>
  14 + </c:if>
  15 + <c:if test="${param.logout != null}">
  16 + <p>
  17 + You have been logged out.
  18 + </p>
  19 + </c:if>
  20 + <p>
  21 + <label for="username">Username</label>
  22 + <input type="text" id="username" name="username"/>
  23 + </p>
  24 + <p>
  25 + <label for="password">Password</label>
  26 + <input type="password" id="password" name="password"/>
  27 + </p>
  28 + <input type="hidden"
  29 + name="${_csrf.parameterName}"
  30 + value="${_csrf.token}"/>
  31 + <button type="submit" class="btn">Log in</button>
  32 +</form>
  33 +</body>
  34 +</html>
src/main/webapp/WEB-INF/views/newUser.jsp renamed to src/main/webapp/WEB-INF/pages/newUser.jsp
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
12 </head> 12 </head>
13 <body> 13 <body>
14 <h1><spring:message code="new.user.main.header"/></h1> 14 <h1><spring:message code="new.user.main.header"/></h1>
15 - <form:form commandName="user" method="POST"> 15 + <form:form commandName="userForm" method="POST">
16 <table> 16 <table>
17 <tr> 17 <tr>
18 <td><form:errors path="username"/></td> 18 <td><form:errors path="username"/></td>
src/main/webapp/WEB-INF/views/viewUsers.jsp renamed to src/main/webapp/WEB-INF/pages/viewUsers.jsp
@@ -32,7 +32,7 @@ @@ -32,7 +32,7 @@
32 32
33 <ul> 33 <ul>
34 <li><a href="newUser"><spring:message code="new.user.main.header"/></a></li> 34 <li><a href="newUser"><spring:message code="new.user.main.header"/></a></li>
35 - <li><a href="logout"><spring:message code="view.users.main.logout"/></a></li> 35 + <li><a href="login?logout"><spring:message code="view.users.main.logout"/></a></li>
36 </ul> 36 </ul>
37 37
38 </body> 38 </body>
src/main/webapp/WEB-INF/views/login.jsp deleted
@@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
1 -<%@ page contentType="text/html" pageEncoding="UTF-8" %>  
2 -<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>  
3 -<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>  
4 -  
5 -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"  
6 - "http://www.w3.org/TR/html4/strict.dtd">  
7 -  
8 -<html>  
9 - <head>  
10 - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
11 - <title><spring:message code="login.page.title"/></title>  
12 - </head>  
13 - <body>  
14 - <h1><spring:message code="login.main.header"/></h1>  
15 - <form:form commandName="user" method="POST">  
16 - <table id="login" class="box">  
17 - <tr>  
18 - <td><form:errors path="*"/></td>  
19 - </tr>  
20 - <tr>  
21 - <td><spring:message code="domain.user.username"/></td>  
22 - <td><form:input path="username"/></td>  
23 - </tr>  
24 - <tr>  
25 - <td><spring:message code="domain.user.password"/></td>  
26 - <td><form:password path="password"/></td></tr>  
27 - <tr>  
28 - <td><input type="submit" value="<spring:message code="login.form.submit"/>"/></td>  
29 - </tr>  
30 - </table>  
31 - </form:form>  
32 - </body>  
33 -</html>  
34 \ No newline at end of file 0 \ No newline at end of file
src/test/java/fr/plil/sio/web/mvc/CheckUserInterceptorTest.java deleted
@@ -1,45 +0,0 @@ @@ -1,45 +0,0 @@
1 -package fr.plil.sio.web.mvc;  
2 -  
3 -import java.io.IOException;  
4 -import static org.junit.Assert.*;  
5 -import org.junit.Before;  
6 -import org.junit.Test;  
7 -import org.springframework.mock.web.MockHttpServletRequest;  
8 -import org.springframework.mock.web.MockHttpServletResponse;  
9 -  
10 -public class CheckUserInterceptorTest {  
11 -  
12 - private CheckUserInterceptor interceptor;  
13 - private UserSession userSession;  
14 - private MockHttpServletRequest request;  
15 - private MockHttpServletResponse response;  
16 -  
17 - @Before  
18 - public void createInstances() {  
19 - interceptor = new CheckUserInterceptor();  
20 - userSession = new UserSession();  
21 - interceptor.setUserSession(userSession);  
22 - request = new MockHttpServletRequest();  
23 - response = new MockHttpServletResponse();  
24 - }  
25 -  
26 - @Test  
27 - public void checkPreHandleServletPathIsLogin() throws IOException {  
28 - request.setServletPath("/login");  
29 - assertTrue(interceptor.preHandle(request, response, null));  
30 - }  
31 -  
32 - @Test  
33 - public void checkPreHandleUsernameInSession() throws IOException {  
34 - userSession.setUsername("admin");  
35 - request.setServletPath("/blabla");  
36 - assertTrue(interceptor.preHandle(request, response, null));  
37 - }  
38 -  
39 - @Test  
40 - public void checkPreHandleUsernameNotInSession() throws IOException {  
41 - request.setServletPath("/blabla");  
42 - assertFalse(interceptor.preHandle(request, response, null));  
43 - assertEquals(response.getRedirectedUrl(),"login");  
44 - }  
45 -}  
src/test/java/fr/plil/sio/web/mvc/LoginControllerTest.java deleted
@@ -1,59 +0,0 @@ @@ -1,59 +0,0 @@
1 -package fr.plil.sio.web.mvc;  
2 -  
3 -import org.junit.Before;  
4 -import org.junit.Test;  
5 -import org.springframework.validation.BeanPropertyBindingResult;  
6 -import org.springframework.validation.BindingResult;  
7 -import org.springframework.web.servlet.ModelAndView;  
8 -  
9 -import static org.junit.Assert.*;  
10 -import static org.mockito.Mockito.mock;  
11 -import static org.mockito.Mockito.when;  
12 -  
13 -public class LoginControllerTest {  
14 -  
15 - private LoginController loginController;  
16 - private BindingResult results;  
17 - private User user;  
18 - private UserRepository userRepository;  
19 - private UserSession userSession;  
20 -  
21 - @Before  
22 - public void createInstances() {  
23 - loginController = new LoginController();  
24 - user = new User();  
25 - results = new BeanPropertyBindingResult(user, "user");  
26 - userRepository = mock(UserRepository.class);  
27 - when(userRepository.findByUsername("admin")).thenReturn(new User("admin", "admin"));  
28 - loginController.setUserRepository(userRepository);  
29 - userSession = new UserSession();  
30 - loginController.setUserSession(userSession);  
31 - }  
32 -  
33 - @Test  
34 - public void testGetLoginForm() {  
35 - ModelAndView mav = loginController.getLoginForm();  
36 - assertEquals("login", mav.getViewName());  
37 - assertEquals(1, mav.getModelMap().size());  
38 - assertTrue(mav.getModel().containsKey("user"));  
39 - assertTrue(mav.getModel().get("user") instanceof User);  
40 - }  
41 -  
42 - @Test  
43 - public void testPostLoginCheckSucceed() {  
44 - user.setUsername("admin");  
45 - user.setPassword("admin");  
46 - String view = loginController.postLoginCheck(user, results);  
47 - assertFalse(results.hasErrors());  
48 - assertEquals("redirect:/",view);  
49 - }  
50 -  
51 - @Test  
52 - public void testPostLoginCheckFailed() {  
53 - user.setUsername("abc");  
54 - user.setPassword("abc");  
55 - String view = loginController.postLoginCheck(user, results);  
56 - assertTrue(results.hasErrors());  
57 - assertEquals("login",view);  
58 - }  
59 -}  
src/test/java/fr/plil/sio/web/mvc/LogoutControllerTest.java deleted
@@ -1,18 +0,0 @@ @@ -1,18 +0,0 @@
1 -package fr.plil.sio.web.mvc;  
2 -  
3 -import static org.junit.Assert.*;  
4 -import org.junit.Test;  
5 -  
6 -public class LogoutControllerTest {  
7 -  
8 - @Test  
9 - public void testGetLogout() {  
10 - LogoutController logoutController = new LogoutController();  
11 - UserSession userSession = new UserSession();  
12 - userSession.setUsername("blabla");  
13 - logoutController.setUserSession(userSession);  
14 - String view = logoutController.getLogout();  
15 - assertNull(userSession.getUsername());  
16 - assertEquals("redirect:/",view);  
17 - }  
18 -}  
src/test/java/fr/plil/sio/web/mvc/NewUserControllerTest.java
@@ -13,28 +13,20 @@ public class NewUserControllerTest { @@ -13,28 +13,20 @@ public class NewUserControllerTest {
13 13
14 private NewUserController newUserController; 14 private NewUserController newUserController;
15 private BindingResult results; 15 private BindingResult results;
16 - private UserForm user;  
17 - private UserRepository userRepository;  
18 - private UserSession userSession;  
19 - private UserFormValidator userFormValidator; 16 + private UserForm userForm;
20 private UserService userService; 17 private UserService userService;
21 18
22 @Before 19 @Before
23 public void createInstances() { 20 public void createInstances() {
24 newUserController = new NewUserController(); 21 newUserController = new NewUserController();
25 - user = new UserForm();  
26 - results = new BeanPropertyBindingResult(user, "user");  
27 - userRepository = mock(UserRepository.class);  
28 - User user = new User("admin", "password");  
29 - when(userRepository.findByUsername("admin")).thenReturn(user);  
30 - newUserController.setUserRepository(userRepository); 22 + userForm = new UserForm();
  23 + results = new BeanPropertyBindingResult(userForm, "user");
  24 + userService = mock(UserService.class);
  25 + User user = new User();
  26 + when(userService.findByUsername("admin")).thenReturn(user);
  27 + newUserController.setUserService(userService);
31 userService = mock(UserService.class); 28 userService = mock(UserService.class);
32 newUserController.setUserService(userService); 29 newUserController.setUserService(userService);
33 - userSession = new UserSession();  
34 - userSession.setUsername("admin");  
35 - newUserController.setUserSession(userSession);  
36 - userFormValidator = new UserFormValidator();  
37 - newUserController.setUserFormValidator(userFormValidator);  
38 } 30 }
39 31
40 @Test 32 @Test
@@ -48,9 +40,9 @@ public class NewUserControllerTest { @@ -48,9 +40,9 @@ public class NewUserControllerTest {
48 40
49 @Test 41 @Test
50 public void testPostNewUserSucceed() { 42 public void testPostNewUserSucceed() {
51 - user.setUsername("abc");  
52 - user.setPassword("abcD#");  
53 - String view = newUserController.postNewUser(user, results); 43 + userForm.setUsername("abc");
  44 + userForm.setPassword("abcD#");
  45 + String view = newUserController.postNewUser(userForm, results);
54 assertFalse(results.hasErrors()); 46 assertFalse(results.hasErrors());
55 assertEquals("redirect:/", view); 47 assertEquals("redirect:/", view);
56 verify(userService).createUser("abc", "abcD#"); 48 verify(userService).createUser("abc", "abcD#");
@@ -58,28 +50,27 @@ public class NewUserControllerTest { @@ -58,28 +50,27 @@ public class NewUserControllerTest {
58 50
59 @Test 51 @Test
60 public void testPostNewUserFailedNotAdmin() { 52 public void testPostNewUserFailedNotAdmin() {
61 - user.setUsername("abc");  
62 - user.setPassword("abcD#");  
63 - userSession.setUsername("blabla");  
64 - String view = newUserController.postNewUser(user, results); 53 + userForm.setUsername("abc");
  54 + userForm.setPassword("abcD#");
  55 + String view = newUserController.postNewUser(userForm, results);
65 assertTrue(results.hasErrors()); 56 assertTrue(results.hasErrors());
66 assertEquals("newUser",view); 57 assertEquals("newUser",view);
67 } 58 }
68 59
69 @Test 60 @Test
70 public void testPostNewUserFailedValidate() { 61 public void testPostNewUserFailedValidate() {
71 - user.setUsername("a");  
72 - user.setPassword("abc");  
73 - String view = newUserController.postNewUser(user, results); 62 + userForm.setUsername("a");
  63 + userForm.setPassword("abc");
  64 + String view = newUserController.postNewUser(userForm, results);
74 assertTrue(results.hasErrors()); 65 assertTrue(results.hasErrors());
75 assertEquals("newUser",view); 66 assertEquals("newUser",view);
76 } 67 }
77 68
78 @Test 69 @Test
79 public void testPostNewUserFailedAlreadyPresent() { 70 public void testPostNewUserFailedAlreadyPresent() {
80 - user.setUsername("admin");  
81 - user.setPassword("blabla");  
82 - String view = newUserController.postNewUser(user, results); 71 + userForm.setUsername("admin");
  72 + userForm.setPassword("blabla");
  73 + String view = newUserController.postNewUser(userForm, results);
83 assertTrue(results.hasErrors()); 74 assertTrue(results.hasErrors());
84 assertEquals("newUser",view); 75 assertEquals("newUser",view);
85 } 76 }
src/test/java/fr/plil/sio/web/mvc/UserFormValidatorTest.java deleted
@@ -1,37 +0,0 @@ @@ -1,37 +0,0 @@
1 -package fr.plil.sio.web.mvc;  
2 -  
3 -import org.junit.Before;  
4 -import org.junit.Test;  
5 -import org.springframework.validation.BeanPropertyBindingResult;  
6 -import org.springframework.validation.Errors;  
7 -  
8 -import static org.junit.Assert.assertFalse;  
9 -import static org.junit.Assert.assertTrue;  
10 -  
11 -public class UserFormValidatorTest {  
12 -  
13 - private UserForm user;  
14 - private UserFormValidator validator;  
15 - private Errors results;  
16 -  
17 - @Before  
18 - public void createInstances() {  
19 - validator = new UserFormValidator();  
20 - user = new UserForm();  
21 - user.setUsername("abc");  
22 - user.setPassword("abc#A");  
23 - results = new BeanPropertyBindingResult(user, "user");  
24 - }  
25 -  
26 - @Test  
27 - public void testSupports() {  
28 - assertTrue(validator.supports(UserForm.class));  
29 - }  
30 -  
31 - @Test  
32 - public void testValidateCorrect() {  
33 - validator.validate(user,results);  
34 - assertFalse(results.hasErrors());  
35 - }  
36 -  
37 -}  
src/test/java/fr/plil/sio/web/mvc/ViewUsersControllerTest.java
@@ -24,7 +24,6 @@ public class ViewUsersControllerTest { @@ -24,7 +24,6 @@ public class ViewUsersControllerTest {
24 24
25 private ViewUsersController viewUsersController; 25 private ViewUsersController viewUsersController;
26 private UserRepository userRepository; 26 private UserRepository userRepository;
27 - private UserSession userSession;  
28 27
29 private MockMvc mockMvc; 28 private MockMvc mockMvc;
30 29
@@ -34,12 +33,12 @@ public class ViewUsersControllerTest { @@ -34,12 +33,12 @@ public class ViewUsersControllerTest {
34 mockMvc = MockMvcBuilders.standaloneSetup(viewUsersController).build(); 33 mockMvc = MockMvcBuilders.standaloneSetup(viewUsersController).build();
35 userRepository = mock(UserRepository.class); 34 userRepository = mock(UserRepository.class);
36 List<User> users = new LinkedList<>(); 35 List<User> users = new LinkedList<>();
37 - users.add(new User("admin", "password")); 36 + User testUser = new User();
  37 + testUser.setPassword("admin");
  38 + testUser.setUsername("password");
  39 + users.add(testUser);
38 when(userRepository.findAll()).thenReturn(users); 40 when(userRepository.findAll()).thenReturn(users);
39 viewUsersController.setUserRepository(userRepository); 41 viewUsersController.setUserRepository(userRepository);
40 - userSession = new UserSession();  
41 - userSession.setUsername("admin");  
42 - viewUsersController.setUserSession(userSession);  
43 } 42 }
44 43
45 @Test 44 @Test
@@ -47,7 +46,6 @@ public class ViewUsersControllerTest { @@ -47,7 +46,6 @@ public class ViewUsersControllerTest {
47 mockMvc.perform(get("/")) 46 mockMvc.perform(get("/"))
48 .andExpect(status().isOk()) 47 .andExpect(status().isOk())
49 .andExpect(view().name("viewUsers")) 48 .andExpect(view().name("viewUsers"))
50 - .andExpect(model().attributeExists("users"))  
51 - .andExpect(model().attributeExists("userSession")); 49 + .andExpect(model().attributeExists("users"));
52 } 50 }
53 } 51 }