alsutton/enterprisepasswordsafe

View on GitHub
src/main/java/com/enterprisepasswordsafe/ui/web/servlets/UserServlet.java

Summary

Maintainability
C
7 hrs
Test Coverage
F
0%
/*
 * Copyright (c) 2017 Carbon Security Ltd. <opensource@carbonsecurity.co.uk>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package com.enterprisepasswordsafe.ui.web.servlets;

import com.enterprisepasswordsafe.database.*;
import com.enterprisepasswordsafe.database.derived.AbstractUserSummary;
import com.enterprisepasswordsafe.database.derived.ImmutableUserSummary;
import com.enterprisepasswordsafe.engine.users.UserClassifier;
import com.enterprisepasswordsafe.engine.users.UserPriviledgeTransitioner;
import com.enterprisepasswordsafe.engine.utils.StringUtils;
import com.enterprisepasswordsafe.ui.web.EPSUIException;
import com.enterprisepasswordsafe.ui.web.utils.SecurityUtils;
import com.enterprisepasswordsafe.ui.web.utils.ServletUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Objects;

public final class UserServlet extends HttpServlet {

    public static final String USER_TYPE_ADMIN = "A",
                                USER_TYPE_SUBADMIN = "P",
                                USER_TYPE_NORMAL = "N";

    private static final String GROUP_MEMBERSHIP_PERAMETER_PREFIX = "group_";

    private static final String ZONE_RULE_PREFIX = "zone_";

    private static final int ZONE_RULE_PREFIX_LENGTH = ZONE_RULE_PREFIX.length();

    private final UserClassifier userClassifier;

    public UserServlet() {
        this(new UserClassifier());
    }

    public UserServlet(UserClassifier userClassifier) {
        this.userClassifier = userClassifier;
    }

    @Override
    public void doGet(final HttpServletRequest request, final HttpServletResponse response)
            throws ServletException, IOException {
        String userId = request.getParameter("userId");
        if (userId == null) {
            Object userIdObject = request.getAttribute("userId");
            if(userIdObject != null) {
                userId = userIdObject.toString();
            }
        }

        try {
            addDataNeededForEditPage(request);

            User user = null;
            if (userId != null) {
                user = addUserInformation(request, userId);
            }

            if(user == null) {
                request.setAttribute("current_auth_source",
                        AuthenticationSourceDAO.getInstance().getById(AuthenticationSource.DEFAULT_SOURCE_ID));
            }

            request.getRequestDispatcher("/admin/edit_user.jsp").forward(request, response);
        } catch(SQLException sqle) {
            throw new ServletException("The user details are unavailable due to an error.", sqle);
        }
    }

    /**
     * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */
    @Override
    protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
            throws IOException, ServletException{
        String csrfToken = request.getParameter("token");
        if(csrfToken == null || !csrfToken.equals(request.getSession(true).getAttribute("csrfToken"))) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);
            return;
        }

        try {
            User remoteUser = SecurityUtils.getRemoteUser(request);
            Group adminGroup = GroupDAO.getInstance().getAdminGroup(remoteUser);
            if(adminGroup == null) {
                response.sendError(HttpServletResponse.SC_FORBIDDEN);
                return;
            }

            try {
                validatePasswordFields(request);
            } catch(EPSUIException e) {
                ServletUtils.getInstance().generateErrorMessage(request, e.getMessage());
                addDataNeededForEditPage(request);
                request.getRequestDispatcher("/admin/edit_user.jsp").forward(request, response);
                return;
            }

            UserDAO uDAO = UserDAO.getInstance();
            ServletUtils servletUtils = ServletUtils.getInstance();

            String userId = request.getParameter("userId");
            boolean newUser = uDAO.getById(userId) == null;
            User user = getUser(request, remoteUser, adminGroup, userId);

            setUserPriviledgeLevel(request, remoteUser, adminGroup, user);
            String enabled = request.getParameter("user_enabled");
            if (enabled.equals("Y")) {
                if( ! user.isEnabled() ) {
                    uDAO.setFailedLogins(user, 0);
                }
                user.setEnabled(true);
            } else {
                user.setEnabled(false);
            }

            String forcePwdChange = request.getParameter("force_change_password");
            if( forcePwdChange != null && forcePwdChange.equals("Y") ) {
                user.forcePasswordChangeAtNextLogin();
            }

            uDAO.update(user);

            updateGroupMemberships(request, remoteUser, user);
            updateRestrictions(request, user);

            servletUtils.generateMessage(request, newUser ? "The profile has been created." :
                    "The profile has been updated.");
            response.sendRedirect(request.getContextPath()+"/admin/User?userId="+user.getId());
        } catch(Exception e) {
            throw new ServletException("There was a problem updating the user.", e);
        }
    }

    private User getUser(HttpServletRequest request, User remoteUser, Group adminGroup, String userId)
            throws SQLException, GeneralSecurityException, UnsupportedEncodingException {
        ServletUtils servletUtils = ServletUtils.getInstance();
        UserDAO uDAO = UserDAO.getInstance();
        User user = null;
        if(userId != null && !userId.isEmpty()) {
            user = uDAO.getById(userId);
        }
        if(user == null) {
            return uDAO.createUser( remoteUser,
                    ImmutableUserSummary.builder()
                        .name(servletUtils.getParameterValue(request, "username"))
                        .fullName(servletUtils.getParameterValue(request, BaseServlet.FULL_NAME_PARAMETER))
                        .build(),
                    servletUtils.getParameterValue(request, "password1"),
                    servletUtils.getParameterValue(request, BaseServlet.EMAIL_PARAMETER));
        }

        user.decryptAdminAccessKey(adminGroup);

        user.setFullName(servletUtils.getParameterValue(request, BaseServlet.FULL_NAME_PARAMETER));
        user.setEmail(servletUtils.getParameterValue(request, BaseServlet.EMAIL_PARAMETER));
        user.setAuthSource(servletUtils.getParameterValue(request, BaseServlet.AUTH_SOURCE_ATTRIBUTE));

        String newPassword = request.getParameter("password1");
        if(newPassword != null && !newPassword.isEmpty()) {
            user.decryptAdminAccessKey(adminGroup);
            uDAO.updatePassword(user, newPassword);
        }
        return user;
    }

    /**
     * Add the information to the HttpServletRequest which is needed to display the
     * user editing page.
     *
     * @param request The request being serviced.
     */

    private void addDataNeededForEditPage(final HttpServletRequest request)
        throws SQLException {
        request.setAttribute("auth_sources", AuthenticationSourceDAO.getInstance().getAll());
        request.setAttribute("groups", GroupDAO.getInstance().getNonSystem());
        request.setAttribute("restrictions", IPZoneDAO.getInstance().getAll());
    }

    /**
     * Add details about a specific user to the HttpServletRequest.
     *
     * @param request The request being serviced.
     * @param id The ID of the user whose details should be added to the response.
     */

    private User addUserInformation(final HttpServletRequest request, final String id)
        throws SQLException {
        User user = UserDAO.getInstance().getById(id);
        if(user == null) {
            return null;
        }

        Map<String, Object> memberships = MembershipDAO.getInstance().getMemberships(id);
        request.setAttribute("group_membership_map", memberships);
        request.setAttribute("restrictions_map", UserIPZoneRestrictionDAO.getInstance().getRulesForUser(id));
        request.setAttribute("user_level", userClassifier.getUserLevelFrom(memberships));
        request.setAttribute("non_viewing", userClassifier.isNonViewingUser(user));

        String authSourceId = (user.getAuthSource() == null) ? AuthenticationSource.DEFAULT_SOURCE_ID : user.getAuthSource();
        request.setAttribute("current_auth_source", AuthenticationSourceDAO.getInstance().getById(authSourceId));

        request.setAttribute("user", user);

        return user;
    }

    /**
     * Validate the values supplied in the password fields.
     *
     * @param request The request being serviced.
     */

    private void validatePasswordFields(final HttpServletRequest request)
        throws EPSUIException, SQLException {
        String password1 = request.getParameter("password1");
        String password2 = request.getParameter("password2");
        if ((password1 == null || password1.isEmpty())
        &&  (password2 == null || password2.isEmpty())) {
            return;
        }

        if ( StringUtils.isAnyEmpty(password1, password2) || !Objects.equals(password1, password2)) {
            throw new EPSUIException("The passwords you entered were not the same.");
        }

        PasswordRestriction control = PasswordRestrictionDAO.getInstance().getById(
                PasswordRestriction.LOGIN_PASSWORD_RESTRICTION_ID);
        if (control != null && !control.verify(password1)) {
            throw new EPSUIException(
                    "The users password has NOT been updated because it does not meet the following requirements; "
                            +control.toString());
        }

    }

    private void updateGroupMemberships(final HttpServletRequest request, final User remoteUser, final User user)
        throws SQLException, GeneralSecurityException, UnsupportedEncodingException {

        MembershipDAO mDAO = MembershipDAO.getInstance();
        for(Group group : GroupDAO.getInstance().getAll() ) {
            String groupId = group.getGroupId();
            String flag = request.getParameter(GROUP_MEMBERSHIP_PERAMETER_PREFIX+groupId);
            boolean membershipRequested = (flag != null && !flag.isEmpty());

            if(membershipRequested) {
                mDAO.create(remoteUser, user, groupId);
            } else {
                mDAO.delete(user, groupId);
            }
        }
    }

    private void updateRestrictions(final HttpServletRequest request, final User user)
        throws SQLException {
        String userId = user.getId();
        Enumeration<String> parameterNames = request.getParameterNames();
        while(parameterNames.hasMoreElements()) {
            String parameterName = parameterNames.nextElement();
            processParameter(request, userId, parameterName);
        }
    }

    private void processParameter(HttpServletRequest request, String userId, String parameterName) throws SQLException {
        if(!parameterName.startsWith(ZONE_RULE_PREFIX)) {
            return;
        }
        String zoneId = parameterName.substring(ZONE_RULE_PREFIX_LENGTH);
        String rule = request.getParameter(parameterName);

        UserIPZoneRestrictionDAO uipzrDAO = UserIPZoneRestrictionDAO.getInstance();
        UserIPZoneRestriction restriction = uipzrDAO.getByZoneAndUser(userId, zoneId);
        if( rule.equals(UserIPZoneRestriction.DEFAULT_STRING) ) {
            setAsDefault(uipzrDAO, restriction);
        } else {
            setRule(uipzrDAO, restriction, zoneId, userId, rule);
        }
    }

    private void setAsDefault(UserIPZoneRestrictionDAO uipzrDAO, UserIPZoneRestriction restriction)
            throws SQLException {
        if( restriction != null ) {
            uipzrDAO.delete(restriction);
        }
    }

    private void setRule(UserIPZoneRestrictionDAO uipzrDAO, UserIPZoneRestriction restriction,
                         String zoneId, String userId, String rule)
            throws SQLException {
        int ruleValue = UserIPZoneRestriction.DENY_INT;
        if( rule.equals(UserIPZoneRestriction.ALLOW_STRING) ) {
            ruleValue = UserIPZoneRestriction.ALLOW_INT;
        }

        if( restriction == null ) {
            uipzrDAO.create(zoneId, userId, ruleValue);
        } else {
            restriction.setRule(ruleValue);
            uipzrDAO.update(restriction);
        }
    }

    private void setUserPriviledgeLevel(final HttpServletRequest request, final User remoteUser,
                                        final Group adminGroup, final User user)
            throws GeneralSecurityException, SQLException, IOException {
        UserPriviledgeTransitioner userPriviledgeTransitioner = new UserPriviledgeTransitioner();
        switch(request.getParameter("user_type")) {
            case USER_TYPE_ADMIN:
                userPriviledgeTransitioner.makeAdmin(remoteUser, adminGroup, user);
                break;
            case USER_TYPE_SUBADMIN:
                userPriviledgeTransitioner.makeSubadmin(remoteUser, adminGroup, user);
                break;
            case USER_TYPE_NORMAL:
                userPriviledgeTransitioner.makeNormalUser(remoteUser, user);
                break;
        }

        String noView = request.getParameter("noview");
        userPriviledgeTransitioner.setNotViewing(user, noView != null && noView.equals("Y"));
    }

    @Override
    public String getServletInfo() {
        return "Obtains the information about a user to be edited.";
    }
}