com.formkiq.core.service.UserServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.formkiq.core.service.UserServiceImpl.java

Source

/*
 * Copyright (C) 2016 FormKiQ Inc.
 *
 * 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 com.formkiq.core.service;

import static com.formkiq.core.domain.type.UserStatus.ACTIVE;
import static com.formkiq.core.domain.type.UserStatus.INVITE;

import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.validator.routines.EmailValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.formkiq.core.dao.FolderDao;
import com.formkiq.core.dao.UserDao;
import com.formkiq.core.domain.Folder;
import com.formkiq.core.domain.FolderAccess;
import com.formkiq.core.domain.User;
import com.formkiq.core.domain.UserSetting;
import com.formkiq.core.domain.type.FolderPermission;
import com.formkiq.core.domain.type.FolderStatus;
import com.formkiq.core.domain.type.UserDTO;
import com.formkiq.core.domain.type.UserListDTO;
import com.formkiq.core.domain.type.UserNotificationListDTO;
import com.formkiq.core.domain.type.UserRole;
import com.formkiq.core.domain.type.UserSettings;
import com.formkiq.core.domain.type.UserStatus;
import com.formkiq.core.form.dto.NotificationMethod;
import com.formkiq.core.form.dto.Workflow;
import com.formkiq.core.util.DateService;
import com.formkiq.core.util.Strings;

/**
 * UserService Implementation.
 *
 */
public class UserServiceImpl implements UserService {

    /** User Disabled Message. */
    private static final String DISABLED_MESSAGE = "Authentication " + "failed. User account is disabled.";

    /** Default User Token expiry time. */
    private static final int DEFAULT_EXPIRY_MINUTES = 24 * 60;

    /** DateService. */
    @Autowired
    private DateService dateservice;

    /** FolderDao. */
    @Autowired
    private FolderDao folderDao;

    /** PasswordEncoder. */
    @Autowired
    private PasswordEncoder passwordEncoder;

    /** SpringSecurityService. */
    @Autowired
    private SpringSecurityService securityService;

    /** SystemPropertyService. */
    @Autowired
    private SystemPropertyService systemPropertyService;

    /** UserDao. */
    @Autowired
    private UserDao userDao;

    /**
     * default constructor.
     */
    public UserServiceImpl() {
    }

    @Override
    public User createUser(final String clientid, final String email, final String password,
            final UserStatus status, final UserRole role, final String loginToken)
            throws PreconditionFailedException {

        if (!this.securityService.isAdmin()) {

            if (this.systemPropertyService.isInviteOnly() && !UserStatus.INVITE.equals(status)) {
                throw new PreconditionFailedException("User can only be created via invite");
            }
        }

        if (!EmailValidator.getInstance().isValid(email)) {
            throw new PreconditionFailedException("Invalid Email " + email);
        }

        if (StringUtils.isEmpty(password)) {
            throw new PreconditionFailedException("Password required");
        }

        if (status == null) {
            throw new PreconditionFailedException("UserStatus required");
        }

        if (role == null) {
            throw new PreconditionFailedException("UserRole required");
        }

        if (this.userDao.findUser(email) != null) {
            throw new PreconditionFailedException("Email already registered");
        }

        User user = new User();
        user.setClientid(clientid);
        user.setEmail(email);
        user.setStatus(status);
        user.setRole(role);
        setUserPassword(user, password);
        setUserLoginToken(user, loginToken);

        user = this.userDao.saveUser(user);

        return user;
    }

    @Override
    public void deleteUser(final String email) {

        if (!StringUtils.isEmpty(email)) {

            User user = this.userDao.findUser(email);
            if (user != null) {

                if (!(UserRole.ROLE_ADMIN.equals(user.getRole()) && this.userDao.getAdminUserCount() == 1)) {
                    this.userDao.deleteUser(user);
                } else {
                    throw new PreconditionFailedException("Cannot delete, only admin");
                }

            } else {
                throw new PreconditionFailedException("Email " + email + " not found");
            }

        } else {

            throw new PreconditionFailedException("Invalid Email");
        }
    }

    @Override
    public void deleteUserNotification(final String email, final String uuid) {

        User user = this.userDao.findUser(email);

        this.userDao.deleteNotification(user, uuid);
    }

    @Override
    public void deleteUserSettings(final String email, final UserSettings setting) {

        User user = this.userDao.findUser(email);

        if (user != null) {

            UserSetting us = this.userDao.findUserSetting(user, setting);

            if (us != null) {

                this.userDao.deleteUserSetting(us);

            } else {

                throw new PreconditionFailedException("Setting not found");
            }

        } else {

            throw new PreconditionFailedException("User not found");
        }

    }

