org.alfresco.module.org_alfresco_module_rm.capability.RMSecurityCommon.java Source code

Java tutorial

Introduction

Here is the source code for org.alfresco.module.org_alfresco_module_rm.capability.RMSecurityCommon.java

Source

/*
 * Copyright (C) 2005-2014 Alfresco Software Limited.
 *
 * This file is part of Alfresco
 *
 * Alfresco is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Alfresco is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 */
package org.alfresco.module.org_alfresco_module_rm.capability;

import java.util.Map;

import net.sf.acegisecurity.vote.AccessDecisionVoter;

import org.alfresco.module.org_alfresco_module_rm.capability.impl.ViewRecordsCapability;
import org.alfresco.module.org_alfresco_module_rm.caveat.RMCaveatConfigComponent;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionalResourceHelper;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.util.Pair;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * Common security functions.
 *
 * TODO move methods to the appropriate services
 *
 * @author Roy Wetherall
 * @since 2.0
 */
public class RMSecurityCommon implements ApplicationContextAware {
    /** No set value */
    protected static final int NOSET_VALUE = -100;

    /** Logger */
    private static Log logger = LogFactory.getLog(RMSecurityCommon.class);

    /** Services */
    //This is the internal NodeService -- no permission checks
    protected NodeService nodeService;
    protected PermissionService permissionService;
    protected RMCaveatConfigComponent caveatConfigComponent;
    private FilePlanService filePlanService;

    /** Application context */
    protected ApplicationContext applicationContext;

    /**
     * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    /**
     * @param nodeService   node service
     */
    public void setNodeService(NodeService nodeService) {
        this.nodeService = nodeService;
    }

    /**
     * @param permissionService permission service
     */
    public void setPermissionService(PermissionService permissionService) {
        this.permissionService = permissionService;
    }

    /**
     * @param caveatConfigComponent caveat config service
     */
    public void setCaveatConfigComponent(RMCaveatConfigComponent caveatConfigComponent) {
        this.caveatConfigComponent = caveatConfigComponent;
    }

    /**
     * @return   FilePlanService   file plan service
     */
    protected FilePlanService getFilePlanService() {
        if (filePlanService == null) {
            filePlanService = (FilePlanService) applicationContext.getBean("filePlanService");
        }
        return filePlanService;
    }

    /**
     * Sets a value into the transaction cache
     *
     * @param prefix
     * @param nodeRef
     * @param value
     * @return
     */
    protected int setTransactionCache(String prefix, NodeRef nodeRef, int value) {
        String user = AuthenticationUtil.getRunAsUser();
        AlfrescoTransactionSupport.bindResource(prefix + nodeRef.toString() + user, Integer.valueOf(value));
        return value;
    }

    /**
     * Gets a value from the transaction cache
     *
     * @param prefix
     * @param nodeRef
     * @return
     */
    protected int getTransactionCache(String prefix, NodeRef nodeRef) {
        int result = NOSET_VALUE;
        String user = AuthenticationUtil.getRunAsUser();
        Integer value = (Integer) AlfrescoTransactionSupport.getResource(prefix + nodeRef.toString() + user);
        if (value != null) {
            result = value.intValue();
        }
        return result;
    }

    /**
     * Check for RM read
     *
     * @param nodeRef
     * @return
     */
    public int checkRead(NodeRef nodeRef) {
        int result = AccessDecisionVoter.ACCESS_ABSTAIN;
        if (nodeRef != null) {
            // now we know the node - we can abstain for certain types and aspects (eg, rm)
            result = checkRead(nodeRef, false);
        }

        return result;
    }

    /**
     * Check for RM read
     *
     * @param nodeRef
     * @param allowDMRead
     * @return
     */
    public int checkRead(NodeRef nodeRef, boolean allowDMRead) {
        int result = AccessDecisionVoter.ACCESS_ABSTAIN;

        if (nodeService.hasAspect(nodeRef, RecordsManagementModel.ASPECT_FILE_PLAN_COMPONENT)) {
            result = checkRmRead(nodeRef);
        } else if (allowDMRead) {
            // Check DM read for copy etc
            // DM does not grant - it can only deny
            if (permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED) {
                if (logger.isDebugEnabled()) {
                    logger.debug("\t\tPermission is denied");
                    Thread.dumpStack();
                }
                result = AccessDecisionVoter.ACCESS_DENIED;
            } else {
                result = AccessDecisionVoter.ACCESS_GRANTED;
            }
        }

        return result;
    }

