eu.scape_project.pw.idp.UserManager.java Source code

Java tutorial

Introduction

Here is the source code for eu.scape_project.pw.idp.UserManager.java

Source

/*******************************************************************************
 * Copyright 2006 - 2012 Vienna University of Technology,
 * Department of Software Technology and Interactive Systems, IFS
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package eu.scape_project.pw.idp;

import java.util.List;
import java.util.Properties;
import java.util.UUID;

import javax.annotation.PostConstruct;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.mail.Message.RecipientType;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.persistence.EntityManager;

import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;

import eu.scape_project.pw.idp.excpetions.CannotSendMailException;
import eu.scape_project.pw.idp.excpetions.UserNotFoundException;
import eu.scape_project.pw.idp.model.IdpRole;
import eu.scape_project.pw.idp.model.IdpUser;
import eu.scape_project.pw.idp.model.IdpUserState;
import eu.scape_project.pw.idp.utils.ConfigurationLoader;

/**
 * Class responsible for managing users in the identity provider.
 */
@Stateless
public class UserManager {

    /**
     * Entity manager.
     */
    @Inject
    private EntityManager em;

    /**
     * Logger for this class.
     */
    @Inject
    private Logger log;

    @Inject
    private ConfigurationLoader configurationLoader;

    /**
     * Standard role name for a user.
     */
    private static final String STANDARD_ROLE_NAME = "authenticated";

    /**
     * Properties for activation mail.
     */
    private Configuration config;

    /**
     * Init this class.
     */
    @PostConstruct
    public void init() {
        config = configurationLoader.load();
    }

    /**
     * Adds a new user. Adds the standard role to the use. If the standard role
     * does not exist, creates it.
     * 
     * @param user
     *            User to add.
     */
    public void addUser(IdpUser user) {
        // Set standard role

        IdpRole role = null;
        List<IdpRole> standardRoles = em
                .createQuery("SELECT r from IdpRole r WHERE rolename = :rolename", IdpRole.class)
                .setParameter("rolename", STANDARD_ROLE_NAME).getResultList();
        if (standardRoles.size() == 1) {
            role = standardRoles.get(0);
        } else {
            role = new IdpRole();
            role.setRoleName(STANDARD_ROLE_NAME);
            em.persist(role);
            log.warn("Standard role not found, added standard role {}.", STANDARD_ROLE_NAME);
        }

        List<IdpRole> roles = user.getRoles();
        roles.add(role);

        // Create a user actionToken which is needed for activation
        user.setActionToken(UUID.randomUUID().toString());
        user.setStatus(IdpUserState.CREATED);

        em.persist(user);
        log.info("Added user with username {}.", user.getUsername());
    }

    /**
     * Activates an existing user.
     * 
     * @param user
     *            the user to activate
     * @throws UserNotFoundException
     *             if the user could not be found
     */
    public void activateUser(IdpUser user) throws UserNotFoundException {
        IdpUser foundUser = em.find(IdpUser.class, user.getId());
        if (foundUser == null) {
            log.error("Error activating user. User {} not found.", user.getUsername());
            throw new UserNotFoundException("Error activating user. User " + user.getUsername() + "not found.");
        }
        foundUser.setStatus(IdpUserState.ACTIVE);
        foundUser.setActionToken("");
        em.persist(foundUser);
        log.info("Activated user with username {}.", foundUser.getUsername());
    }

    /**
     * Method responsible for sending a email to the user, including a link to
     * activate his user account.
     * 
     * @param user
     *            User the activation mail should be sent to
     * @param serverString
     *            Name and port of the server the user was added.
     * @throws CannotSendMailException
     *             if the mail could not be sent
     */
    public void sendActivationMail(IdpUser user, String serverString) throws CannotSendMailException {

        try {
            Properties props = System.getProperties();

            props.put("mail.smtp.host", config.getString("mail.smtp.host"));
            Session session = Session.getDefaultInstance(props, null);

            MimeMessage message = new MimeMessage(session);
            message.setFrom(new InternetAddress(config.getString("mail.from")));
            message.setRecipient(RecipientType.TO, new InternetAddress(user.getEmail()));
            message.setSubject("Please confirm your Planningsuite user account");

            StringBuilder builder = new StringBuilder();
            builder.append("Dear " + user.getFirstName() + " " + user.getLastName() + ", \n\n");
            builder.append("Please use the following link to confirm your Planningsuite user account: \n");
            builder.append("http://" + serverString + "/idp/activateUser.jsf?uid=" + user.getActionToken());
            builder.append("\n\n--\n");
            builder.append("Your Planningsuite team");

            message.setText(builder.toString());
            message.saveChanges();

            Transport.send(message);
            log.debug("Activation mail sent successfully to {}", user.getEmail());
        } catch (Exception e) {
            log.error("Error at sending activation mail to {}", user.getEmail());
            throw new CannotSendMailException("Error at sending activation mail to " + user.getEmail(), e);
        }
    }

