Package org.jboss.seam.wiki.core.action

Source Code of org.jboss.seam.wiki.core.action.UserPasswordReset

/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.seam.wiki.core.action;

import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.international.StatusMessages;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.faces.Renderer;
import org.jboss.seam.log.Log;
import org.jboss.seam.wiki.core.action.prefs.UserManagementPreferences;
import org.jboss.seam.wiki.core.action.prefs.WikiPreferences;
import org.jboss.seam.wiki.core.dao.UserDAO;
import org.jboss.seam.wiki.core.model.User;
import org.jboss.seam.wiki.preferences.Preferences;
import org.jboss.seam.wiki.util.Hash;

import static org.jboss.seam.international.StatusMessage.Severity.ERROR;
import static org.jboss.seam.international.StatusMessage.Severity.WARN;
import static org.jboss.seam.international.StatusMessage.Severity.INFO;

import javax.persistence.EntityManager;
import java.io.Serializable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* The password reset feature works as follows:
*
* - User enters username and e-mail address. The account does not have to be activated, so
*   the "Reset Password" functionality can also serve as "Resend Activation E-Mail".
*
* - Both username and e-mail address are checked with what we have in the database.
*
* - An activation code is generated and stored in the database for this user account.
*
* - An e-mail with the activation code is send to the users e-mail address.
*
* - If the user clicks on the activation link, the login form on the page will
*   switch to a password reset form. (If the activation code was correct.)
*
* - After typing in the password twice, the user account gets a new password and
*   we also activate it.
*
*
* @author Christian Bauer
*/
@Name("userPasswordReset")
@Scope(ScopeType.CONVERSATION)
public class UserPasswordReset implements Serializable {

    public static final String RESET_PASSWORD_OF_USER = "resetPasswordOfUser";

    @Logger
    Log log;

    @In
    private StatusMessages statusMessages;

    @In("#{preferences.get('UserManagement')}")
    UserManagementPreferences prefs;

    @In(create = true)
    private Renderer renderer;

    @In
    private UserDAO userDAO;

    @In
    protected EntityManager entityManager;

    @In
    private Hash hashUtil;

    private String activationCode;
    private String username;
    private String email;

    private String password;
    private String passwordControl;

    public String getActivationCode() { return activationCode; }
    public void setActivationCode(String activationCode) { this.activationCode = activationCode; }
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }

    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
    public String getPasswordControl() { return passwordControl; }
    public void setPasswordControl(String passwordControl) { this.passwordControl = passwordControl; }


    public void sendResetPasswordEmail() {
        log.debug("trying to reset password of user: " + username);

        User user = getUserForEmail(username, email);
        if (user == null) {
            statusMessages.addFromResourceBundleOrDefault(
                WARN,
                "lacewiki.msg.resetPassword.NotValid",
                "Your account and e-mail address information didn't match, please try again to reset your password."
            );
            username = null;
            email = null;
            return;
        }

        // Set activation code (unique user in time)
        String seed = user.getUsername() + System.currentTimeMillis() + prefs.getActivationCodeSalt();
        user.setActivationCode( ((Hash) Component.getInstance(Hash.class)).hash(seed) );
        // TODO: Flush by side effect?

        try {

            // Outject for email
            Contexts.getEventContext().set(RESET_PASSWORD_OF_USER, user);

            // Send confirmation email
            renderer.render("/themes/"
                    + Preferences.instance().get(WikiPreferences.class).getThemeName()
                    + "/mailtemplates/resetPassword.xhtml");

            statusMessages.addFromResourceBundleOrDefault(
                INFO,
                "lacewiki.msg.resetPassword.EmailSent",
                "A new activation code has been sent to your e-mail address, please read this e-mail to reset your password."
            );

        } catch (Exception ex) {
            statusMessages.add(WARN, "Couldn't send password reset email: " + ex.getMessage());
        }
    }

    public String prepare() {
        User user = userDAO.findUserWithActivationCode(activationCode);
        if (user != null) {
            log.debug("preparing password reset of: " + user);
            user.setActivationCode(null);
            // Outject for form
            Contexts.getSessionContext().set(RESET_PASSWORD_OF_USER, user);

            return "prepared";
        } else {
            return "notFound";
        }
    }

    public void reset() {
        User user = (User)Component.getInstance(RESET_PASSWORD_OF_USER);
        if (user == null) {
            throw new IllegalStateException("No user for password reset in SESSION context");
        }

        // Validate
        if (!passwordAndControlNotNull() ||
            !passwordMatchesRegex() ||
            !passwordMatchesControl()) {

            // Force re-entry
            setPassword(null);
            setPasswordControl(null);

            return;
        }
        log.debug("resetting password of: " + user);

        User persistentUser = userDAO.findUser(user.getId());
        persistentUser.setPasswordHash(hashUtil.hash(getPassword()));

        // As a side effect, also activate the user! http://jira.jboss.com/jira/browse/JBSEAM-2687
        persistentUser.setActivated(true);

        Contexts.getSessionContext().remove(RESET_PASSWORD_OF_USER);

        statusMessages.addFromResourceBundleOrDefault(
            INFO,
            "lacewiki.msg.resetPassword.Complete",
            "Successfully reset password of account '{0}', please log in.",
            persistentUser.getUsername()
        );

    }

    private User getUserForEmail(String username, String email) {
        if (User.GUEST_USERNAME.equals(username)) return null;
        User user = userDAO.findUser(username, false, true);
        return user != null && user.getEmail().equals(email) ? user : null;
    }

    public boolean passwordAndControlNotNull() {
        if (getPassword() == null || getPassword().length() == 0 ||
            getPasswordControl() == null || getPasswordControl().length() == 0) {
            statusMessages.addFromResourceBundleOrDefault(
                WARN,
                "lacewiki.msg.PasswordOrPasswordControlEmpty",
                "Please enter your password twice!"
            );
            return false;
        }
        return true;
    }

    public boolean passwordMatchesRegex() {
        Matcher matcher = Pattern.compile(prefs.getPasswordRegex()).matcher(getPassword());
        if (!matcher.find()) {
            statusMessages.addFromResourceBundleOrDefault(
                WARN,
                "lacewiki.msg.PasswordDoesntMatchPattern",
                "Password does not match the pattern: {0}",
                prefs.getPasswordRegex()
            );
            return false;
        }
        return true;
    }

    public boolean passwordMatchesControl() {
        if (!password.equals(passwordControl) ) {
            statusMessages.addFromResourceBundleOrDefault(
                WARN,
                "lacewiki.msg.PasswordControlNoMatch",
                "The passwords don't match."
            );
            return false;
        }
        return true;
    }

}
TOP

Related Classes of org.jboss.seam.wiki.core.action.UserPasswordReset

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.