    /**
     * Core RM read check
     *
     * @param nodeRef   node reference
     * @return int      see {@link AccessDecisionVoter}
     */
    public int checkRmRead(NodeRef nodeRef) {
        int result = AccessDecisionVoter.ACCESS_ABSTAIN;

        Map<Pair<String, NodeRef>, Integer> transactionCache = TransactionalResourceHelper
                .getMap("rm.security.checkRMRead");
        Pair<String, NodeRef> key = new Pair<String, NodeRef>(AuthenticationUtil.getRunAsUser(), nodeRef);

        if (transactionCache.containsKey(key)) {
            result = transactionCache.get(key);
        } else {
            if (permissionService.hasPermission(nodeRef, RMPermissionModel.READ_RECORDS) == AccessStatus.DENIED) {
                if (logger.isDebugEnabled()) {
                    logger.debug("\t\tUser does not have read record permission on node, access denied.  (nodeRef="
                            + nodeRef.toString() + ", user=" + AuthenticationUtil.getRunAsUser() + ")");
                }
                result = AccessDecisionVoter.ACCESS_DENIED;
            } else {
                // Get the file plan for the node
                NodeRef filePlan = getFilePlanService().getFilePlan(nodeRef);
                if (hasViewCapability(filePlan) == AccessStatus.DENIED) {
                    if (logger.isDebugEnabled()) {
                        logger.debug(
                                "\t\tUser does not have view records capability permission on node, access denied. (filePlan="
                                        + filePlan.toString() + ", user=" + AuthenticationUtil.getRunAsUser()
                                        + ")");
                    }
                    result = AccessDecisionVoter.ACCESS_DENIED;
                } else if (!caveatConfigComponent.hasAccess(nodeRef)) {
                    result = AccessDecisionVoter.ACCESS_DENIED;
                } else {
                    result = AccessDecisionVoter.ACCESS_GRANTED;
                }
            }

            // cache result
            transactionCache.put(key, result);
        }

        return result;
    }

    /**
     * Helper method to determine whether the current user has view capability on the file plan
     *
     * @param  filePlan   file plan
     * @return {@link AccessStatus}
     */
    private AccessStatus hasViewCapability(NodeRef filePlan) {
        Map<Pair<String, NodeRef>, AccessStatus> transactionCache = TransactionalResourceHelper
                .getMap("rm.security.hasViewCapability");
        Pair<String, NodeRef> key = new Pair<String, NodeRef>(AuthenticationUtil.getRunAsUser(), filePlan);

        if (transactionCache.containsKey(key)) {
            return transactionCache.get(key);
        } else {
            AccessStatus result = permissionService.hasPermission(filePlan, ViewRecordsCapability.NAME);
            transactionCache.put(key, result);
            return result;
        }
    }

    @SuppressWarnings("rawtypes")
    protected NodeRef getTestNode(MethodInvocation invocation, Class[] params, int position, boolean parent) {
        NodeRef testNodeRef = null;
        if (position < 0) {
            if (logger.isDebugEnabled()) {
                logger.debug("\tNothing to test permission against.");
            }
            testNodeRef = null;
        } else if (StoreRef.class.isAssignableFrom(params[position])) {
            if (invocation.getArguments()[position] != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("\tPermission test against the store - using permissions on the root node");
                }
                StoreRef storeRef = (StoreRef) invocation.getArguments()[position];
                if (nodeService.exists(storeRef)) {
                    testNodeRef = nodeService.getRootNode(storeRef);
                }
            }
        } else if (NodeRef.class.isAssignableFrom(params[position])) {
            testNodeRef = (NodeRef) invocation.getArguments()[position];
            if (parent) {
                testNodeRef = nodeService.getPrimaryParent(testNodeRef).getParentRef();
                if (logger.isDebugEnabled()) {
                    if (nodeService.exists(testNodeRef)) {
                        logger.debug("\tPermission test for parent on node " + nodeService.getPath(testNodeRef));
                    } else {
                        logger.debug("\tPermission test for parent on non-existing node " + testNodeRef);
                    }
                    logger.debug("\tPermission test for parent on node " + nodeService.getPath(testNodeRef));
                }
            } else {
                if (logger.isDebugEnabled()) {
                    if (nodeService.exists(testNodeRef)) {
                        logger.debug("\tPermission test on node " + nodeService.getPath(testNodeRef));
                    } else {
                        logger.debug("\tPermission test on non-existing node " + testNodeRef);
                    }
                }
            }
        } else if (ChildAssociationRef.class.isAssignableFrom(params[position])) {
            if (invocation.getArguments()[position] != null) {
                if (parent) {
                    testNodeRef = ((ChildAssociationRef) invocation.getArguments()[position]).getParentRef();
                } else {
                    testNodeRef = ((ChildAssociationRef) invocation.getArguments()[position]).getChildRef();
                }
                if (logger.isDebugEnabled()) {
                    if (nodeService.exists(testNodeRef)) {
                        logger.debug("\tPermission test on node " + nodeService.getPath(testNodeRef));
                    } else {
                        logger.debug("\tPermission test on non-existing node " + testNodeRef);
                    }
                }
            }
        } else if (AssociationRef.class.isAssignableFrom(params[position])
                && invocation.getArguments()[position] != null) {
            if (parent) {
                testNodeRef = ((AssociationRef) invocation.getArguments()[position]).getSourceRef();
            } else {
                testNodeRef = ((AssociationRef) invocation.getArguments()[position]).getTargetRef();
            }
            if (logger.isDebugEnabled()) {
                if (nodeService.exists(testNodeRef)) {
                    logger.debug("\tPermission test on node " + nodeService.getPath(testNodeRef));
                } else {
                    logger.debug("\tPermission test on non-existing node " + testNodeRef);
                }
            }
        }
        return testNodeRef;
    }
}