Merge pull request #128 from Doha2012/master

spring security reset password
This commit is contained in:
Eugen 2015-02-02 22:58:38 +02:00
commit bf72c56a9a
16 changed files with 423 additions and 9 deletions

View File

@ -0,0 +1,12 @@
package org.baeldung.persistence.dao;
import org.baeldung.persistence.model.PasswordResetToken;
import org.baeldung.persistence.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PasswordResetTokenRepository extends JpaRepository<PasswordResetToken, Long> {
public PasswordResetToken findByToken(String token);
public PasswordResetToken findByUser(User user);
}

View File

@ -0,0 +1,133 @@
package org.baeldung.persistence.model;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
@Entity
public class PasswordResetToken {
private static final int EXPIRATION = 60 * 24;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String token;
@OneToOne(targetEntity = User.class, fetch = FetchType.EAGER)
@JoinColumn(nullable = false, name = "user_id")
private User user;
private Date expiryDate;
public PasswordResetToken() {
super();
}
public PasswordResetToken(String token) {
super();
this.token = token;
this.expiryDate = calculateExpiryDate(EXPIRATION);
}
public PasswordResetToken(String token, User user) {
super();
this.token = token;
this.user = user;
this.expiryDate = calculateExpiryDate(EXPIRATION);
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Date getExpiryDate() {
return expiryDate;
}
public void setExpiryDate(Date expiryDate) {
this.expiryDate = expiryDate;
}
private Date calculateExpiryDate(int expiryTimeInMinutes) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Timestamp(cal.getTime().getTime()));
cal.add(Calendar.MINUTE, expiryTimeInMinutes);
return new Date(cal.getTime().getTime());
}
public void updateToken(String token) {
this.token = token;
this.expiryDate = calculateExpiryDate(EXPIRATION);
}
//
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((expiryDate == null) ? 0 : expiryDate.hashCode());
result = prime * result + ((token == null) ? 0 : token.hashCode());
result = prime * result + ((user == null) ? 0 : user.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PasswordResetToken other = (PasswordResetToken) obj;
if (expiryDate == null) {
if (other.expiryDate != null)
return false;
} else if (!expiryDate.equals(other.expiryDate))
return false;
if (token == null) {
if (other.token != null)
return false;
} else if (!token.equals(other.token))
return false;
if (user == null) {
if (other.user != null)
return false;
} else if (!user.equals(other.user))
return false;
return true;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("Token [String=").append(token).append("]").append("[Expires").append(expiryDate).append("]");
return builder.toString();
}
}

View File

@ -1,10 +1,8 @@
package org.baeldung.persistence.model;
import java.util.Calendar;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
@ -16,7 +14,7 @@ import javax.persistence.OneToOne;
@Entity
public class VerificationToken {
private static final int EXPIRATION = 60 * 24;
private static final int EXPIRATION = 2;// 60 * 24;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@ -75,11 +73,16 @@ public class VerificationToken {
private Date calculateExpiryDate(int expiryTimeInMinutes) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Timestamp(cal.getTime().getTime()));
cal.setTimeInMillis(new Date().getTime());
cal.add(Calendar.MINUTE, expiryTimeInMinutes);
return new Date(cal.getTime().getTime());
}
public void updateToken(String token) {
this.token = token;
this.expiryDate = calculateExpiryDate(EXPIRATION);
}
//
@Override

View File

@ -1,5 +1,6 @@
package org.baeldung.persistence.service;
import org.baeldung.persistence.model.PasswordResetToken;
import org.baeldung.persistence.model.User;
import org.baeldung.persistence.model.VerificationToken;
import org.baeldung.validation.EmailExistsException;
@ -18,4 +19,17 @@ public interface IUserService {
VerificationToken getVerificationToken(String VerificationToken);
VerificationToken updateVerificationToken(String token);
void createPasswordResetTokenForUser(User user, String token);
User findUserByEmail(String email);
PasswordResetToken getPasswordResetToken(String token);
User getUserByPasswordResetToken(String token);
User getUserByID(long id);
void changeUserPassword(User user, String password);
}