    @Override
    public UserDetails findActiveUser(final String email, final String password)
            throws AuthenticationFailureException {

        boolean matched = false;
        User user = null;

        if (!StringUtils.isEmpty(email) && !StringUtils.isEmpty(password)) {

            try {
                user = findActiveUserByEmail(email);

                matched = isMatch(password, user.getPassword());

                if (!matched && password.startsWith("Basic")) {
                    user = findActiveUserByLoginToken(email, password);
                }

            } catch (AuthenticationFailureException e) {

                if (password.startsWith("Basic")) {
                    user = findActiveUserByLoginToken(email, password);
                    matched = true;
                } else {
                    throw e;
                }
            }

            if (!matched) {
                user = null;
            }
        }

        if (user == null) {
            throw new AuthenticationFailureException("Authentication failed. " + "Please verify your email address "
                    + "and password and try again.");
        }

        return user;
    }

    /**
      * Find Active User.
      * @param email {@link String}
      * @return {@link User}
      */
    @Override
    public User findActiveUserByEmail(final String email) {

        User user = this.userDao.findUser(email);
        return verifyUserActive(user);
    }

    /**
     * Finds Active User by Login Token.
     * @param loginToken {@link String}
     * @param password {@link String}
     * @return {@link User}
     */
    private User findActiveUserByLoginToken(final String loginToken, final String password) {

        String clientid = null;
        String s = password.replaceAll("Basic ", "");
        String[] decode = Strings.decode(s, ":");

        if (decode.length == 2) {
            clientid = decode[0];
        }

        User user = this.userDao.findUserByLoginToken(clientid, loginToken);
        return verifyUserActive(user);
    }

    @Override
    public UserNotificationListDTO findNotifications(final String email, final String token) {

        User user = this.userDao.findUser(email);

        if (user != null) {
            return this.userDao.findNotifications(user, token);
        }

        throw new PreconditionFailedException("User not found");
    }

    @Override
    public UserDTO findUser(final String email, final boolean includePassword)
            throws AuthenticationFailureException {

        UserDTO user = null;

        if (!StringUtils.isEmpty(email)) {

            user = this.userDao.findUserDTO(email);

            if (user != null && !includePassword) {
                user.setPassword(null);
            }
        }

        if (user == null) {
            throw new AuthenticationFailureException("Authentication failed. " + "Please verify your email address "
                    + "and password and try again.");
        }

        return user;
    }

    /**
      * Find User.
      * @param email {@link String}
      * @return {@link User}
      */
    @Override
    public UserDetails findUserByEmail(final String email) {
        return this.userDao.findUser(email);
    }

    @Override
    public UserListDTO findUsers(final String token, final String text) {
        return this.userDao.findUsers(token, text);
    }

    /**
    * Generate secured Password Hash.
    * @param password String
    * @return {@link String}
    */
    String generatedSecuredPasswordHash(final String password) {

        String securedPasswordHash = this.passwordEncoder.encode(password);
        return securedPasswordHash;
    }

    @Override
    public String generateResetToken(final String email) throws AuthenticationFailureException {

        User u = this.userDao.findUser(email);

        if (u != null && (ACTIVE.equals(u.getStatus()) || INVITE.equals(u.getStatus()))) {

            String token = generateSecurityToken();
            String securedTokenHash = generatedSecuredPasswordHash(token);

            Date now = this.dateservice.now();

            u.setResetToken(securedTokenHash);
            u.setResetInsertedDate(now);
            u.setUpdatedDate(now);
            this.userDao.saveUser(u);

            return token;
        }

        throw new AuthenticationFailureException(DISABLED_MESSAGE);
    }

    @Override
    public String generateSecurityToken() {

        String securityToken = UUID.randomUUID().toString().replaceAll("-", "");
        return securityToken;
    }

    /**
    * Gets the User Reset Token expiry in minutes.
    * @return int
    */
    protected int getUserTokenExpiryInMinutes() {
        return DEFAULT_EXPIRY_MINUTES;
    }

    /**
     * Checks password match.
     * @param rawPassword String
     * @param encodedPassword String
     * @return boolean
     */
    private boolean isMatch(final String rawPassword, final String encodedPassword) {
        return this.passwordEncoder.matches(rawPassword, encodedPassword);
    }

    @Override
    public void saveNotification(final String email, final String folder, final Workflow workflow,
            final NotificationMethod type) throws JsonProcessingException {

        User user = this.userDao.findUser(email);

        if (user != null) {

            this.userDao.saveUserNotification(user, folder, workflow, type);

        } else {
            throw new PreconditionFailedException("User not found");
        }
    }

