From 322c9502a32ebc9aeee8179c5eac890ca876211c Mon Sep 17 00:00:00 2001 From: Julien Cartigny Date: Wed, 7 Jun 2017 13:33:53 +0200 Subject: [PATCH] Ad Spring security support and validation --- pom.xml | 8 ++++---- src/main/java/fr/plil/sio/web/mvc/Application.java | 9 ++++++++- src/main/java/fr/plil/sio/web/mvc/ApplicationMvcConfiguration.java | 29 ++++------------------------- src/main/java/fr/plil/sio/web/mvc/ApplicationSecurityConfiguration.java | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/main/java/fr/plil/sio/web/mvc/CheckUserInterceptor.java | 45 --------------------------------------------- src/main/java/fr/plil/sio/web/mvc/LoginController.java | 45 +++++++++------------------------------------ src/main/java/fr/plil/sio/web/mvc/LogoutController.java | 23 ----------------------- src/main/java/fr/plil/sio/web/mvc/NewUserController.java | 45 ++++++++++----------------------------------- src/main/java/fr/plil/sio/web/mvc/Role.java | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/fr/plil/sio/web/mvc/RoleRepository.java | 8 ++++++++ src/main/java/fr/plil/sio/web/mvc/User.java | 51 ++++++++++++++++++++++++++++++++++++++++++++------- src/main/java/fr/plil/sio/web/mvc/UserDetailsServiceImpl.java | 26 ++++++++++++++++++++++++++ src/main/java/fr/plil/sio/web/mvc/UserForm.java | 8 ++++---- src/main/java/fr/plil/sio/web/mvc/UserFormValidator.java | 41 ----------------------------------------- src/main/java/fr/plil/sio/web/mvc/UserService.java | 2 ++ src/main/java/fr/plil/sio/web/mvc/UserServiceImpl.java | 19 ++++++++++++++++++- src/main/java/fr/plil/sio/web/mvc/UserSession.java | 16 ---------------- src/main/java/fr/plil/sio/web/mvc/ViewUsersController.java | 12 ------------ src/main/resources/application.properties | 6 +++--- src/main/resources/import.sql | 10 +++++++++- src/main/resources/messages.properties | 9 --------- src/main/webapp/WEB-INF/pages/login.jsp | 34 ++++++++++++++++++++++++++++++++++ src/main/webapp/WEB-INF/pages/newUser.jsp | 36 ++++++++++++++++++++++++++++++++++++ src/main/webapp/WEB-INF/pages/viewUsers.jsp | 39 +++++++++++++++++++++++++++++++++++++++ src/main/webapp/WEB-INF/views/login.jsp | 33 --------------------------------- src/main/webapp/WEB-INF/views/newUser.jsp | 36 ------------------------------------ src/main/webapp/WEB-INF/views/viewUsers.jsp | 39 --------------------------------------- src/test/java/fr/plil/sio/web/mvc/CheckUserInterceptorTest.java | 45 --------------------------------------------- src/test/java/fr/plil/sio/web/mvc/LoginControllerTest.java | 59 ----------------------------------------------------------- src/test/java/fr/plil/sio/web/mvc/LogoutControllerTest.java | 18 ------------------ src/test/java/fr/plil/sio/web/mvc/NewUserControllerTest.java | 47 +++++++++++++++++++---------------------------- src/test/java/fr/plil/sio/web/mvc/UserFormValidatorTest.java | 37 ------------------------------------- src/test/java/fr/plil/sio/web/mvc/ViewUsersControllerTest.java | 12 +++++------- 33 files changed, 382 insertions(+), 565 deletions(-) create mode 100644 src/main/java/fr/plil/sio/web/mvc/ApplicationSecurityConfiguration.java delete mode 100644 src/main/java/fr/plil/sio/web/mvc/CheckUserInterceptor.java delete mode 100644 src/main/java/fr/plil/sio/web/mvc/LogoutController.java create mode 100644 src/main/java/fr/plil/sio/web/mvc/Role.java create mode 100644 src/main/java/fr/plil/sio/web/mvc/RoleRepository.java create mode 100644 src/main/java/fr/plil/sio/web/mvc/UserDetailsServiceImpl.java delete mode 100644 src/main/java/fr/plil/sio/web/mvc/UserFormValidator.java delete mode 100644 src/main/java/fr/plil/sio/web/mvc/UserSession.java create mode 100644 src/main/webapp/WEB-INF/pages/login.jsp create mode 100644 src/main/webapp/WEB-INF/pages/newUser.jsp create mode 100644 src/main/webapp/WEB-INF/pages/viewUsers.jsp delete mode 100644 src/main/webapp/WEB-INF/views/login.jsp delete mode 100644 src/main/webapp/WEB-INF/views/newUser.jsp delete mode 100644 src/main/webapp/WEB-INF/views/viewUsers.jsp delete mode 100644 src/test/java/fr/plil/sio/web/mvc/CheckUserInterceptorTest.java delete mode 100644 src/test/java/fr/plil/sio/web/mvc/LoginControllerTest.java delete mode 100644 src/test/java/fr/plil/sio/web/mvc/LogoutControllerTest.java delete mode 100644 src/test/java/fr/plil/sio/web/mvc/UserFormValidatorTest.java diff --git a/pom.xml b/pom.xml index a50f7b6..a63848d 100644 --- a/pom.xml +++ b/pom.xml @@ -36,15 +36,15 @@ org.springframework.boot spring-boot-starter-web - org.springframework.boot spring-boot-starter-tomcat provided + + org.springframework.boot + spring-boot-starter-security + org.springframework.boot spring-boot-starter-test diff --git a/src/main/java/fr/plil/sio/web/mvc/Application.java b/src/main/java/fr/plil/sio/web/mvc/Application.java index b02b3b6..2da6bbd 100644 --- a/src/main/java/fr/plil/sio/web/mvc/Application.java +++ b/src/main/java/fr/plil/sio/web/mvc/Application.java @@ -2,11 +2,18 @@ package fr.plil.sio.web.mvc; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.support.SpringBootServletInitializer; @SpringBootApplication -public class Application { +public class Application extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(Application.class, args); } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(Application.class); + } } diff --git a/src/main/java/fr/plil/sio/web/mvc/ApplicationMvcConfiguration.java b/src/main/java/fr/plil/sio/web/mvc/ApplicationMvcConfiguration.java index 1cd230b..2a18116 100644 --- a/src/main/java/fr/plil/sio/web/mvc/ApplicationMvcConfiguration.java +++ b/src/main/java/fr/plil/sio/web/mvc/ApplicationMvcConfiguration.java @@ -1,38 +1,17 @@ package fr.plil.sio.web.mvc; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.boot.SpringBootConfiguration; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Scope; -import org.springframework.context.annotation.ScopedProxyMode; -import org.springframework.web.context.WebApplicationContext; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @SpringBootConfiguration public class ApplicationMvcConfiguration extends WebMvcConfigurerAdapter { - private static final Logger logger = LoggerFactory.getLogger(ApplicationMvcConfiguration.class); - - @Bean - @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode. TARGET_CLASS) - public UserSession userSession() { - logger.debug("new user session bean"); - return new UserSession(); - } - -/* @Bean - public CheckUserInterceptor checkUserInterceptor() { - return new CheckUserInterceptor(); - } - - @Override - public void addInterceptors(InterceptorRegistry registry) { - CheckUserInterceptor interceptor = checkUserInterceptor(); - interceptor.setUserSession(userSession()); - registry.addInterceptor(interceptor); + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); } -*/ } diff --git a/src/main/java/fr/plil/sio/web/mvc/ApplicationSecurityConfiguration.java b/src/main/java/fr/plil/sio/web/mvc/ApplicationSecurityConfiguration.java new file mode 100644 index 0000000..b53f01e --- /dev/null +++ b/src/main/java/fr/plil/sio/web/mvc/ApplicationSecurityConfiguration.java @@ -0,0 +1,44 @@ +package fr.plil.sio.web.mvc; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.PasswordEncoder; + +import javax.annotation.Resource; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class ApplicationSecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Resource + private PasswordEncoder passwordEncoder; + + @Resource + private UserDetailsService userDetailsService; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeRequests() + .anyRequest().authenticated() + .and() + .formLogin() + .loginPage("/login") + .permitAll() + .and() + .logout() + .permitAll(); + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder); + } +} \ No newline at end of file diff --git a/src/main/java/fr/plil/sio/web/mvc/CheckUserInterceptor.java b/src/main/java/fr/plil/sio/web/mvc/CheckUserInterceptor.java deleted file mode 100644 index 40334cd..0000000 --- a/src/main/java/fr/plil/sio/web/mvc/CheckUserInterceptor.java +++ /dev/null @@ -1,45 +0,0 @@ -package fr.plil.sio.web.mvc; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -public class CheckUserInterceptor extends HandlerInterceptorAdapter { - - private static final Logger logger = LoggerFactory.getLogger(CheckUserInterceptor.class); - - @Resource - private UserSession userSession; - - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, - Object handler) throws IOException { - - logger.debug("servlet path: " + request.getServletPath()); - - if (request.getServletPath().equals("/login")) { - logger.debug("access granted as path is /login"); - return true; - } - - String username = userSession.getUsername(); - - if (username != null) { - logger.debug("authenticated"); - return true; - } else { - logger.debug("not authenticated"); - response.sendRedirect("login"); - return false; - } - } - - void setUserSession(UserSession userSession) { - this.userSession = userSession; - } -} diff --git a/src/main/java/fr/plil/sio/web/mvc/LoginController.java b/src/main/java/fr/plil/sio/web/mvc/LoginController.java index f230ac7..ed6af96 100644 --- a/src/main/java/fr/plil/sio/web/mvc/LoginController.java +++ b/src/main/java/fr/plil/sio/web/mvc/LoginController.java @@ -1,53 +1,26 @@ package fr.plil.sio.web.mvc; import org.springframework.stereotype.Controller; -import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; -import javax.annotation.Resource; - @Controller -@RequestMapping(value = "/login") public class LoginController { - @Resource - private UserRepository userRepository; - - @Resource - private UserSession userSession; - - @RequestMapping(method = RequestMethod.GET) - public ModelAndView getLoginForm() { - return new ModelAndView("login", "user", new User()); - } + @RequestMapping(value = "/login", method = RequestMethod.GET) + public ModelAndView login(String error, String logout) { - @RequestMapping(method = RequestMethod.POST) - public String postLoginCheck(User user, BindingResult result) { + ModelAndView modelAndView = new ModelAndView("login"); - User userFromRepository = userRepository.findByUsername(user.getUsername()); - - if (userFromRepository == null) { - result.rejectValue("username","login.form.invalid"); - return "login"; + if (error != null) { + modelAndView.addObject("error", "Your username and password is invalid."); } - if (!userFromRepository.getPassword().equals(user.getPassword())) { - result.rejectValue("username","login.form.invalid"); - return "login"; + if (logout != null) { + modelAndView.addObject("message", "You have been logged out successfully."); } - userSession.setUsername(userFromRepository.getUsername()); - - return "redirect:/"; - } - - public void setUserRepository(UserRepository userRepository) { - this.userRepository = userRepository; - } - - public void setUserSession(UserSession userSession) { - this.userSession = userSession; + return modelAndView; } -} \ No newline at end of file +} diff --git a/src/main/java/fr/plil/sio/web/mvc/LogoutController.java b/src/main/java/fr/plil/sio/web/mvc/LogoutController.java deleted file mode 100644 index 16235a0..0000000 --- a/src/main/java/fr/plil/sio/web/mvc/LogoutController.java +++ /dev/null @@ -1,23 +0,0 @@ -package fr.plil.sio.web.mvc; - -import javax.annotation.Resource; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -@Controller -public class LogoutController { - - @Resource - private UserSession userSession; - - @RequestMapping(value = {"/logout"}, method = RequestMethod.GET) - public String getLogout() { - userSession.setUsername(null); - return "redirect:/"; - } - - public void setUserSession(UserSession userSession) { - this.userSession = userSession; - } -} diff --git a/src/main/java/fr/plil/sio/web/mvc/NewUserController.java b/src/main/java/fr/plil/sio/web/mvc/NewUserController.java index f85980e..26b5dbf 100644 --- a/src/main/java/fr/plil/sio/web/mvc/NewUserController.java +++ b/src/main/java/fr/plil/sio/web/mvc/NewUserController.java @@ -1,45 +1,32 @@ package fr.plil.sio.web.mvc; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; import javax.annotation.Resource; +import javax.validation.Valid; @Controller +@RequestMapping(value = {"/newUser"}) public class NewUserController { @Resource - private UserRepository userRepository; - - @Resource private UserService userService; - @Resource - private UserSession userSession; - - @Resource - private UserFormValidator userFormValidator; - - @RequestMapping(value = {"/newUser"}, method = RequestMethod.GET) + @RequestMapping(method = RequestMethod.GET) public ModelAndView getNewUserForm() { - return new ModelAndView("newUser", "user", new User()); + return new ModelAndView("newUser", "userForm", new UserForm()); } - @RequestMapping(value = {"/newUser"}, method = RequestMethod.POST) - public String postNewUser(@ModelAttribute("userForm") UserForm user, - BindingResult result) { - - if (!userSession.getUsername().equals("admin")) { - result.rejectValue("username", "new.user.only.admin"); - } + @PreAuthorize("hasRole('ROLE_ADMIN')") + @RequestMapping(method = RequestMethod.POST) + public String postNewUser(@Valid UserForm userForm, BindingResult result) { - userFormValidator.validate(user, result); - - boolean present = (userRepository.findByUsername(user.getUsername()) != null); + boolean present = (userService.findByUsername(userForm.getUsername()) != null); if (present) { result.rejectValue("username", "new.user.form.present"); @@ -49,23 +36,11 @@ public class NewUserController { return "newUser"; } - userService.createUser(user.getUsername(), user.getPassword()); + userService.createUser(userForm.getUsername(), userForm.getPassword()); return "redirect:/"; } - public void setUserRepository(UserRepository userRepository) { - this.userRepository = userRepository; - } - - public void setUserSession(UserSession userSession) { - this.userSession = userSession; - } - - public void setUserFormValidator(UserFormValidator userFormValidator) { - this.userFormValidator = userFormValidator; - } - public void setUserService(UserService userService) { this.userService = userService; } diff --git a/src/main/java/fr/plil/sio/web/mvc/Role.java b/src/main/java/fr/plil/sio/web/mvc/Role.java new file mode 100644 index 0000000..648b32b --- /dev/null +++ b/src/main/java/fr/plil/sio/web/mvc/Role.java @@ -0,0 +1,56 @@ +package fr.plil.sio.web.mvc; + +import org.springframework.security.core.GrantedAuthority; + +import javax.persistence.*; +import java.util.Set; +import java.util.TreeSet; + +@Entity +@Table(name = "ROLE_T") +public class Role implements GrantedAuthority { + + @Id + @Column(name = "ROLE_ID") + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @Column(name = "NAME_F") + private String name; + + @ManyToMany + @JoinTable( + name = "USER_ROLE_T", + joinColumns = @JoinColumn(name = "ROLE_ID", referencedColumnName = "ROLE_ID"), + inverseJoinColumns = @JoinColumn(name = "USER_ID", referencedColumnName = "USER_ID")) + private Set users = new TreeSet<>(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getUsers() { + return users; + } + + public void setUsers(Set users) { + this.users = users; + } + + @Override + public String getAuthority() { + return name; + } +} diff --git a/src/main/java/fr/plil/sio/web/mvc/RoleRepository.java b/src/main/java/fr/plil/sio/web/mvc/RoleRepository.java new file mode 100644 index 0000000..abd2fdd --- /dev/null +++ b/src/main/java/fr/plil/sio/web/mvc/RoleRepository.java @@ -0,0 +1,8 @@ +package fr.plil.sio.web.mvc; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RoleRepository extends JpaRepository { + + Role findByName(String name); +} diff --git a/src/main/java/fr/plil/sio/web/mvc/User.java b/src/main/java/fr/plil/sio/web/mvc/User.java index b35e576..b357b23 100644 --- a/src/main/java/fr/plil/sio/web/mvc/User.java +++ b/src/main/java/fr/plil/sio/web/mvc/User.java @@ -1,27 +1,44 @@ package fr.plil.sio.web.mvc; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + import javax.persistence.*; +import java.util.Collection; +import java.util.Set; +import java.util.TreeSet; @Entity -public class User { +@Table(name = "USER_T") +public class User implements UserDetails { @Id + @Column(name = "USER_ID") @GeneratedValue(strategy = GenerationType.AUTO) private Long id; - @Column + @Column(name = "USERNAME_F") private String username; - @Column + @Column(name = "PASSWORD_F") private String password; - public User() { + @ManyToMany(mappedBy = "users", fetch = FetchType.EAGER) + private Set roles = new TreeSet<>(); + + public Set getRoles() { + return roles; } - public User(String username, String password) { - this.username = username; - this.password = password; + public void setRoles(Set roles) { + this.roles = roles; + } + + + @Override + public Collection getAuthorities() { + return roles; } public String getUsername() { @@ -32,6 +49,26 @@ public class User { this.username = username; } + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + public String getPassword() { return password; } diff --git a/src/main/java/fr/plil/sio/web/mvc/UserDetailsServiceImpl.java b/src/main/java/fr/plil/sio/web/mvc/UserDetailsServiceImpl.java new file mode 100644 index 0000000..10d59ab --- /dev/null +++ b/src/main/java/fr/plil/sio/web/mvc/UserDetailsServiceImpl.java @@ -0,0 +1,26 @@ +package fr.plil.sio.web.mvc; + +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +@Service +public class UserDetailsServiceImpl implements UserDetailsService { + + @Resource + private UserService userService; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + User user = userService.findByUsername(username); + + if (user == null) { + throw new UsernameNotFoundException("cannot found user " + username); + } + + return user; + } +} \ No newline at end of file diff --git a/src/main/java/fr/plil/sio/web/mvc/UserForm.java b/src/main/java/fr/plil/sio/web/mvc/UserForm.java index 6594d9c..95d5892 100644 --- a/src/main/java/fr/plil/sio/web/mvc/UserForm.java +++ b/src/main/java/fr/plil/sio/web/mvc/UserForm.java @@ -1,16 +1,16 @@ package fr.plil.sio.web.mvc; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; public class UserForm { - @Min(3) - @Max(16) + @NotNull + @Size(min = 3, max = 16) private String username; @NotNull + @Size(min = 4) private String password; public String getUsername() { diff --git a/src/main/java/fr/plil/sio/web/mvc/UserFormValidator.java b/src/main/java/fr/plil/sio/web/mvc/UserFormValidator.java deleted file mode 100644 index b521a3a..0000000 --- a/src/main/java/fr/plil/sio/web/mvc/UserFormValidator.java +++ /dev/null @@ -1,41 +0,0 @@ -package fr.plil.sio.web.mvc; - -import org.springframework.stereotype.Component; -import org.springframework.validation.Errors; -import org.springframework.validation.Validator; - -@Component -public class UserFormValidator implements Validator { - - @Override - public boolean supports(Class clazz) { - return UserForm.class.equals(clazz); - } - - private void checkUsername(String username, Errors errors) { - - } - - private void checkPassword(String password, Errors errors) { - boolean hasUppercase = !password.equals(password.toLowerCase()); - boolean hasLowercase = !password.equals(password.toUpperCase()); - boolean hasSpecial = !password.matches("[A-Za-z0-9 ]*"); - - if (!hasUppercase) { - errors.rejectValue("password", "validator.user.form.must.contains.uppercase"); - } - if (!hasLowercase) { - errors.rejectValue("password", "validator.user.form.must.contains.lowercase"); - } - if (!hasSpecial) { - errors.rejectValue("password", "validator.user.form.must.contains.special.char"); - } - } - - @Override - public void validate(Object target, Errors errors) { - UserForm user = (UserForm) target; - checkUsername(user.getUsername(), errors); - checkPassword(user.getPassword(), errors); - } -} \ No newline at end of file diff --git a/src/main/java/fr/plil/sio/web/mvc/UserService.java b/src/main/java/fr/plil/sio/web/mvc/UserService.java index 976d1f5..dae452d 100644 --- a/src/main/java/fr/plil/sio/web/mvc/UserService.java +++ b/src/main/java/fr/plil/sio/web/mvc/UserService.java @@ -3,4 +3,6 @@ package fr.plil.sio.web.mvc; public interface UserService { User createUser(String username, String password); + + User findByUsername(String username); } diff --git a/src/main/java/fr/plil/sio/web/mvc/UserServiceImpl.java b/src/main/java/fr/plil/sio/web/mvc/UserServiceImpl.java index 569854e..f9b565e 100644 --- a/src/main/java/fr/plil/sio/web/mvc/UserServiceImpl.java +++ b/src/main/java/fr/plil/sio/web/mvc/UserServiceImpl.java @@ -1,9 +1,12 @@ package fr.plil.sio.web.mvc; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.util.HashSet; +import java.util.Set; @Service("userService") public class UserServiceImpl implements UserService { @@ -11,13 +14,27 @@ public class UserServiceImpl implements UserService { @Resource private UserRepository userRepository; + @Resource + private RoleRepository roleRepository; + + @Resource + private PasswordEncoder passwordEncoder; + @Override @Transactional public User createUser(String username, String password) { User user = new User(); user.setUsername(username); - user.setPassword(password); + user.setPassword(passwordEncoder.encode(password)); + Set roles = new HashSet<>(); + roles.add(roleRepository.findByName("ROLE_USER")); + user.setRoles(roles); userRepository.save(user); return user; } + + @Override + public User findByUsername(String username) { + return userRepository.findByUsername(username); + } } diff --git a/src/main/java/fr/plil/sio/web/mvc/UserSession.java b/src/main/java/fr/plil/sio/web/mvc/UserSession.java deleted file mode 100644 index 27e9c68..0000000 --- a/src/main/java/fr/plil/sio/web/mvc/UserSession.java +++ /dev/null @@ -1,16 +0,0 @@ -package fr.plil.sio.web.mvc; - -import java.io.Serializable; - -public class UserSession implements Serializable { - - private String username; - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } -} diff --git a/src/main/java/fr/plil/sio/web/mvc/ViewUsersController.java b/src/main/java/fr/plil/sio/web/mvc/ViewUsersController.java index eade0a1..8474737 100644 --- a/src/main/java/fr/plil/sio/web/mvc/ViewUsersController.java +++ b/src/main/java/fr/plil/sio/web/mvc/ViewUsersController.java @@ -14,19 +14,11 @@ public class ViewUsersController { @Resource private UserRepository userRepository; - @Resource - private UserSession userSession; - @ModelAttribute("users") public List populateUsers() { return userRepository.findAll(); } - @ModelAttribute("userSession") - public UserSession populateUser() { - return userSession; - } - @RequestMapping(value={"/"},method=RequestMethod.GET) public String getViewUsers() { return "viewUsers"; @@ -35,8 +27,4 @@ public class ViewUsersController { public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } - - public void setUserSession(UserSession userSession) { - this.userSession = userSession; - } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index fe57822..8c03a6b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,6 +2,6 @@ logging.level.fr.plil.sio.web.mvc=DEBUG logging.level.org.hibernate=INFO spring.jpa.hibernate.ddl-auto=create-drop - -spring.view.prefix=/WEB-INF/views/ -spring.view.suffix=.jsp +spring.mvc.view.prefix=/WEB-INF/pages/ +spring.mvc.view.suffix=.jsp +security.enable-csrf=false \ No newline at end of file diff --git a/src/main/resources/import.sql b/src/main/resources/import.sql index 4f25c25..d175fe7 100644 --- a/src/main/resources/import.sql +++ b/src/main/resources/import.sql @@ -1 +1,9 @@ -INSERT INTO USER (username,password) VALUES ('admin','admin') \ No newline at end of file +INSERT INTO USER_T (USERNAME_F, PASSWORD_F) +VALUES ('admin', '$2a$04$/87gxfQlNqMNRvI/ILyZ/.F8Bk2/t2RuWoZXE1upQHeUglbjTYIIa'); +INSERT INTO ROLE_T (NAME_F) VALUES ('ROLE_ADMIN'); +INSERT INTO ROLE_T (NAME_F) VALUES ('ROLE_USER'); +INSERT INTO USER_ROLE_T (USER_ID, ROLE_ID) VALUES ((SELECT USER_ID + FROM USER_T + WHERE USERNAME_F = 'admin'), (SELECT ROLE_ID + FROM ROLE_T + WHERE NAME_F = 'ROLE_ADMIN')); \ No newline at end of file diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index f5cd2b0..e663351 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -1,14 +1,6 @@ domain.user.username=Username domain.user.password=Password -validator.user.username.minimal.size=Username must be at least 3 characters -validator.user.password.minimal.size=Password must be at least 3 characters - -login.page.title=Login Page -login.main.header=Please login... -login.form.submit=login -login.form.invalid=Invalid username and/or password - view.users.page.title=User List view.users.main.header=List of users view.users.greetings=Hello @@ -17,5 +9,4 @@ view.users.main.logout=Logout new.user.page.title=New user new.user.main.header=Add a new user new.user.form.submit=Add the user -new.user.only.admin=Only administrator user can do it new.user.form.present=user already present \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/pages/login.jsp b/src/main/webapp/WEB-INF/pages/login.jsp new file mode 100644 index 0000000..dc318f8 --- /dev/null +++ b/src/main/webapp/WEB-INF/pages/login.jsp @@ -0,0 +1,34 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + Title + + + +
+ +

+ Invalid username and password. +

+
+ +

+ You have been logged out. +

+
+

+ + +

+

+ + +

+ + +
+ + diff --git a/src/main/webapp/WEB-INF/pages/newUser.jsp b/src/main/webapp/WEB-INF/pages/newUser.jsp new file mode 100644 index 0000000..a90320f --- /dev/null +++ b/src/main/webapp/WEB-INF/pages/newUser.jsp @@ -0,0 +1,36 @@ +<%@ page contentType="text/html" pageEncoding="UTF-8" %> +<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> +<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %> + + + + + + + <spring:message code="new.user.page.title"/> + + +

+ + + + + + + + + + + + + + + + + + +
"/>
+
+ + diff --git a/src/main/webapp/WEB-INF/pages/viewUsers.jsp b/src/main/webapp/WEB-INF/pages/viewUsers.jsp new file mode 100644 index 0000000..97ed3c7 --- /dev/null +++ b/src/main/webapp/WEB-INF/pages/viewUsers.jsp @@ -0,0 +1,39 @@ +<%@ page contentType="text/html" pageEncoding="UTF-8" %> +<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + <spring:message code="view.users.page.title"/> + + +

+ +

${userSession.username} !

+ + + + + + + + + + + + + + +
${user.username}
+ +
    +
  • +
  • +
+ + + diff --git a/src/main/webapp/WEB-INF/views/login.jsp b/src/main/webapp/WEB-INF/views/login.jsp deleted file mode 100644 index 200c55a..0000000 --- a/src/main/webapp/WEB-INF/views/login.jsp +++ /dev/null @@ -1,33 +0,0 @@ -<%@ page contentType="text/html" pageEncoding="UTF-8" %> -<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %> -<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> - - - - - - - <spring:message code="login.page.title"/> - - -

- - - - - - - - - - - - - - - -
"/>
-
- - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/views/newUser.jsp b/src/main/webapp/WEB-INF/views/newUser.jsp deleted file mode 100644 index 200ffcf..0000000 --- a/src/main/webapp/WEB-INF/views/newUser.jsp +++ /dev/null @@ -1,36 +0,0 @@ -<%@ page contentType="text/html" pageEncoding="UTF-8" %> -<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> -<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %> - - - - - - - <spring:message code="new.user.page.title"/> - - -

- - - - - - - - - - - - - - - - - - -
"/>
-
- - diff --git a/src/main/webapp/WEB-INF/views/viewUsers.jsp b/src/main/webapp/WEB-INF/views/viewUsers.jsp deleted file mode 100644 index 81b28b1..0000000 --- a/src/main/webapp/WEB-INF/views/viewUsers.jsp +++ /dev/null @@ -1,39 +0,0 @@ -<%@ page contentType="text/html" pageEncoding="UTF-8" %> -<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - - - - - - <spring:message code="view.users.page.title"/> - - -

- -

${userSession.username} !

- - - - - - - - - - - - - - -
${user.username}
- -
    -
  • -
  • -
- - - diff --git a/src/test/java/fr/plil/sio/web/mvc/CheckUserInterceptorTest.java b/src/test/java/fr/plil/sio/web/mvc/CheckUserInterceptorTest.java deleted file mode 100644 index 9f7b8bf..0000000 --- a/src/test/java/fr/plil/sio/web/mvc/CheckUserInterceptorTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package fr.plil.sio.web.mvc; - -import java.io.IOException; -import static org.junit.Assert.*; -import org.junit.Before; -import org.junit.Test; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; - -public class CheckUserInterceptorTest { - - private CheckUserInterceptor interceptor; - private UserSession userSession; - private MockHttpServletRequest request; - private MockHttpServletResponse response; - - @Before - public void createInstances() { - interceptor = new CheckUserInterceptor(); - userSession = new UserSession(); - interceptor.setUserSession(userSession); - request = new MockHttpServletRequest(); - response = new MockHttpServletResponse(); - } - - @Test - public void checkPreHandleServletPathIsLogin() throws IOException { - request.setServletPath("/login"); - assertTrue(interceptor.preHandle(request, response, null)); - } - - @Test - public void checkPreHandleUsernameInSession() throws IOException { - userSession.setUsername("admin"); - request.setServletPath("/blabla"); - assertTrue(interceptor.preHandle(request, response, null)); - } - - @Test - public void checkPreHandleUsernameNotInSession() throws IOException { - request.setServletPath("/blabla"); - assertFalse(interceptor.preHandle(request, response, null)); - assertEquals(response.getRedirectedUrl(),"login"); - } -} diff --git a/src/test/java/fr/plil/sio/web/mvc/LoginControllerTest.java b/src/test/java/fr/plil/sio/web/mvc/LoginControllerTest.java deleted file mode 100644 index c160573..0000000 --- a/src/test/java/fr/plil/sio/web/mvc/LoginControllerTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package fr.plil.sio.web.mvc; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.validation.BeanPropertyBindingResult; -import org.springframework.validation.BindingResult; -import org.springframework.web.servlet.ModelAndView; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class LoginControllerTest { - - private LoginController loginController; - private BindingResult results; - private User user; - private UserRepository userRepository; - private UserSession userSession; - - @Before - public void createInstances() { - loginController = new LoginController(); - user = new User(); - results = new BeanPropertyBindingResult(user, "user"); - userRepository = mock(UserRepository.class); - when(userRepository.findByUsername("admin")).thenReturn(new User("admin", "admin")); - loginController.setUserRepository(userRepository); - userSession = new UserSession(); - loginController.setUserSession(userSession); - } - - @Test - public void testGetLoginForm() { - ModelAndView mav = loginController.getLoginForm(); - assertEquals("login", mav.getViewName()); - assertEquals(1, mav.getModelMap().size()); - assertTrue(mav.getModel().containsKey("user")); - assertTrue(mav.getModel().get("user") instanceof User); - } - - @Test - public void testPostLoginCheckSucceed() { - user.setUsername("admin"); - user.setPassword("admin"); - String view = loginController.postLoginCheck(user, results); - assertFalse(results.hasErrors()); - assertEquals("redirect:/",view); - } - - @Test - public void testPostLoginCheckFailed() { - user.setUsername("abc"); - user.setPassword("abc"); - String view = loginController.postLoginCheck(user, results); - assertTrue(results.hasErrors()); - assertEquals("login",view); - } -} diff --git a/src/test/java/fr/plil/sio/web/mvc/LogoutControllerTest.java b/src/test/java/fr/plil/sio/web/mvc/LogoutControllerTest.java deleted file mode 100644 index 04e24ff..0000000 --- a/src/test/java/fr/plil/sio/web/mvc/LogoutControllerTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package fr.plil.sio.web.mvc; - -import static org.junit.Assert.*; -import org.junit.Test; - -public class LogoutControllerTest { - - @Test - public void testGetLogout() { - LogoutController logoutController = new LogoutController(); - UserSession userSession = new UserSession(); - userSession.setUsername("blabla"); - logoutController.setUserSession(userSession); - String view = logoutController.getLogout(); - assertNull(userSession.getUsername()); - assertEquals("redirect:/",view); - } -} diff --git a/src/test/java/fr/plil/sio/web/mvc/NewUserControllerTest.java b/src/test/java/fr/plil/sio/web/mvc/NewUserControllerTest.java index 48c0042..e325e2b 100644 --- a/src/test/java/fr/plil/sio/web/mvc/NewUserControllerTest.java +++ b/src/test/java/fr/plil/sio/web/mvc/NewUserControllerTest.java @@ -13,28 +13,20 @@ public class NewUserControllerTest { private NewUserController newUserController; private BindingResult results; - private UserForm user; - private UserRepository userRepository; - private UserSession userSession; - private UserFormValidator userFormValidator; + private UserForm userForm; private UserService userService; @Before public void createInstances() { newUserController = new NewUserController(); - user = new UserForm(); - results = new BeanPropertyBindingResult(user, "user"); - userRepository = mock(UserRepository.class); - User user = new User("admin", "password"); - when(userRepository.findByUsername("admin")).thenReturn(user); - newUserController.setUserRepository(userRepository); + userForm = new UserForm(); + results = new BeanPropertyBindingResult(userForm, "user"); + userService = mock(UserService.class); + User user = new User(); + when(userService.findByUsername("admin")).thenReturn(user); + newUserController.setUserService(userService); userService = mock(UserService.class); newUserController.setUserService(userService); - userSession = new UserSession(); - userSession.setUsername("admin"); - newUserController.setUserSession(userSession); - userFormValidator = new UserFormValidator(); - newUserController.setUserFormValidator(userFormValidator); } @Test @@ -48,9 +40,9 @@ public class NewUserControllerTest { @Test public void testPostNewUserSucceed() { - user.setUsername("abc"); - user.setPassword("abcD#"); - String view = newUserController.postNewUser(user, results); + userForm.setUsername("abc"); + userForm.setPassword("abcD#"); + String view = newUserController.postNewUser(userForm, results); assertFalse(results.hasErrors()); assertEquals("redirect:/", view); verify(userService).createUser("abc", "abcD#"); @@ -58,28 +50,27 @@ public class NewUserControllerTest { @Test public void testPostNewUserFailedNotAdmin() { - user.setUsername("abc"); - user.setPassword("abcD#"); - userSession.setUsername("blabla"); - String view = newUserController.postNewUser(user, results); + userForm.setUsername("abc"); + userForm.setPassword("abcD#"); + String view = newUserController.postNewUser(userForm, results); assertTrue(results.hasErrors()); assertEquals("newUser",view); } @Test public void testPostNewUserFailedValidate() { - user.setUsername("a"); - user.setPassword("abc"); - String view = newUserController.postNewUser(user, results); + userForm.setUsername("a"); + userForm.setPassword("abc"); + String view = newUserController.postNewUser(userForm, results); assertTrue(results.hasErrors()); assertEquals("newUser",view); } @Test public void testPostNewUserFailedAlreadyPresent() { - user.setUsername("admin"); - user.setPassword("blabla"); - String view = newUserController.postNewUser(user, results); + userForm.setUsername("admin"); + userForm.setPassword("blabla"); + String view = newUserController.postNewUser(userForm, results); assertTrue(results.hasErrors()); assertEquals("newUser",view); } diff --git a/src/test/java/fr/plil/sio/web/mvc/UserFormValidatorTest.java b/src/test/java/fr/plil/sio/web/mvc/UserFormValidatorTest.java deleted file mode 100644 index 44c8a9d..0000000 --- a/src/test/java/fr/plil/sio/web/mvc/UserFormValidatorTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package fr.plil.sio.web.mvc; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.validation.BeanPropertyBindingResult; -import org.springframework.validation.Errors; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class UserFormValidatorTest { - - private UserForm user; - private UserFormValidator validator; - private Errors results; - - @Before - public void createInstances() { - validator = new UserFormValidator(); - user = new UserForm(); - user.setUsername("abc"); - user.setPassword("abc#A"); - results = new BeanPropertyBindingResult(user, "user"); - } - - @Test - public void testSupports() { - assertTrue(validator.supports(UserForm.class)); - } - - @Test - public void testValidateCorrect() { - validator.validate(user,results); - assertFalse(results.hasErrors()); - } - -} diff --git a/src/test/java/fr/plil/sio/web/mvc/ViewUsersControllerTest.java b/src/test/java/fr/plil/sio/web/mvc/ViewUsersControllerTest.java index 593183f..a6800b6 100644 --- a/src/test/java/fr/plil/sio/web/mvc/ViewUsersControllerTest.java +++ b/src/test/java/fr/plil/sio/web/mvc/ViewUsersControllerTest.java @@ -24,7 +24,6 @@ public class ViewUsersControllerTest { private ViewUsersController viewUsersController; private UserRepository userRepository; - private UserSession userSession; private MockMvc mockMvc; @@ -34,12 +33,12 @@ public class ViewUsersControllerTest { mockMvc = MockMvcBuilders.standaloneSetup(viewUsersController).build(); userRepository = mock(UserRepository.class); List users = new LinkedList<>(); - users.add(new User("admin", "password")); + User testUser = new User(); + testUser.setPassword("admin"); + testUser.setUsername("password"); + users.add(testUser); when(userRepository.findAll()).thenReturn(users); viewUsersController.setUserRepository(userRepository); - userSession = new UserSession(); - userSession.setUsername("admin"); - viewUsersController.setUserSession(userSession); } @Test @@ -47,7 +46,6 @@ public class ViewUsersControllerTest { mockMvc.perform(get("/")) .andExpect(status().isOk()) .andExpect(view().name("viewUsers")) - .andExpect(model().attributeExists("users")) - .andExpect(model().attributeExists("userSession")); + .andExpect(model().attributeExists("users")); } } -- libgit2 0.21.2