alsutton/enterprisepasswordsafe

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

Summary

Maintainability
A
1 hr
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.HierarchyNodeChildren;
import com.enterprisepasswordsafe.database.derived.ImmutableHierarchyNodeChildren;
import com.enterprisepasswordsafe.engine.hierarchy.HierarchyTools;
import com.enterprisepasswordsafe.engine.users.UserClassifier;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.sql.SQLException;
import java.util.Comparator;


/**
 * Handles the user interacting with the password hierarchy.
 */

public final class Explorer extends HttpServlet {

    private static final String INCLUDE_EMPTY_ATTRIBUTE = "_include_empty";

    private final UserClassifier userClassifier = new UserClassifier();
    private final HierarchyTools hierarchyTools = new HierarchyTools();

    @Override
    protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
            throws ServletException, IOException {
        request.setAttribute("isInExplorer", Boolean.TRUE);

        User user = SecurityUtils.getRemoteUser(request);

        ServletUtils su = ServletUtils.getInstance();
        String nodeId = su.getNodeId(request);
        if(nodeId == null) {
            nodeId = HierarchyNode.ROOT_NODE_ID;
        }

        try {
            HierarchyNodeDAO hnDAO = HierarchyNodeDAO.getInstance();
            HierarchyNode node = getClosestValidNodeToRequested(request, user, nodeId);
            su.setCurrentNodeId(request, node.getNodeId());

            request.setAttribute(INCLUDE_EMPTY_ATTRIBUTE,
              ConfigurationDAO.getValue(ConfigurationOption.HIDE_EMPTY_FOLDERS).equals(Configuration.HIDE_EMPTY_FOLDERS_OFF));

            determineHierarchyEditability(request, user);

            request.setAttribute(BaseServlet.NODE, node);
            request.setAttribute(BaseServlet.NODE_PARENTAGE, hierarchyTools.getParentage(node));
            request.setAttribute(BaseServlet.NODE_CHILDREN, getVisibleChildren(request, user, node));
        } catch( GeneralSecurityException | SQLException e ) {
            throw new ServletException("The password explorer encountered an error.", e);
        }
        request.getRequestDispatcher("/system/view_subnodes.jsp").forward(request, response);
    }

    @Override
    public String getServletInfo() {
        return "Obtains and displays the information about a node in the hierarchy";
    }

    private HierarchyNode getClosestValidNodeToRequested(HttpServletRequest request, User user, String nodeId)
            throws SQLException, GeneralSecurityException {
        HierarchyNodeDAO hnDAO = HierarchyNodeDAO.getInstance();
        HierarchyNode node = hnDAO.getById(nodeId);
        if(node == null || node.getType() == HierarchyNode.USER_CONTAINER_NODE) {
            nodeId = HierarchyNode.ROOT_NODE_ID;
            node = hnDAO.getById(nodeId);
        }

        HierarchyNodeAccessRuleDAO hnarDAO = HierarchyNodeAccessRuleDAO.getInstance();
        if (userClassifier.isAdministrator(user)) {
            return node;
        }

        ServletUtils.getInstance().generateErrorMessage(request, "You are not allowed access to the folder "+
                "you requested. You have been diverted to a folder you can access.");
        for(HierarchyNode thisNode : hierarchyTools.getParentage(node)) {
            if(hnarDAO.getAccessibilityForUser(thisNode, user) != HierarchyNodeAccessRuleDAO.ACCESIBILITY_DENIED) {
                return thisNode;
            }
        }
        return hnDAO.getById(HierarchyNode.ROOT_NODE_ID);
    }

    private void determineHierarchyEditability(HttpServletRequest request, User user)
            throws SQLException {
        request.setAttribute("edithierarchy_allowed", "N");
        if(userClassifier.isNonViewingUser(user)) {
            return;
        }

        if            ( userClassifier.isAdministrator(user) ) {
            request.setAttribute("edithierarchy_allowed", "Y");
            return;
        }

        if    ( userClassifier.isSubadministrator(user) ){
            String displayEdit = ConfigurationDAO.getValue(ConfigurationOption.EDIT_USER_MINIMUM_USER_LEVEL);
            if( displayEdit != null &&     displayEdit.equals("S") ) {
                request.setAttribute("edithierarchy_allowed", "Y");
                request.setAttribute(INCLUDE_EMPTY_ATTRIBUTE, Boolean.TRUE);
            }
        }
    }