    @Override
    public User saveUser(final String clientid, final String email, final String password, final UserRole role,
            final UserStatus status, final String loginToken) {

        User user = this.userDao.findUser(email);

        if (user != null) {

            if (role != null) {
                user.setRole(role);
            }

            if (status != null) {
                user.setStatus(status);

                if (UserStatus.DELETED.equals(status) || UserStatus.DISABLE.equals(status)) {
                    this.userDao.deleteUserAccessToken(user.getEmail());
                }
            }

            setUserPassword(user, password);
            setUserLoginToken(user, loginToken);

            user = this.userDao.saveUser(user);

        } else {

            user = createUser(clientid, email, password, status, role, loginToken);
        }

        return user;
    }

    @Override
    public void saveUserSettings(final String email, final UserSettings setting, final String value) {

        User user = this.userDao.findUser(email);

        if (user != null) {

            UserSetting us = this.userDao.findUserSetting(user, setting);

            if (us == null) {

                us = new UserSetting();
                us.setUserid(user.getUserid());
                us.setSetting(setting);
            }

            us.setValue(value);
            this.userDao.saveUserSetting(us);

        } else {

            throw new PreconditionFailedException("User not found");
        }
    }

    /**
     * Encrypts the User Login Token and set it into the object.
     * @param user User
     * @param loginToken unencrypted login token
     */
    private void setUserLoginToken(final User user, final String loginToken) {

        if (!StringUtils.isEmpty(loginToken)) {
            user.setLoginToken(loginToken);
        }
    }

    /**
     * Encrypts the User Password and set it into the object.
     * @param user User
     * @param password unencrypted password
     */
    private void setUserPassword(final User user, final String password) {

        if (!StringUtils.isEmpty(password)) {
            String securedPassHash = generatedSecuredPasswordHash(password);
            user.setPassword(securedPassHash);
        }
    }

    @Override
    public void shareFolderWithUser(final UserDetails ud, final String email, final String folderId,
            final List<FolderPermission> permissions) {

        User user = (User) ud;
        FolderAccess access = this.folderDao.findFolderAccess(user, folderId);

        if (this.securityService.hasPermission(access, FolderPermission.PERM_FORM_ADMIN)) {

            User inviteUser = this.userDao.findUser(email);

            if (inviteUser == null) {
                throw new PreconditionFailedException("User " + email + " does not exist");
            }

            FolderAccess fa = this.folderDao.findFolderAccess(inviteUser, folderId);

            if (fa == null || fa.getFolderaccessid() == null) {
                fa = new FolderAccess();
                fa.setStatus(FolderStatus.ACTIVE);
            }

            Folder folder = this.folderDao.findFolder(folderId);
            fa.setFolderid(folder.getFolderid());
            fa.setUserid(inviteUser.getUserid());
            fa.setPermissions(permissions);
            this.folderDao.saveFolderAccess(fa);

        } else {

            throw new FormAccessDeniedException();
        }
    }

    @Override
    public void updateLastLogin(final String email, final Date date) {
        this.userDao.updateLastLogin(email, date);
    }

    @Override
    public void updateLastUserAgent(final String email, final String useragent) {

        if (StringUtils.hasText(useragent)) {

            User user = (User) this.securityService.getUserDetails();
            if (!useragent.equals(user.getLastUserAgent())) {
                this.userDao.updateLastUserAgent(email, useragent);
            }
        }
    }

    @Override
    public void updatePassword(final String email, final String resettoken, final String newPassword) {

        boolean updated = false;

        if (!StringUtils.isEmpty(resettoken)) {

            User user = this.userDao.findUser(email);

            if (user != null) {

                if (isMatch(resettoken, user.getResetToken())) {

                    Date now = this.dateservice.now();
                    Date date = DateUtils.addMinutes(now, -getUserTokenExpiryInMinutes());

                    if (user.getResetInsertedDate().after(date)) {

                        user.setResetInsertedDate(null);
                        user.setResetToken(null);
                        updated = true;
                    }

                } else {

                    updated = isMatch(resettoken, user.getPassword());
                }

                if (updated) {

                    if (UserStatus.INVITE.equals(user.getStatus())) {
                        user.setStatus(UserStatus.ACTIVE);
                    }

                    setUserPassword(user, newPassword);

                    this.userDao.saveUser(user);
                }
            }
        }

        if (!updated) {
            throw new PreconditionFailedException("Invalid Old Password or Reset Token");
        }
    }

    /**
    * Checks to make sure User is Active.
    * @param user {@link User}
    * @return {@link User}
    */
    private User verifyUserActive(final User user) {

        if (user != null) {

            if (UserStatus.ACTIVE.equals(user.getStatus())) {
                return user;
            }

            throw new AuthenticationFailureException(DISABLED_MESSAGE);
        }

        throw new AuthenticationFailureException(
                "Authentication failed. " + "Please verify your email address " + "and password and try again.");
    }

    @Override
    public UserDetails findUser(final String userid) {
        return this.userDao.findUser(UUID.fromString(userid));
    }
}