From d1eb4546bdc56d1dde1dcbd9d9e94535b72978f3 Mon Sep 17 00:00:00 2001 From: DOHA Date: Mon, 16 Feb 2015 13:22:19 +0200 Subject: [PATCH] update registration methods --- .../listener/RegistrationListener.java | 2 - .../web/controller/GenericResponse.java | 23 -- .../controller/Registration2Controller.java | 219 ++++++++++++++++++ .../controller/RegistrationController.java | 35 --- .../RestResponseEntityExceptionHandler.java | 39 +++- .../web/error/UserNotFoundException.java | 23 ++ .../baeldung/web/util/GenericResponse.java | 34 +++ .../src/main/resources/messages_en.properties | 3 +- .../main/resources/messages_es_ES.properties | 3 +- .../src/main/webapp/WEB-INF/view/badUser.jsp | 12 +- .../webapp/WEB-INF/view/forgetPassword.jsp | 15 +- .../webapp/WEB-INF/view/updatePassword.jsp | 72 +++--- 12 files changed, 359 insertions(+), 121 deletions(-) delete mode 100644 spring-security-login-and-registration/src/main/java/org/baeldung/web/controller/GenericResponse.java create mode 100644 spring-security-login-and-registration/src/main/java/org/baeldung/web/controller/Registration2Controller.java create mode 100644 spring-security-login-and-registration/src/main/java/org/baeldung/web/error/UserNotFoundException.java create mode 100644 spring-security-login-and-registration/src/main/java/org/baeldung/web/util/GenericResponse.java diff --git a/spring-security-login-and-registration/src/main/java/org/baeldung/registration/listener/RegistrationListener.java b/spring-security-login-and-registration/src/main/java/org/baeldung/registration/listener/RegistrationListener.java index 5d9fca4106..16eb2177d5 100644 --- a/spring-security-login-and-registration/src/main/java/org/baeldung/registration/listener/RegistrationListener.java +++ b/spring-security-login-and-registration/src/main/java/org/baeldung/registration/listener/RegistrationListener.java @@ -8,14 +8,12 @@ import org.baeldung.registration.OnRegistrationCompleteEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.context.MessageSource; -import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.stereotype.Component; @Component -@PropertySource("classpath:email.properties") public class RegistrationListener implements ApplicationListener { @Autowired private IUserService service; diff --git a/spring-security-login-and-registration/src/main/java/org/baeldung/web/controller/GenericResponse.java b/spring-security-login-and-registration/src/main/java/org/baeldung/web/controller/GenericResponse.java deleted file mode 100644 index fd2869cf97..0000000000 --- a/spring-security-login-and-registration/src/main/java/org/baeldung/web/controller/GenericResponse.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.baeldung.web.controller; - -public class GenericResponse { - - private String message; - - public GenericResponse() { - super(); - } - - public GenericResponse(final String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - -} diff --git a/spring-security-login-and-registration/src/main/java/org/baeldung/web/controller/Registration2Controller.java b/spring-security-login-and-registration/src/main/java/org/baeldung/web/controller/Registration2Controller.java new file mode 100644 index 0000000000..8d702d669e --- /dev/null +++ b/spring-security-login-and-registration/src/main/java/org/baeldung/web/controller/Registration2Controller.java @@ -0,0 +1,219 @@ +package org.baeldung.web.controller; + +import java.util.Calendar; +import java.util.Locale; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +import org.baeldung.persistence.model.PasswordResetToken; +import org.baeldung.persistence.model.User; +import org.baeldung.persistence.model.VerificationToken; +import org.baeldung.persistence.service.IUserService; +import org.baeldung.persistence.service.UserDto; +import org.baeldung.registration.OnRegistrationCompleteEvent; +import org.baeldung.validation.EmailExistsException; +import org.baeldung.web.error.UserNotFoundException; +import org.baeldung.web.util.GenericResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.MessageSource; +import org.springframework.core.env.Environment; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.validation.Errors; +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.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class Registration2Controller { + private final Logger LOGGER = LoggerFactory.getLogger(getClass()); + + @Autowired + private IUserService userService; + + @Autowired + private MessageSource messages; + + @Autowired + private JavaMailSender mailSender; + + @Autowired + private ApplicationEventPublisher eventPublisher; + + @Autowired + private UserDetailsService userDetailsService; + + @Autowired + private Environment env; + + public Registration2Controller() { + + } + + // API + + @RequestMapping(value = "/user/registration2", method = RequestMethod.GET) + public String showRegistrationForm(final HttpServletRequest request, final Model model) { + LOGGER.debug("Rendering registration page."); + final UserDto accountDto = new UserDto(); + model.addAttribute("user", accountDto); + return "registration"; + } + + @RequestMapping(value = "/regitrationConfirm2", method = RequestMethod.GET) + public String confirmRegistration(final HttpServletRequest request, final Model model, @RequestParam("token") final String token) { + final Locale locale = request.getLocale(); + + final VerificationToken verificationToken = userService.getVerificationToken(token); + if (verificationToken == null) { + final String message = messages.getMessage("auth.message.invalidToken", null, locale); + model.addAttribute("message", message); + return "redirect:/badUser.html?lang=" + locale.getLanguage(); + } + + final User user = verificationToken.getUser(); + final Calendar cal = Calendar.getInstance(); + if ((verificationToken.getExpiryDate().getTime() - cal.getTime().getTime()) <= 0) { + model.addAttribute("message", messages.getMessage("auth.message.expired", null, locale)); + model.addAttribute("expired", true); + model.addAttribute("token", token); + return "redirect:/badUser.html?lang=" + locale.getLanguage(); + } + + user.setEnabled(true); + userService.saveRegisteredUser(user); + model.addAttribute("message", messages.getMessage("message.accountVerified", null, locale)); + return "redirect:/login.html?lang=" + locale.getLanguage(); + } + + @RequestMapping(value = "/user/registration2", method = RequestMethod.POST) + public ModelAndView registerUserAccount(@ModelAttribute("user") @Valid final UserDto accountDto, final BindingResult result, final HttpServletRequest request, final Errors errors) { + LOGGER.debug("Registering user account with information: {}", accountDto); + if (result.hasErrors()) { + return new ModelAndView("registration", "user", accountDto); + } + + final User registered = createUserAccount(accountDto); + if (registered == null) { + result.rejectValue("email", "message.regError"); + return new ModelAndView("registration", "user", accountDto); + } + try { + final String appUrl = "http://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath(); + eventPublisher.publishEvent(new OnRegistrationCompleteEvent(registered, request.getLocale(), appUrl)); + } catch (final Exception ex) { + LOGGER.warn("Unable to register user", ex); + return new ModelAndView("emailError", "user", accountDto); + } + return new ModelAndView("successRegister", "user", accountDto); + } + + @RequestMapping(value = "/user/resendRegistrationToken2", method = RequestMethod.GET) + public @ResponseBody GenericResponse resendRegistrationToken2(final HttpServletRequest request, @RequestParam("token") final String existingToken) { + final VerificationToken newToken = userService.generateNewVerificationToken(existingToken); + final User user = userService.getUser(newToken.getToken()); + final String appUrl = "http://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath(); + final SimpleMailMessage email = constructResetVerificationTokenEmail(appUrl, request.getLocale(), newToken, user); + mailSender.send(email); + return new GenericResponse(messages.getMessage("message.resendToken", null, request.getLocale())); + } + + @RequestMapping(value = "/user/resetPassword2", method = RequestMethod.POST) + public @ResponseBody GenericResponse resetPassword2(final HttpServletRequest request, @RequestParam("email") final String userEmail) { + final User user = userService.findUserByEmail(userEmail); + if (user == null) { + throw new UserNotFoundException(); + } + + final String token = UUID.randomUUID().toString(); + userService.createPasswordResetTokenForUser(user, token); + final String appUrl = "http://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath(); + final SimpleMailMessage email = constructResetTokenEmail(appUrl, request.getLocale(), token, user); + mailSender.send(email); + + return new GenericResponse(messages.getMessage("message.resetPasswordEmail", null, request.getLocale())); + } + + // ==== will not be changed this is used as the confirmation url of reset password token + @RequestMapping(value = "/user/changePassword2", method = RequestMethod.GET) + public String changePassword(final HttpServletRequest request, final Model model, @RequestParam("id") final long id, @RequestParam("token") final String token) { + final Locale locale = request.getLocale(); + + final PasswordResetToken passToken = userService.getPasswordResetToken(token); + final User user = passToken.getUser(); + if (passToken == null || user.getId() != id) { + final String message = messages.getMessage("auth.message.invalidToken", null, locale); + model.addAttribute("message", message); + return "redirect:/login.html?lang=" + locale.getLanguage(); + } + + final Calendar cal = Calendar.getInstance(); + if ((passToken.getExpiryDate().getTime() - cal.getTime().getTime()) <= 0) { + model.addAttribute("message", messages.getMessage("auth.message.expired", null, locale)); + return "redirect:/login.html?lang=" + locale.getLanguage(); + } + + final Authentication auth = new UsernamePasswordAuthenticationToken(user, null, userDetailsService.loadUserByUsername(user.getEmail()).getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(auth); + + return "redirect:/updatePassword.html?lang=" + locale.getLanguage(); + } + + @RequestMapping(value = "/user/savePassword2", method = RequestMethod.POST) + @PreAuthorize("hasRole('READ_PRIVILEGE')") + public @ResponseBody GenericResponse savePassword(final HttpServletRequest request, @RequestParam("password") final String password) { + final User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + userService.changeUserPassword(user, password); + return new GenericResponse(messages.getMessage("message.resetPasswordSuc", null, request.getLocale())); + } + + // NON-API + + private final SimpleMailMessage constructResetVerificationTokenEmail(final String contextPath, final Locale locale, final VerificationToken newToken, final User user) { + final String confirmationUrl = contextPath + "/regitrationConfirm.html?token=" + newToken.getToken(); + final String message = messages.getMessage("message.resendToken", null, locale); + final SimpleMailMessage email = new SimpleMailMessage(); + email.setSubject("Resend Registration Token"); + email.setText(message + " \r\n" + confirmationUrl); + email.setTo(user.getEmail()); + email.setFrom(env.getProperty("support.email")); + return email; + } + + private final SimpleMailMessage constructResetTokenEmail(final String contextPath, final Locale locale, final String token, final User user) { + final String url = contextPath + "/user/changePassword2?id=" + user.getId() + "&token=" + token; + final String message = messages.getMessage("message.resetPassword", null, locale); + final SimpleMailMessage email = new SimpleMailMessage(); + email.setTo(user.getEmail()); + email.setSubject("Reset Password"); + email.setText(message + " \r\n" + url); + email.setFrom(env.getProperty("support.email")); + return email; + } + + private User createUserAccount(final UserDto accountDto) { + User registered = null; + try { + registered = userService.registerNewUserAccount(accountDto); + } catch (final EmailExistsException e) { + return null; + } + return registered; + } +} diff --git a/spring-security-login-and-registration/src/main/java/org/baeldung/web/controller/RegistrationController.java b/spring-security-login-and-registration/src/main/java/org/baeldung/web/controller/RegistrationController.java index b7bbeab977..5879e5ddb3 100644 --- a/spring-security-login-and-registration/src/main/java/org/baeldung/web/controller/RegistrationController.java +++ b/spring-security-login-and-registration/src/main/java/org/baeldung/web/controller/RegistrationController.java @@ -19,8 +19,6 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.MessageSource; -import org.springframework.context.NoSuchMessageException; -import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.mail.MailAuthenticationException; import org.springframework.mail.SimpleMailMessage; @@ -38,14 +36,9 @@ 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.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - @Controller -@PropertySource("classpath:email.properties") public class RegistrationController { private final Logger LOGGER = LoggerFactory.getLogger(getClass()); @@ -150,17 +143,6 @@ public class RegistrationController { return "redirect:/login.html?lang=" + locale.getLanguage(); } - @RequestMapping(value = "/user/resendRegistrationToken2", method = RequestMethod.GET) - public @ResponseBody GenericResponse resendRegistrationToken2(final HttpServletRequest request, @RequestParam("token") final String existingToken) { - final VerificationToken newToken = userService.generateNewVerificationToken(existingToken); - final User user = userService.getUser(newToken.getToken()); - final String appUrl = "http://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath(); - final SimpleMailMessage email = constructResetVerificationTokenEmail(appUrl, request.getLocale(), newToken, user); - mailSender.send(email); - - return new GenericResponse(messages.getMessage("message.resendToken", null, request.getLocale())); - } - @RequestMapping(value = "/user/resetPassword", method = RequestMethod.POST) public String resetPassword(final HttpServletRequest request, final Model model, @RequestParam("email") final String userEmail) { final User user = userService.findUserByEmail(userEmail); @@ -187,23 +169,6 @@ public class RegistrationController { return "redirect:/login.html?lang=" + request.getLocale().getLanguage(); } - @RequestMapping(value = "/user/resetPassword2", method = RequestMethod.POST) - public @ResponseBody String resetPassword2(final HttpServletRequest request, @RequestParam("email") final String userEmail) throws JsonProcessingException, NoSuchMessageException { - final User user = userService.findUserByEmail(userEmail); - if (user == null) { - // throw new NotFoundExceptions(messages.getMessage("message.userNotFound", null, request.getLocale())); // 404 - return new ObjectMapper().writeValueAsString(messages.getMessage("message.userNotFound", null, request.getLocale())); - } - - final String token = UUID.randomUUID().toString(); - userService.createPasswordResetTokenForUser(user, token); - final String appUrl = "http://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath(); - final SimpleMailMessage email = constructResetTokenEmail(appUrl, request.getLocale(), token, user); - mailSender.send(email); - - return new ObjectMapper().writeValueAsString(messages.getMessage("message.resetPasswordEmail", null, request.getLocale())); - } - @RequestMapping(value = "/user/changePassword", method = RequestMethod.GET) public String changePassword(final HttpServletRequest request, final Model model, @RequestParam("id") final long id, @RequestParam("token") final String token) { final Locale locale = request.getLocale(); diff --git a/spring-security-login-and-registration/src/main/java/org/baeldung/web/error/RestResponseEntityExceptionHandler.java b/spring-security-login-and-registration/src/main/java/org/baeldung/web/error/RestResponseEntityExceptionHandler.java index e77f6798b0..d263e0fc26 100644 --- a/spring-security-login-and-registration/src/main/java/org/baeldung/web/error/RestResponseEntityExceptionHandler.java +++ b/spring-security-login-and-registration/src/main/java/org/baeldung/web/error/RestResponseEntityExceptionHandler.java @@ -1,35 +1,50 @@ package org.baeldung.web.error; +import org.baeldung.web.util.GenericResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.mail.MailAuthenticationException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - @ControllerAdvice public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { + @Autowired + private MessageSource messages; + public RestResponseEntityExceptionHandler() { super(); } // API - // 500 - @ExceptionHandler({ MailAuthenticationException.class }) - public @ResponseBody String handleMail(final RuntimeException ex, final WebRequest request) throws JsonProcessingException { - logger.error("500 Status Code", ex); - return new ObjectMapper().writeValueAsString("MailError"); + // 404 + @ExceptionHandler({ UserNotFoundException.class }) + public ResponseEntity handleUserNotFound(final RuntimeException ex, final WebRequest request) { + logger.error("404 Status Code", ex); + final GenericResponse bodyOfResponse = new GenericResponse(messages.getMessage("message.userNotFound", null, request.getLocale()), "UserNotFound"); + return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.NOT_FOUND, request); } - @ExceptionHandler({ NullPointerException.class, IllegalArgumentException.class, IllegalStateException.class }) - public @ResponseBody String handleInternal(final RuntimeException ex, final WebRequest request) throws JsonProcessingException { + // 500 + @ExceptionHandler({ MailAuthenticationException.class }) + public ResponseEntity handleMail(final RuntimeException ex, final WebRequest request) { logger.error("500 Status Code", ex); - return new ObjectMapper().writeValueAsString("InternalError"); + final GenericResponse bodyOfResponse = new GenericResponse(messages.getMessage("message.email.config.error", null, request.getLocale()), "MailError"); + return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.NOT_FOUND, request); + } + + @ExceptionHandler({ Exception.class }) + public ResponseEntity handleInternal(final RuntimeException ex, final WebRequest request) { + logger.error("500 Status Code", ex); + final GenericResponse bodyOfResponse = new GenericResponse(messages.getMessage("message.error", null, request.getLocale()), "InternalError"); + return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.NOT_FOUND, request); } } diff --git a/spring-security-login-and-registration/src/main/java/org/baeldung/web/error/UserNotFoundException.java b/spring-security-login-and-registration/src/main/java/org/baeldung/web/error/UserNotFoundException.java new file mode 100644 index 0000000000..4f45e0f978 --- /dev/null +++ b/spring-security-login-and-registration/src/main/java/org/baeldung/web/error/UserNotFoundException.java @@ -0,0 +1,23 @@ +package org.baeldung.web.error; + +public final class UserNotFoundException extends RuntimeException { + + private static final long serialVersionUID = 5861310537366287163L; + + public UserNotFoundException() { + super(); + } + + public UserNotFoundException(final String message, final Throwable cause) { + super(message, cause); + } + + public UserNotFoundException(final String message) { + super(message); + } + + public UserNotFoundException(final Throwable cause) { + super(cause); + } + +} diff --git a/spring-security-login-and-registration/src/main/java/org/baeldung/web/util/GenericResponse.java b/spring-security-login-and-registration/src/main/java/org/baeldung/web/util/GenericResponse.java new file mode 100644 index 0000000000..b80c8ef578 --- /dev/null +++ b/spring-security-login-and-registration/src/main/java/org/baeldung/web/util/GenericResponse.java @@ -0,0 +1,34 @@ +package org.baeldung.web.util; + +public class GenericResponse { + private String message; + private String error; + + public GenericResponse(String message) { + super(); + this.message = message; + } + + public GenericResponse(String message, String error) { + super(); + this.message = message; + this.error = error; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + +} diff --git a/spring-security-login-and-registration/src/main/resources/messages_en.properties b/spring-security-login-and-registration/src/main/resources/messages_en.properties index eba22ff73e..f3ad8d2307 100644 --- a/spring-security-login-and-registration/src/main/resources/messages_en.properties +++ b/spring-security-login-and-registration/src/main/resources/messages_en.properties @@ -63,4 +63,5 @@ auth.message.blocked=This ip is blocked for 24 hours message.accountVerified=Your account verified successfully message.resetPasswordSuc=Password reset successfully message.resetYourPassword=Reset your password -message.resetPasswordEmail=You should receive an Password Reset Email shortly \ No newline at end of file +message.resetPasswordEmail=You should receive an Password Reset Email shortly +message.error=Error Occurred \ No newline at end of file diff --git a/spring-security-login-and-registration/src/main/resources/messages_es_ES.properties b/spring-security-login-and-registration/src/main/resources/messages_es_ES.properties index a20b5fb4dc..0830f94336 100644 --- a/spring-security-login-and-registration/src/main/resources/messages_es_ES.properties +++ b/spring-security-login-and-registration/src/main/resources/messages_es_ES.properties @@ -63,4 +63,5 @@ auth.message.blocked=Esta IP se bloquea durante 24 horas message.accountVerified=Su cuenta verificada con éxito message.resetPasswordSuc=Contraseña reajusta correctamente message.resetYourPassword=Restablecer su contraseña -message.resetPasswordEmail=Te enviaremos un correo electrónico para restablecer su contraseña \ No newline at end of file +message.resetPasswordEmail=Te enviaremos un correo electrónico para restablecer su contraseña +message.error=Se produjo un error \ No newline at end of file diff --git a/spring-security-login-and-registration/src/main/webapp/WEB-INF/view/badUser.jsp b/spring-security-login-and-registration/src/main/webapp/WEB-INF/view/badUser.jsp index d85a4ca371..919bcaeb69 100644 --- a/spring-security-login-and-registration/src/main/webapp/WEB-INF/view/badUser.jsp +++ b/spring-security-login-and-registration/src/main/webapp/WEB-INF/view/badUser.jsp @@ -32,15 +32,15 @@ code="label.form.loginSignUp"> +function savePass(){ + var pass = $("#pass").val(); + var valid = pass == $("#passConfirm").val(); + if(!valid) { + $("#error").show(); + return; + } + $.post("",{password: pass} ,function(data){ + window.location.href = "" + "?message="+data.message; + }) + .fail(function(data) { + window.location.href = "" + "?message=" + data.responseJSON.message; + }); +} + + \ No newline at end of file