View File

@ -1,12 +1,15 @@
package org.baeldung.persistence.service;
import java.util.Arrays;
import java.util.UUID;
import javax.transaction.Transactional;
import org.baeldung.persistence.dao.PasswordResetTokenRepository;
import org.baeldung.persistence.dao.RoleRepository;
import org.baeldung.persistence.dao.UserRepository;
import org.baeldung.persistence.dao.VerificationTokenRepository;
import org.baeldung.persistence.model.PasswordResetToken;
import org.baeldung.persistence.model.User;
import org.baeldung.persistence.model.VerificationToken;
import org.baeldung.validation.EmailExistsException;
@ -23,6 +26,9 @@ public class UserService implements IUserService {
@Autowired
private VerificationTokenRepository tokenRepository;
@Autowired
private PasswordResetTokenRepository passwordTokenRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@ -74,6 +80,39 @@ public class UserService implements IUserService {
tokenRepository.save(myToken);
}
public VerificationToken updateVerificationToken(String verificationToken) {
VerificationToken vToken = tokenRepository.findByToken(verificationToken);
vToken.updateToken(UUID.randomUUID().toString());
vToken = tokenRepository.save(vToken);
return vToken;
}
public void createPasswordResetTokenForUser(User user, String token) {
PasswordResetToken myToken = new PasswordResetToken(token, user);
passwordTokenRepository.save(myToken);
}
public User findUserByEmail(String email) {
return repository.findByEmail(email);
}
public PasswordResetToken getPasswordResetToken(String token) {
return passwordTokenRepository.findByToken(token);
}
public User getUserByPasswordResetToken(String token) {
return passwordTokenRepository.findByToken(token).getUser();
}
public User getUserByID(long id) {
return repository.findOne(id);
}
public void changeUserPassword(User user, String password) {
user.setPassword(passwordEncoder.encode(password));
repository.save(user);
}
private boolean emailExist(String email) {
User user = repository.findByEmail(email);
if (user != null) {

View File

@ -41,6 +41,7 @@ public class RegistrationListener implements ApplicationListener<OnRegistrationC
email.setTo(recipientAddress);
email.setSubject(subject);
email.setText(message + " \r\n" + "http://localhost:8080" + confirmationUrl);
System.out.println(email.getText());
mailSender.send(email);
}
}

View File

@ -56,7 +56,7 @@ public class MyUserDetailsService implements UserDetailsService {
// UTIL
private final Collection<? extends GrantedAuthority> getAuthorities(final Collection<Role> roles) {
public final Collection<? extends GrantedAuthority> getAuthorities(final Collection<Role> roles) {
return getGrantedAuthorities(getPrivileges(roles));
}

View File

@ -48,6 +48,8 @@ public class MvcConfig extends WebMvcConfigurerAdapter {
registry.addViewController("/admin.html");
registry.addViewController("/registration.html");
registry.addViewController("/successRegister.html");
registry.addViewController("/forgetPassword.html");
registry.addViewController("/updatePassword.html");
}
@Override

View File

@ -1,14 +1,18 @@
package org.baeldung.web.controller;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.UUID;
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.UserDto;
import org.baeldung.persistence.service.IUserService;
import org.baeldung.persistence.service.UserDto;
import org.baeldung.registration.OnRegistrationCompleteEvent;
import org.baeldung.validation.EmailExistsException;
import org.slf4j.Logger;
@ -16,7 +20,13 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.MessageSource;
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;
@ -45,6 +55,9 @@ public class RegistrationController {
@Autowired
private ApplicationEventPublisher eventPublisher;
@Autowired
private UserDetailsService userDetailsService;
public RegistrationController() {
}
@ -70,8 +83,14 @@ public class RegistrationController {
User user = verificationToken.getUser();
Calendar cal = Calendar.getInstance();
DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
System.out.println(df.format(verificationToken.getExpiryDate()));
System.out.println(df.format(cal.getTime()));
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();
}
@ -100,6 +119,93 @@ public class RegistrationController {
return new ModelAndView("successRegister", "user", accountDto);
}
@RequestMapping(value = "/user/resendRegistrationToken", method = RequestMethod.GET)
public String resendRegistrationToken(WebRequest request, Model model, @RequestParam("token") String token) {
Locale locale = request.getLocale();
VerificationToken newToken = service.updateVerificationToken(token);
User user = service.getUser(newToken.getToken());
try {
String confirmationUrl = request.getContextPath() + "/regitrationConfirm.html?token=" + newToken.getToken();
String message = messages.getMessage("message.resendToken", null, request.getLocale());
SimpleMailMessage email = new SimpleMailMessage();
email.setTo(user.getEmail());
email.setSubject("Resend Registration Token");
email.setText(message + " \r\n" + "http://localhost:8080" + confirmationUrl);
System.out.println(email.getText());
mailSender.send(email);
System.out.println(email.getText());
} catch (Exception e) {
return "redirect:/emailError.html?lang=" + locale.getLanguage();
}
model.addAttribute("message", messages.getMessage("message.resendToken", null, locale));
return "redirect:/login.html?lang=" + locale.getLanguage();
}
@RequestMapping(value = "/user/resetPassword", method = RequestMethod.POST)
public String resetPassword(WebRequest request, Model model, @RequestParam("email") String userEmail) {
User user = service.findUserByEmail(userEmail);
if (user == null) {
model.addAttribute("message", messages.getMessage("auth.message.expired", null, request.getLocale()));
return "redirect:/login.html?lang=" + request.getLocale().getLanguage();
}
String token = UUID.randomUUID().toString();
service.createPasswordResetTokenForUser(user, token);
try {
String url = request.getContextPath() + "/user/changePassword?id=" + user.getId() + "&token=" + token;
String message = messages.getMessage("message.resetPassword", null, request.getLocale());
SimpleMailMessage email = new SimpleMailMessage();
email.setTo(user.getEmail());
email.setSubject("Reset Password");
email.setText(message + " \r\n" + "http://localhost:8080" + url);
System.out.println(email.getText());
mailSender.send(email);
System.out.println(email.getText());
} catch (Exception e) {
return "redirect:/emailError.html?lang=" + request.getLocale().getLanguage();
}
model.addAttribute("message", messages.getMessage("message.resetPassword", null, request.getLocale()));
return "redirect:/login.html?lang=" + request.getLocale().getLanguage();
}
@RequestMapping(value = "/user/changePassword", method = RequestMethod.GET)
public String changePassword(WebRequest request, Model model, @RequestParam("id") long id, @RequestParam("token") String token) {
Locale locale = request.getLocale();
PasswordResetToken passToken = service.getPasswordResetToken(token);
User user = passToken.getUser();
if (passToken == null || user.getId() != id) {
String message = messages.getMessage("auth.message.invalidToken", null, locale);
model.addAttribute("message", message);
System.out.println(id);
System.out.println(passToken);
return "redirect:/login.html?lang=" + locale.getLanguage();
}
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();
}
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/savePassword", method = RequestMethod.POST)
@PreAuthorize("hasRole('READ_PRIVILEGE')")
public String savePassword(WebRequest request, Model model, @RequestParam("password") String password) {
Locale locale = request.getLocale();
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
service.changeUserPassword(user, password);
return "redirect:/login.html?lang=" + locale;
}
private User createUserAccount(UserDto accountDto) {
User registered = null;
try {
@ -109,4 +215,4 @@ public class RegistrationController {
}
return registered;
}
}
}

View File

@ -52,4 +52,9 @@ NotEmpty.user.password=Password required
NotNull.user.matchingPassword=Required
NotEmpty.user.matchingPassword=Required
PasswordMatches.user:Password does not match!
Email.user.email=Invalid Username (Email)
Email.user.email=Invalid Username (Email)
label.form.resendRegistrationToken=Re-send Token
message.resendToken=We will send you a message with a new registration token to your email account.
message.forgetPassword=Forget Password
message.resetPassword=Reset Password
message.updatePassword=Update Password

View File

@ -53,3 +53,4 @@ NotNull.user.matchingPassword=Campo obligatirio
NotEmpty.user.matchingPassword=Campo obligatrio
PasswordMatches.user:Las claves no coinciden!
Email.user.email=Email no es valido
label.form.resendRegistrationToken=Reenviar mensaje de emergencia

View File

@ -15,6 +15,12 @@
<intercept-url pattern="/expiredAccount*" access="permitAll" />
<intercept-url pattern="/registration*" access="permitAll" />
<intercept-url pattern="/badUser*" access="permitAll" />
<intercept-url pattern="/user/resendRegistrationToken*" access="permitAll" />
<intercept-url pattern="/forgetPassword*" access="permitAll" />
<intercept-url pattern="/user/resetPassword*" access="permitAll" />
<intercept-url pattern="/user/changePassword*" access="permitAll" />
<intercept-url pattern="/updatePassword*" access="isAuthenticated()" />
<intercept-url pattern="/user/savePassword*" access="isAuthenticated()" />
<intercept-url pattern="/emailError*" access="permitAll" />
<intercept-url pattern="/resources/**" access="permitAll" />

View File

@ -20,5 +20,15 @@ code="label.badUser.title"></spring:message></title>
<a href="<c:url value="/user/registration" />"><spring:message
code="label.form.loginSignUp"></spring:message></a>
<c:if test="${param.expired}">
<br>
<h1>${label.form.resendRegistrationToken}</h1>
<a href="<c:url value="/user/resendRegistrationToken">
<c:param name="token" value="${param.token}"/>
</c:url>">
<spring:message code="label.form.resendRegistrationToken"></spring:message>
</a>
</c:if>
</body>
</html>

View File

@ -0,0 +1,39 @@
<!DOCTYPE html>
<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="sec"
uri="http://www.springframework.org/security/tags"%>
<%@ page session="false"%>
<html>
<head>
<link href="<c:url value="/resources/bootstrap.css" />" rel="stylesheet">
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title><spring:message code="message.resetPassword"></spring:message></title>
</head>
<body>
<div class="container">
<div class="span12">
<H1>
<spring:message code="message.resetPassword"></spring:message>
</H1>
<form:form action="user/resetPassword" method="POST" enctype="utf8">
<br>
<tr>
<td><label><spring:message code="label.user.email"></spring:message></label></td>
<td><input name="email" type="email" value="" /></td>
</tr>
<button type="submit">
<spring:message code="message.resetPassword"></spring:message>
</button>
</form:form>
<br> <a href="<c:url value="registration.html" />"><spring:message
code="label.form.loginSignUp"></spring:message></a>
</div>
</div>
</body>
</html>

View File

@ -25,6 +25,8 @@
<div class="alert alert-error">
<!-- <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/> -->
<spring:message code="message.badCredentials"></spring:message>
<a href="<c:url value="/forgetPassword.html" />"><spring:message
code="message.forgetPassword"></spring:message></a>
</div>
</c:otherwise>
</c:choose>

View File

@ -0,0 +1,41 @@
<!DOCTYPE html>
<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="sec"
uri="http://www.springframework.org/security/tags"%>
<%@ page session="false"%>
<html>
<head>
<link href="<c:url value="/resources/bootstrap.css" />" rel="stylesheet">
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title><spring:message code="message.updatePassword"></spring:message></title>
</head>
<body>
<sec:authorize access="hasRole('READ_PRIVILEGE')">
<div class="container">
<div class="span12">
<H1>
<spring:message code="message.updatePassword"></spring:message>
</H1>
<form:form action="user/savePassword" method="POST" enctype="utf8">
<br>
<tr>
<td><label><spring:message code="label.user.password"></spring:message></label></td>
<td><input name="password" type="password" value="" /></td>
</tr>
<button type="submit">
<spring:message code="message.updatePassword"></spring:message>
</button>
</form:form>
</div>
</div>
</sec:authorize>
</body>
</html>