com.mirth.connect.server.controllers.DefaultUserController.java Source code

Java tutorial

Introduction

Here is the source code for com.mirth.connect.server.controllers.DefaultUserController.java

Source

/*
 * Copyright (c) Mirth Corporation. All rights reserved.
 * 
 * http://www.mirthcorp.com
 * 
 * The software in this package is published under the terms of the MPL license a copy of which has
 * been included with this distribution in the LICENSE.txt file.
 */

package com.mirth.connect.server.controllers;

import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.log4j.Logger;

import com.mirth.commons.encryption.Digester;
import com.mirth.connect.client.core.ControllerException;
import com.mirth.connect.model.Credentials;
import com.mirth.connect.model.LoginStatus;
import com.mirth.connect.model.PasswordRequirements;
import com.mirth.connect.model.User;
import com.mirth.connect.server.ExtensionLoader;
import com.mirth.connect.server.mybatis.KeyValuePair;
import com.mirth.connect.server.util.DatabaseUtil;
import com.mirth.connect.server.util.LoginRequirementsChecker;
import com.mirth.connect.server.util.PasswordRequirementsChecker;
import com.mirth.connect.server.util.Pre22PasswordChecker;
import com.mirth.connect.server.util.SqlConfig;

public class DefaultUserController extends UserController {
    private Logger logger = Logger.getLogger(this.getClass());
    private ExtensionController extensionController = null;

    private static UserController instance = null;

    private DefaultUserController() {

    }

    public static UserController create() {
        synchronized (DefaultUserController.class) {
            if (instance == null) {
                instance = ExtensionLoader.getInstance().getControllerInstance(UserController.class);

                if (instance == null) {
                    instance = new DefaultUserController();
                }
            }

            return instance;
        }
    }

    public void resetUserStatus() {
        try {
            SqlConfig.getSqlSessionManager().update("User.resetUserStatus");
        } catch (PersistenceException e) {
            logger.error("Could not reset user status.");
        }
    }

    public List<User> getAllUsers() throws ControllerException {
        logger.debug("getting all users");

        try {
            return SqlConfig.getSqlSessionManager().selectList("User.getUser");
        } catch (PersistenceException e) {
            throw new ControllerException(e);
        }
    }

    public User getUser(Integer userId, String userName) throws ControllerException {
        logger.debug("getting user: " + userId);

        if (userId == null && userName == null) {
            throw new ControllerException("Error getting user: Both user ID and user name cannot be null.");
        }

        try {
            User user = new User();
            user.setId(userId);
            user.setUsername(userName);
            return SqlConfig.getSqlSessionManager().selectOne("User.getUser", user);
        } catch (PersistenceException e) {
            throw new ControllerException(e);
        }
    }

    public synchronized void updateUser(User user) throws ControllerException {
        try {
            User existingUser = getUser(null, user.getUsername());

            if (user.getId() == null) {
                if (existingUser != null) {
                    throw new ControllerException("Error adding user: username must be unique");
                }

                logger.debug("adding user: " + user);
                SqlConfig.getSqlSessionManager().insert("User.insertUser", getUserMap(user));
            } else {
                if (existingUser != null && !user.getId().equals(existingUser.getId())) {
                    throw new ControllerException("Error updating user: username must be unique");
                }

                logger.debug("updating user: " + user);
                SqlConfig.getSqlSessionManager().update("User.updateUser", getUserMap(user));
            }
        } catch (PersistenceException e) {
            throw new ControllerException(e);
        }
    }

