/* vim: set ts=2 et sw=2 cindent fo=qroca: */ package com.globant.katari.registration.application; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.UUID; import org.acegisecurity.Authentication; import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.apache.commons.lang.Validate; import org.slf4j.LoggerFactory; import org.slf4j.Logger; import org.springframework.validation.Errors; import com.globant.katari.core.application.Command; import com.globant.katari.core.application.Validatable; import com.globant.katari.email.application.EmailSender; import com.globant.katari.email.model.EmailModel; import com.globant.katari.registration.domain.EmailConfigurer; import com.globant.katari.registration.domain.RecoverPasswordRequest; import com.globant.katari.registration.domain.RegistrationRepository; import com.globant.katari.user.domain.User; import com.globant.katari.user.domain.UserRepository; import com.globant.katari.user.integration.DomainUserDetails; /** Resets the password for the given user id and token. * * Passwords can be reset only for tokens that are 12 hours old or less. * * @author waabox (emiliano[dot]arango[at]globant[dot]com) */ public class ResetPasswordCommand implements Command<User>, Validatable { /** The class logger. */ private static Logger log = LoggerFactory.getLogger( ResetPasswordCommand.class); /** The token life, in ms (12 hours). */ private static final long TIME_TO_LIVE = 12 * 60 * 60 * 1000; /** The registration repository. It's never null */ private final RegistrationRepository registrationRepository; /** The user repository. It's never null. */ private final UserRepository userRepository; /** The email sender, never null.*/ private final EmailSender emailSender; /** The generated token for the reset password operation.*/ private String token; /** The user id.*/ private long userId; /** The email configurer. */ private final EmailConfigurer emailConfigurer; /** The password lenght. */ private static final int PASSWORD_LENGHT = 20; /** Builds the command. * @param theRegistrationRepository The reg repository. Cannot be null. * @param theUserRepository The user repository. Cannot be null. * @param theEmailSender The email sender. Cannot be null. * @param theEmailConfigurer The email configurer. Cannot be null. */ public ResetPasswordCommand( final RegistrationRepository theRegistrationRepository, final UserRepository theUserRepository, final EmailSender theEmailSender, final EmailConfigurer theEmailConfigurer) { Validate.notNull(theRegistrationRepository, "RegistrationRepository cannot be null"); Validate.notNull(theUserRepository, "UserRepository cannot be null"); Validate.notNull(theEmailSender, "EmailSender cannot be null"); Validate.notNull(theEmailConfigurer, "EmailConfigurer cannot be null"); registrationRepository = theRegistrationRepository; userRepository = theUserRepository; emailSender = theEmailSender; emailConfigurer = theEmailConfigurer; } /** Validates that the provided token is valid and corresponds to the user. * * {@inheritDoc} */ public void validate(final Errors errors) { RecoverPasswordRequest request; request = registrationRepository.findRecoverPasswordRequest(userId, token); if (request == null) { errors.rejectValue("token", "forgotpassword.token.invalid", "The reset password request is invalid or too old."); } } /** Retrieve recover password request by the userId + token and also * checks that the token is active. * * Double check that the userId and token are not null, else, will raise * an IllegalArgumentException. * * @return the user or null if the recover password token do not exist, or * the token is expired. */ public User execute() { Validate.notNull(userId, "The userId cannot be null"); Validate.notNull(token, "The token cannot be null"); RecoverPasswordRequest request; request = registrationRepository.findRecoverPasswordRequest(userId, token); if (request == null) { return null; } Date creationDate = request.getCreationDate(); Date expiration = new Date(System.currentTimeMillis() - TIME_TO_LIVE); if (expiration.after(creationDate)) { return null; } String newPassword = generatePassword(); User user = userRepository.findUser(request.getUserId()); user.changePassword(newPassword); userRepository.save(user); log.debug("Returning the user: {}", user.getEmail()); Map<String, Object> values = new HashMap<String, Object>(1); values.put("newPassword", newPassword); EmailModel emailModel = new EmailModel(emailConfigurer.getEmailFrom(), user.getEmail(), values, emailConfigurer.getPlainMessage(), emailConfigurer.getSubject()); emailSender.send(emailModel, emailConfigurer.getTemplate()); log.debug("Authenticating the user: " + user.getEmail()); DomainUserDetails details = new DomainUserDetails(user); Authentication authentication = new UsernamePasswordAuthenticationToken( details, "", details.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authentication); return user; } /** Generate a new password for the user. * @return the new password. */ private String generatePassword() { return UUID.randomUUID().toString().substring(0, PASSWORD_LENGHT); } /** Sets the user token. * @param userToken the token to set. */ public void setToken(final String userToken) { token = userToken; } /** Gets the user token. * * @return the user token. */ public String getToken() { return token; } /** Sets the userId. * @param theUserId the user id. */ public void setUserId(final Long theUserId) { userId = theUserId; } }