    /**
     * Initiates password reset for the user.
     * 
     * @param user
     *            the user
     */
    public void initiateResetPassword(IdpUser user) {
        user.setActionToken(UUID.randomUUID().toString());
        em.persist(em.merge(user));
        log.info("Set action token for password reset mail for user {}", user.getUsername());
    }

    /**
     * Sends the user a link to reset the password.
     * 
     * @param user
     *            the user
     * @param serverString
     *            host and port of the server
     * @throws CannotSendMailException
     *             if the password reset mail could not be sent
     */
    public void sendPasswordResetMail(IdpUser user, String serverString) throws CannotSendMailException {
        try {
            Properties props = System.getProperties();

            props.put("mail.smtp.host", config.getString("mail.smtp.host"));
            Session session = Session.getDefaultInstance(props, null);

            MimeMessage message = new MimeMessage(session);
            message.setFrom(new InternetAddress(config.getString("mail.from")));
            message.setRecipient(RecipientType.TO, new InternetAddress(user.getEmail()));
            message.setSubject("Planningsuite password recovery");

            StringBuilder builder = new StringBuilder();
            builder.append("Dear " + user.getFirstName() + " " + user.getLastName() + ", \n\n");
            builder.append("You have requested help recovering the password for the Plato user ");
            builder.append(user.getUsername()).append(".\n\n");
            builder.append("Please use the following link to reset your Planningsuite password: \n");
            builder.append("http://" + serverString + "/idp/resetPassword.jsf?uid=" + user.getActionToken());
            builder.append("\n\n--\n");
            builder.append("Your Planningsuite team");

            message.setText(builder.toString());
            message.saveChanges();

            Transport.send(message);
            log.debug("Sent password reset mail to " + user.getEmail());

        } catch (Exception e) {
            log.error("Error at sending password reset mail to {}", user.getEmail());
            throw new CannotSendMailException("Error at sending password reset mail to " + user.getEmail());
        }
    }

    /**
     * Resets the password of the user identified by the actionToken.
     * 
     * @param user
     *            the user
     * @throws UserNotFoundException
     *             if the user could not be found
     */
    public void resetPassword(IdpUser user) throws UserNotFoundException {

        // We have to find the user because if we use em.merge(user)
        // user.plainPassword will be deleted (because it is transient).
        IdpUser foundUser = em.find(IdpUser.class, user.getId());
        if (foundUser == null) {
            log.error("Error resetting password. User not found {}.", user.getUsername());
            throw new UserNotFoundException("Error resetting password. User not found " + user.getUsername());
        }
        foundUser.setPlainPassword(user.getPlainPassword());
        foundUser.setActionToken("");
        foundUser.setStatus(IdpUserState.ACTIVE);
        em.persist(foundUser);

        log.info("Reset password for user " + user.getUsername());
    }

    /**
     * Reads the user identified by the provided action token.
     * 
     * @param actionToken
     *            the action token identifying the user
     * @return the user
     * @throws UserNotFoundException
     *             if no user could be found
     */
    public IdpUser getUserByActionToken(String actionToken) throws UserNotFoundException {
        List<IdpUser> matchingUsers = em
                .createQuery("SELECT u FROM IdpUser u WHERE u.actionToken = :actionToken", IdpUser.class)
                .setParameter("actionToken", actionToken).getResultList();

        if (matchingUsers.size() != 1) {
            log.error("{} users matching given actionToken {}", matchingUsers.size(), actionToken);
            throw new UserNotFoundException(
                    matchingUsers.size() + " users matching given actionToken " + actionToken);
        }

        return matchingUsers.get(0);
    }

    /**
     * Reads the user identified by the provided identifier.
     * 
     * @param userIdentifier
     *            the identifier identifying the user
     * @return the user
     * @throws UserNotFoundException
     *             if no user could be found
     */
    public IdpUser getUserByIdentifier(String userIdentifier) throws UserNotFoundException {
        List<IdpUser> matchingUsers = em.createQuery(
                "SELECT u FROM IdpUser u WHERE u.username = :userIdentifier OR u.email = :userIdentifier",
                IdpUser.class).setParameter("userIdentifier", userIdentifier).getResultList();

        if (matchingUsers.size() != 1) {
            log.error("{} users matching given identifier {}", matchingUsers.size(), userIdentifier);
            throw new UserNotFoundException(
                    matchingUsers.size() + " users matching given identifier " + userIdentifier);
        }

        return matchingUsers.get(0);
    }

    // ---------- getter/setter ----------

    // Method used to make this class Unit-testable
    protected void setEntityManager(EntityManager em) {
        this.em = em;
    }

    // Method used to make this class Unit-testable
    protected void setLog(Logger log) {
        this.log = log;
    }
}