    public List<String> checkOrUpdateUserPassword(Integer userId, String plainPassword) throws ControllerException {
        try {
            Digester digester = ControllerFactory.getFactory().createConfigurationController().getDigester();
            PasswordRequirements passwordRequirements = ControllerFactory.getFactory()
                    .createConfigurationController().getPasswordRequirements();
            List<String> responses = PasswordRequirementsChecker.getInstance().doesPasswordMeetRequirements(userId,
                    plainPassword, passwordRequirements);
            if (responses != null) {
                return responses;
            }

            /*
             * If no userId was passed in, stop here and don't try to add the password.
             */
            if (userId == null) {
                return null;
            }

            logger.debug("updating password for user id: " + userId);

            Calendar pruneDate = PasswordRequirementsChecker.getInstance()
                    .getLastExpirationDate(passwordRequirements);

            // If a null prune date is returned, do not prune
            if (pruneDate != null) {
                Map<String, Object> userDateMap = new HashMap<String, Object>();
                userDateMap.put("id", userId);
                userDateMap.put("pruneDate", pruneDate);

                try {
                    SqlConfig.getSqlSessionManager().delete("User.prunePasswords", userDateMap);
                } catch (Exception e) {
                    // Don't abort changing the password if pruning fails.
                    logger.error("There was an error pruning passwords for user id: " + userId, e);
                }
            }

            Map<String, Object> userPasswordMap = new HashMap<String, Object>();
            userPasswordMap.put("id", userId);
            userPasswordMap.put("password", digester.digest(plainPassword));
            userPasswordMap.put("passwordDate", Calendar.getInstance());
            SqlConfig.getSqlSessionManager().insert("User.updateUserPassword", userPasswordMap);
            SqlConfig.getSqlSessionManager().update("User.clearGracePeriod", userId);

            return null;
        } catch (PersistenceException e) {
            throw new ControllerException(e);
        }
    }

    public synchronized void removeUser(Integer userId, Integer currentUserId) throws ControllerException {
        logger.debug("removing user: " + userId);

        if (userId == null) {
            throw new ControllerException("Error removing user: User Id cannot be null");
        }

        if (userId.equals(currentUserId)) {
            throw new ControllerException("Error removing user: You cannot remove yourself");
        }

        try {
            User user = new User();
            user.setId(userId);
            SqlConfig.getSqlSessionManager().delete("User.deleteUser", user);

            if (DatabaseUtil.statementExists("User.vacuumPersonTable")) {
                SqlConfig.getSqlSessionManager().update("User.vacuumPersonTable");
            }
        } catch (PersistenceException e) {
            throw new ControllerException(e);
        }
    }