    private HierarchyNodeChildren getVisibleChildren(HttpServletRequest request, User user, HierarchyNode node)
            throws SQLException, GeneralSecurityException, UnsupportedEncodingException {
        String sortOrder = getSortOrder(request);
        Comparator<Password> objectComparator;
        if (sortOrder != null && sortOrder.startsWith("S")) {
            objectComparator = new SystemComparator();
        } else {
            objectComparator = new UsernameComparator();
        }

        HierarchyNodeDAO hnDAO = HierarchyNodeDAO.getInstance();
        HierarchyNodeChildren children =
                hierarchyTools.getChildrenValidForUser(node, user,
                        ((Boolean)request.getAttribute(INCLUDE_EMPTY_ATTRIBUTE)), null, objectComparator);
        if(userClassifier.isNonViewingUser(user)) {
            children = ImmutableHierarchyNodeChildren.copyOf(children).withObjects((Password) null);
        }
        return children;
    }

    private String getSortOrder(HttpServletRequest request) {
        HttpSession session = request.getSession(false);

        String sortOrder = request.getParameter(BaseServlet.SORT_PARAMETER);
        if (sortOrder == null) {
            sortOrder = (String) session.getAttribute(BaseServlet.SORT_PARAMETER);
        }
        session.setAttribute(BaseServlet.SORT_PARAMETER, sortOrder);
        return sortOrder;
    }


    private abstract static class PasswordComparator implements Comparator<Password>, Serializable {

        protected abstract String getKeyString(Object passwordObject);

        protected abstract String getSecondaryString(Object passwordObject);

        @Override
        public int compare(final Password passwordObject0, final Password passwordObject1) {
            try {
                if (passwordObject0 == passwordObject1) {
                    return 0;
                }
                if (passwordObject0 == null) {
                    return Integer.MIN_VALUE;
                }
                if (passwordObject1 == null) {
                    return Integer.MAX_VALUE;
                }

                if(passwordObject0.getId().equals(passwordObject1.getId())) {
                    return 0;
                }

                int keyComparison = compareKeys(passwordObject0, passwordObject1);
                return keyComparison == 0 ? passwordObject0.getId().compareTo(passwordObject1.getId()) : keyComparison;
            } catch( Exception ex ) {
                throw new RuntimeException(ex);
            }
        }

        private int compareKeys(final Password passwordObject0, final Password passwordObject1) {
            int primaryKeyComparison = compareIndividualKeys(getKeyString(passwordObject0), getKeyString(passwordObject1));
            return primaryKeyComparison == 0 ?
                    compareIndividualKeys(getSecondaryString(passwordObject0), getSecondaryString(passwordObject1))
                :    primaryKeyComparison;
        }

        private int compareIndividualKeys(String key0, String key1) {
            if (key0 == null) {
                return Integer.MIN_VALUE;
            }
            if (key1 == null) {
                return Integer.MAX_VALUE;
            }

            int caseInsensitiveComparison = key0.compareToIgnoreCase(key1);
            if (caseInsensitiveComparison != 0) {
                return caseInsensitiveComparison;
            }

            return key0.compareTo(key1);
        }
    }

    private class UsernameComparator extends PasswordComparator {

        @Override
        protected String getKeyString(final Object passwordObject) {
            if (passwordObject instanceof PasswordBase) {
                return ((PasswordBase) passwordObject).getUsername();
            }
            return null;
        }

        @Override
        protected String getSecondaryString(final Object passwordObject) {
            if (passwordObject instanceof PasswordBase) {
                return ((PasswordBase) passwordObject).getLocation();
            }

            return null;
        }
    }

    private class SystemComparator extends PasswordComparator {

        @Override
        protected String getKeyString(final Object passwordObject) {
            if (passwordObject instanceof PasswordBase) {
                return ((PasswordBase) passwordObject).getLocation();
            }
            return null;
        }

        @Override
        protected String getSecondaryString(final Object passwordObject) {
            if (passwordObject instanceof PasswordBase) {
                return ((PasswordBase) passwordObject).getUsername();
            }

            return null;
        }
    }
}