    public LoginStatus authorizeUser(String username, String plainPassword) throws ControllerException {
        try {
            // Invoke and return from the Authorization Plugin if one exists
            if (extensionController == null) {
                extensionController = ControllerFactory.getFactory().createExtensionController();
            }

            if (extensionController.getAuthorizationPlugin() != null) {
                LoginStatus loginStatus = extensionController.getAuthorizationPlugin().authorizeUser(username,
                        plainPassword);

                /*
                 * A null return value indicates that the authorization plugin is disabled or is
                 * otherwise delegating control back to the UserController to perform
                 * authentication.
                 */
                if (loginStatus != null) {
                    return loginStatus;
                }
            }

            Digester digester = ControllerFactory.getFactory().createConfigurationController().getDigester();
            LoginRequirementsChecker loginRequirementsChecker = new LoginRequirementsChecker(username);
            if (loginRequirementsChecker.isUserLockedOut()) {
                return new LoginStatus(LoginStatus.Status.FAIL_LOCKED_OUT,
                        "User account \"" + username + "\" has been locked. You may attempt to login again in "
                                + loginRequirementsChecker.getPrintableStrikeTimeRemaining() + ".");
            }

            loginRequirementsChecker.resetExpiredStrikes();
            boolean authorized = false;

            // Validate the user
            User validUser = getUser(null, username);
            Credentials credentials = null;

            if (validUser != null) {
                credentials = (Credentials) SqlConfig.getSqlSessionManager()
                        .selectOne("User.getLatestUserCredentials", validUser.getId());

                if (credentials != null) {
                    if (Pre22PasswordChecker.isPre22Hash(credentials.getPassword())) {
                        if (Pre22PasswordChecker.checkPassword(plainPassword, credentials.getPassword())) {
                            checkOrUpdateUserPassword(validUser.getId(), plainPassword);
                            authorized = true;
                        }
                    } else {
                        authorized = digester.matches(plainPassword, credentials.getPassword());
                    }
                }
            }

            PasswordRequirements passwordRequirements = ControllerFactory.getFactory()
                    .createConfigurationController().getPasswordRequirements();
            LoginStatus loginStatus = null;

            if (authorized) {
                loginRequirementsChecker.resetStrikes();

                // If password expiration is enabled, do checks now
                if (passwordRequirements.getExpiration() > 0) {
                    long passwordTime = credentials.getPasswordDate().getTimeInMillis();
                    long currentTime = System.currentTimeMillis();

                    // If the password is expired, do grace period checks
                    if (loginRequirementsChecker.isPasswordExpired(passwordTime, currentTime)) {
                        // Let 0 be infinite grace period, -1 be no grace period
                        if (passwordRequirements.getGracePeriod() == 0) {
                            loginStatus = new LoginStatus(LoginStatus.Status.SUCCESS_GRACE_PERIOD,
                                    "Your password has expired. Please change your password now.");
                        } else if (passwordRequirements.getGracePeriod() > 0) {
                            // If there has never been a grace time, start it now
                            long gracePeriodStartTime;
                            if (validUser.getGracePeriodStart() == null) {
                                gracePeriodStartTime = currentTime;

                                Map<String, Object> gracePeriodMap = new HashMap<String, Object>();
                                gracePeriodMap.put("id", validUser.getId());
                                gracePeriodMap.put("gracePeriodStart", Calendar.getInstance());

                                SqlConfig.getSqlSessionManager().update("User.startGracePeriod", gracePeriodMap);
                            } else {
                                gracePeriodStartTime = validUser.getGracePeriodStart().getTimeInMillis();
                            }

                            long graceTimeRemaining = loginRequirementsChecker
                                    .getGraceTimeRemaining(gracePeriodStartTime, currentTime);
                            if (graceTimeRemaining > 0) {
                                loginStatus = new LoginStatus(LoginStatus.Status.SUCCESS_GRACE_PERIOD,
                                        "Your password has expired. You are required to change your password in the next "
                                                + loginRequirementsChecker
                                                        .getPrintableGraceTimeRemaining(graceTimeRemaining)
                                                + ".");
                            }
                        }

                        // If there is no grace period or it has passed, FAIL_EXPIRED
                        if (loginStatus == null) {
                            loginStatus = new LoginStatus(LoginStatus.Status.FAIL_EXPIRED,
                                    "Your password has expired. Please contact an administrator to have your password reset.");
                        }

                        /*
                         * Reset the user's grace period if it isn't being used but one was
                         * previously set. This should only happen if a user is in a grace period
                         * before grace periods are disabled.
                         */
                        if ((passwordRequirements.getGracePeriod() <= 0)
                                && (validUser.getGracePeriodStart() != null)) {
                            SqlConfig.getSqlSessionManager().update("User.clearGracePeriod", validUser.getId());
                        }
                    }
                }
                // End of password expiration and grace period checks

                // If nothing failed (loginStatus != null), set SUCCESS now
                if (loginStatus == null) {
                    loginStatus = new LoginStatus(LoginStatus.Status.SUCCESS, "");

                    // Clear the user's grace period if one exists
                    if (validUser.getGracePeriodStart() != null) {
                        SqlConfig.getSqlSessionManager().update("User.clearGracePeriod", validUser.getId());
                    }
                }
            } else {
                loginRequirementsChecker.incrementStrikes();
                String failMessage = "Incorrect username or password.";
                if (loginRequirementsChecker.isLockoutEnabled()) {
                    failMessage += " " + loginRequirementsChecker.getStrikesRemaining()
                            + " login attempt(s) remaining for \"" + username
                            + "\" until the account is locked for "
                            + loginRequirementsChecker.getPrintableLockoutPeriod() + ".";
                }
                loginStatus = new LoginStatus(LoginStatus.Status.FAIL, failMessage);
            }

            return loginStatus;
        } catch (Exception e) {
            throw new ControllerException(e);
        }
    }

    public boolean checkPassword(String plainPassword, String encryptedPassword) {
        Digester digester = ControllerFactory.getFactory().createConfigurationController().getDigester();
        return digester.matches(plainPassword, encryptedPassword);
    }

    public void loginUser(User user) throws ControllerException {
        try {
            Map<String, Object> params = new HashMap<String, Object>();
            params.put("id", user.getId());
            params.put("lastLogin", Calendar.getInstance());

            SqlConfig.getSqlSessionManager().update("User.loginUser", params);
        } catch (Exception e) {
            throw new ControllerException(e);
        }
    }

    public void logoutUser(User user) throws ControllerException {
        try {
            SqlConfig.getSqlSessionManager().update("User.logoutUser", user.getId());
        } catch (Exception e) {
            throw new ControllerException(e);
        }

    }

    public boolean isUserLoggedIn(Integer userId) throws ControllerException {
        try {
            return (Boolean) SqlConfig.getSqlSessionManager().selectOne("User.isUserLoggedIn", userId);
        } catch (Exception e) {
            throw new ControllerException(e);
        }
    }

    private Map<String, Object> getUserMap(User user) {
        Map<String, Object> parameterMap = new HashMap<String, Object>();

        if (user.getId() != null) {
            parameterMap.put("id", user.getId());
        }

        parameterMap.put("username", user.getUsername());
        parameterMap.put("firstName", user.getFirstName());
        parameterMap.put("lastName", user.getLastName());
        parameterMap.put("organization", user.getOrganization());
        parameterMap.put("industry", user.getIndustry());
        parameterMap.put("email", user.getEmail());
        parameterMap.put("phoneNumber", user.getPhoneNumber());
        parameterMap.put("description", user.getDescription());
        return parameterMap;
    }

    @Override
    public List<Credentials> getUserCredentials(Integer userId) throws ControllerException {
        try {
            return SqlConfig.getSqlSessionManager().selectList("User.getUserCredentials", userId);
        } catch (Exception e) {
            throw new ControllerException(e);
        }
    }

    @Override
    public void setUserPreferences(Integer userId, Properties properties) throws ControllerException {
        for (String property : properties.stringPropertyNames()) {
            setUserPreference(userId, property, properties.getProperty(property));
        }
    }

    @Override
    public void setUserPreference(Integer userId, String name, String value) {
        logger.debug("storing preference: user id=" + userId + ", name=" + name);

        try {
            Map<String, Object> parameterMap = new HashMap<String, Object>();
            parameterMap.put("person_id", userId);
            parameterMap.put("name", name);
            parameterMap.put("value", value);

            if (getUserPreference(userId, name) == null) {
                SqlConfig.getSqlSessionManager().insert("User.insertPreference", parameterMap);
            } else {
                SqlConfig.getSqlSessionManager().insert("User.updatePreference", parameterMap);
            }

            if (DatabaseUtil.statementExists("User.vacuumPersonPreferencesTable")) {
                SqlConfig.getSqlSessionManager().update("User.vacuumPersonPreferencesTable");
            }
        } catch (Exception e) {
            logger.error("Could not store preference: user id=" + userId + ", name=" + name, e);
        }
    }

    @Override
    public Properties getUserPreferences(Integer userId, Set<String> names) {
        logger.debug("retrieving preferences: user id=" + userId);
        Properties properties = new Properties();

        try {
            List<KeyValuePair> result = SqlConfig.getSqlSessionManager().selectList("User.selectPreferencesForUser",
                    userId);

            for (KeyValuePair pair : result) {
                if (CollectionUtils.isEmpty(names) || names.contains(pair.getKey())) {
                    properties.setProperty(pair.getKey(), StringUtils.defaultString(pair.getValue()));
                }
            }
        } catch (Exception e) {
            logger.error("Could not retrieve preferences: user id=" + userId, e);
        }

        return properties;
    }

    @Override
    public String getUserPreference(Integer userId, String name) {
        logger.debug("retrieving preference: user id=" + userId + ", name=" + name);

        try {
            Map<String, Object> parameterMap = new HashMap<String, Object>();
            parameterMap.put("person_id", userId);
            parameterMap.put("name", name);
            return (String) SqlConfig.getSqlSessionManager().selectOne("User.selectPreference", parameterMap);
        } catch (Exception e) {
            logger.warn("Could not retrieve preference: user id=" + userId + ", name=" + name, e);
        }

        return null;
    }

    public void removePreferencesForUser(int id) {
        logger.debug("deleting all preferences: user id=" + id);

        try {
            Map<String, Object> parameterMap = new HashMap<String, Object>();
            parameterMap.put("person_id", id);
            SqlConfig.getSqlSessionManager().delete("User.deletePreference", parameterMap);
        } catch (Exception e) {
            logger.error("Could not delete preferences: user id=" + id);
        }
    }

    @Override
    public void removePreference(int id, String name) {
        logger.debug("deleting preference: user id=" + id + ", name=" + name);

        try {
            Map<String, Object> parameterMap = new HashMap<String, Object>();
            parameterMap.put("category", id);
            parameterMap.put("name", name);
            SqlConfig.getSqlSessionManager().delete("User.deletePreference", parameterMap);
        } catch (Exception e) {
            logger.error("Could not delete preference: user id=" + id + ", name=" + name, e);
        }
    }
}