Package org.apache.jackrabbit.core.security.authorization.principalbased

Source Code of org.apache.jackrabbit.core.security.authorization.principalbased.ACLProvider$CompiledPermissionImpl

/*
* $Id: ACLProvider.java 689499 2008-08-27 15:12:04Z angela $
*
* Copyright 1997-2005 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package org.apache.jackrabbit.core.security.authorization.principalbased;

import org.apache.jackrabbit.core.security.authorization.AbstractAccessControlProvider;
import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
import org.apache.jackrabbit.core.security.authorization.AccessControlProvider;
import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
import org.apache.jackrabbit.core.security.authorization.AccessControlEditor;
import org.apache.jackrabbit.core.security.authorization.CompiledPermissions;
import org.apache.jackrabbit.core.security.authorization.Permission;
import org.apache.jackrabbit.core.security.authorization.AbstractCompiledPermissions;
import org.apache.jackrabbit.core.security.authorization.AccessControlUtils;
import org.apache.jackrabbit.core.security.authorization.UnmodifiableAccessControlList;
import org.apache.jackrabbit.core.security.SecurityConstants;
import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
import org.apache.jackrabbit.core.NodeImpl;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.ItemImpl;
import org.apache.jackrabbit.core.observation.SynchronousEventListener;
import org.apache.jackrabbit.spi.Path;
import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
import org.apache.jackrabbit.api.security.principal.PrincipalManager;
import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicy;
import org.apache.jackrabbit.api.jsr283.security.AccessControlEntry;
import org.apache.jackrabbit.api.jsr283.security.Privilege;
import org.apache.jackrabbit.api.jsr283.security.AccessControlManager;
import org.apache.jackrabbit.util.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.PropertyType;
import javax.jcr.ValueFactory;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventListener;
import javax.jcr.observation.EventIterator;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Arrays;
import java.util.HashMap;
import java.security.Principal;

/**
* <code>CombinedProvider</code>...
*/
public class ACLProvider extends AbstractAccessControlProvider implements AccessControlConstants {

    private static Logger log = LoggerFactory.getLogger(ACLProvider.class);

    // TODO: add means to show effective-policy to a user.

    private ACLEditor editor;
    private NodeImpl acRoot;

    //-------------------------------------------------< AccessControlUtils >---
    /**
     * @see AccessControlUtils#isAcItem(Path)
     */
    public boolean isAcItem(Path absPath) throws RepositoryException {
        Path.Element[] elems = absPath.getElements();
        for (int i = 0; i < elems.length; i++) {
            if (N_POLICY.equals(elems[i].getName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * @see AccessControlUtils#isAcItem(ItemImpl)
     */
    public boolean isAcItem(ItemImpl item) throws RepositoryException {
        NodeImpl n = ((item.isNode()) ? (NodeImpl) item : (NodeImpl) item.getParent());
        return n.isNodeType(NT_REP_ACL) || n.isNodeType(NT_REP_ACE);
    }

    //----------------------------------------------< AccessControlProvider >---
    /**
     * @see AccessControlProvider#init(javax.jcr.Session, java.util.Map)
     */
    public void init(Session systemSession, Map configuration) throws RepositoryException {
        super.init(systemSession, configuration);

        NodeImpl root = (NodeImpl) session.getRootNode();
        if (root.hasNode(N_ACCESSCONTROL)) {
            acRoot = root.getNode(N_ACCESSCONTROL);
            if (!acRoot.isNodeType(NT_REP_ACCESS_CONTROL)) {
                throw new RepositoryException("Error while initializing Access Control Provider: Found ac-root to be wrong node type " + acRoot.getPrimaryNodeType().getName());
            }
        } else {
            acRoot = root.addNode(N_ACCESSCONTROL, NT_REP_ACCESS_CONTROL, null);
        }

        editor = new ACLEditor(session, resolver.getQPath(acRoot.getPath()));
        if (!configuration.containsKey(PARAM_OMIT_DEFAULT_PERMISSIONS)) {
            try {
                log.info("Install initial permissions: ...");

                ValueFactory vf = session.getValueFactory();
                Map restrictions = new HashMap();
                restrictions.put(session.getJCRName(ACLTemplate.P_NODE_PATH), vf.createValue(root.getPath(), PropertyType.PATH));
                restrictions.put(session.getJCRName(ACLTemplate.P_GLOB), vf.createValue(GlobPattern.WILDCARD_ALL));

                PrincipalManager pMgr = session.getPrincipalManager();
                AccessControlManager acMgr = session.getAccessControlManager();
                Principal administrators;
                String pName = SecurityConstants.ADMINISTRATORS_NAME;
                if (pMgr.hasPrincipal(pName)) {
                    administrators = pMgr.getPrincipal(pName);
                } else {
                    log.warn("Administrators principal group is missing.");
                    administrators = new PrincipalImpl(pName);
                }
                AccessControlPolicy[] acls = editor.editAccessControlPolicies(administrators);
                ACLTemplate acl = (ACLTemplate) acls[0];
                if (acl.isEmpty()) {
                    log.info("... Privilege.ALL for administrators principal.");
                    acl.addEntry(administrators,
                            new Privilege[] {acMgr.privilegeFromName(Privilege.JCR_ALL)},
                            true, restrictions);
                    editor.setPolicy(acl.getPath(), acl);
                } else {
                    log.info("... policy for administrators principal already present.");
                }

                Principal everyone = pMgr.getEveryone();
                acls = editor.editAccessControlPolicies(everyone);
                acl = (ACLTemplate) acls[0];
                if (acl.isEmpty()) {
                    log.info("... Privilege.READ for everyone principal.");
                    acl.addEntry(everyone,
                            new Privilege[] {acMgr.privilegeFromName(Privilege.JCR_READ)},
                            true, restrictions);
                    editor.setPolicy(acl.getPath(), acl);
                } else {
                    log.info("... policy for everyone principal already present.");
                }

                session.save();
                log.info("... done.");
            } catch (RepositoryException e) {
                log.error("Failed to set-up minimal access control for root node of workspace " + session.getWorkspace().getName());
                session.getRootNode().refresh(false);
                throw e;
            }
        }
    }

    /**
     * @see AccessControlProvider#getEffectivePolicies(Path)
     */
    public AccessControlPolicy[] getEffectivePolicies(Path absPath)
            throws ItemNotFoundException, RepositoryException {
        AccessControlPolicy[] tmpls = editor.getPolicies(session.getJCRPath(absPath));
        AccessControlPolicy[] effectives = new AccessControlPolicy[tmpls.length];
        for (int i = 0; i < tmpls.length; i++) {
            effectives[i] = new UnmodifiableAccessControlList((ACLTemplate) tmpls[i]);
        }
        return effectives;
    }

    /**
     * @see AccessControlProvider#getEditor(Session)
     */
    public AccessControlEditor getEditor(Session editingSession) {
        checkInitialized();
        if (editingSession instanceof SessionImpl) {
            try {
                return new ACLEditor((SessionImpl) editingSession, session.getQPath(acRoot.getPath()));
            } catch (RepositoryException e) {
                // should never get here
                log.error("Internal error: ", e.getMessage());
            }
        }

        log.debug("Unable to build access control editor " + ACLEditor.class.getName() + ".");
        return null;
    }

    /**
     * @see AccessControlProvider#compilePermissions(Set)
     */
    public CompiledPermissions compilePermissions(Set principals) throws RepositoryException {
        checkInitialized();
        if (isAdminOrSystem(principals)) {
            return getAdminPermissions();
        } else if (isReadOnly(principals)) {
            return getReadOnlyPermissions();
        } else {
            return new ACLProvider.CompiledPermissionImpl(principals);
        }
    }

    /**
     * @see AccessControlProvider#canAccessRoot(Set)
     */
    public boolean canAccessRoot(Set principals) throws RepositoryException {
        checkInitialized();
        if (isAdminOrSystem(principals)) {
            return true;
        } else {
            CompiledPermissions cp = new CompiledPermissionImpl(principals, false);
            return cp.grants(PathFactoryImpl.getInstance().getRootPath(), Permission.READ);
        }
    }

    //-----------------------------------------------------< CompiledPolicy >---
    /**
     *
     */
    private class CompiledPermissionImpl extends AbstractCompiledPermissions
            implements SynchronousEventListener {

        private final Set principals;
        private final Set acPaths;
        private ACLProvider.Entries entries;

        /**
         * @param principals
         * @throws RepositoryException
         */
        private CompiledPermissionImpl(Set principals) throws RepositoryException {
            this(principals, true);
        }

        /**
         * @param principals
         * @throws RepositoryException
         */
        private CompiledPermissionImpl(Set principals, boolean listenToEvents) throws RepositoryException {

            this.principals = principals;
            acPaths = new HashSet(principals.size());
            entries = reload();

            // TODO: describe
            if (listenToEvents) {
                int events = Event.PROPERTY_CHANGED | Event.PROPERTY_ADDED |
                        Event.PROPERTY_REMOVED | Event.NODE_ADDED | Event.NODE_REMOVED;
                String[] ntNames = new String[] {
                        session.getJCRName(NT_REP_ACE)
                };
                observationMgr.addEventListener(this, events, acRoot.getPath(), true, null, ntNames, false);
            }
        }

        //------------------------------------< AbstractCompiledPermissions >---
        /**
         * @see AbstractCompiledPermissions#buildResult(Path)
         */
        protected synchronized Result buildResult(Path absPath) throws RepositoryException {
            if (!absPath.isAbsolute()) {
                throw new RepositoryException("Absolute path expected.");
            }

            boolean isAcItem = isAcItem(absPath);
            String jcrPath = session.getJCRPath(absPath);

            // retrieve principal-based permissions and privileges
            Result result;
            if (session.itemExists(jcrPath)) {
                Item item = session.getItem(jcrPath);
                result = entries.getResult(item, item.getPath(), isAcItem);
            } else {
                result = entries.getResult(null, jcrPath, isAcItem);
            }
            return result;
        }

        //--------------------------------------------< CompiledPermissions >---
        /**
         * @see CompiledPermissions#close()
         */
        public void close() {
            try {
                observationMgr.removeEventListener(this);
            } catch (RepositoryException e) {
                log.debug("Unable to unregister listener: ", e.getMessage());
            }
            super.close();
        }

        //--------------------------------------------------< EventListener >---
        /**
         * @see EventListener#onEvent(EventIterator)
         */
        public synchronized void onEvent(EventIterator events) {
            try {
                boolean reload = false;
                while (events.hasNext() && !reload) {
                    Event ev = events.nextEvent();
                    String path = ev.getPath();
                    // only invalidate cache if any of the events affects the
                    // nodes defining permissions for the principals.
                    switch (ev.getType()) {
                        case Event.NODE_ADDED:
                        case Event.NODE_REMOVED:
                            reload = acPaths.contains(Text.getRelativeParent(path, 2));
                            break;
                        case Event.PROPERTY_ADDED:
                        case Event.PROPERTY_CHANGED:
                        case Event.PROPERTY_REMOVED:
                            reload = acPaths.contains(Text.getRelativeParent(path, 3));
                            break;
                        default:
                            // illegal event-type: should never occur. ignore
                            break;
                    }
                }
                // eventually reload the ACL and clear the cache
                if (reload) {
                    clearCache();
                    // reload the acl
                    entries = reload();
                }
            } catch (RepositoryException e) {
                // should never get here
                log.warn("Internal error: ", e.getMessage());
            }
        }

        /**
         *
         * @return
         * @throws RepositoryException
         */
        private ACLProvider.Entries reload() throws RepositoryException {
            // reload the paths
            acPaths.clear();

            // acNodes must be ordered in the same order as the principals
            // in order to obtain proper acl-evalution in case the given
            // principal-set is ordered.
            List allACEs = new ArrayList();
            // build acl-hierarchy assuming that principal-order determines the
            // acl-inheritance.
            for (Iterator it = principals.iterator(); it.hasNext();) {
                Principal princ = (Principal) it.next();
                ACLTemplate acl = editor.getACL(princ);
                if (acl == null || acl.isEmpty()) {
                    acPaths.add(editor.getPathToAcNode(princ));
                } else {
                    // retrieve the ACEs from the node
                    AccessControlEntry[] aces = (AccessControlEntry[]) acl.getAccessControlEntries();
                    allACEs.addAll(Arrays.asList(aces));
                    acPaths.add(acl.getPath());
                }
            }

            return new ACLProvider.Entries(allACEs);
        }
    }

    //--------------------------------------------------------------------------
    /**
     * Utility class that raps a list of access control entries and evaluates
     * them for a specified item/path.
     */
    private class Entries {

        private final List entries;

        /**
         *
         * @param entries
         */
        private Entries(List entries) {
            this.entries = entries;
        }

        /**
         * Loop over all entries and evaluate allows/denies for those matching
         * the given jcrPath.
         *
         * @param target Existing target item for which the permissions will be
         * evaluated or <code>null</code>.
         * @param targetPath Path used for the evaluation; pointing to an
         * existing or non-existing item.
         * @param isAcItem
         * @return
         * @throws RepositoryException
         */
        private AbstractCompiledPermissions.Result getResult(Item target,
                                                             String targetPath,
                                                             boolean isAcItem) throws RepositoryException {
            int allows = Permission.NONE;
            int denies = Permission.NONE;
            int allowPrivileges = PrivilegeRegistry.NO_PRIVILEGE;
            int denyPrivileges = PrivilegeRegistry.NO_PRIVILEGE;
            int parentAllows = PrivilegeRegistry.NO_PRIVILEGE;
            int parentDenies = PrivilegeRegistry.NO_PRIVILEGE;

            String parentPath = Text.getRelativeParent(targetPath, 1);
            for (Iterator it = entries.iterator(); it.hasNext() && allows != Permission.ALL;) {
                ACLTemplate.Entry entr = (ACLTemplate.Entry) it.next();
                int privs = entr.getPrivilegeBits();

                if (!"".equals(parentPath) && entr.matches(parentPath)) {
                    if (entr.isAllow()) {
                        parentAllows |= Permission.diff(privs, parentDenies);
                    } else {
                        parentDenies |= Permission.diff(privs, parentAllows);
                    }
                }

                boolean matches = (target != null) ? entr.matches(target) : entr.matches(targetPath);
                if (matches) {
                    if (entr.isAllow()) {
                        allowPrivileges |= Permission.diff(privs, denyPrivileges);
                        int permissions = Permission.calculatePermissions(allowPrivileges, parentAllows, true, isAcItem);
                        allows |= Permission.diff(permissions, denies);
                    } else {
                        denyPrivileges |= Permission.diff(privs, allowPrivileges);
                        int permissions = Permission.calculatePermissions(denyPrivileges, parentDenies, false, isAcItem);
                        denies |= Permission.diff(permissions, allows);
                    }
                }
            }
            return new AbstractCompiledPermissions.Result(allows, denies, allowPrivileges, denyPrivileges);
        }
    }
}
TOP

Related Classes of org.apache.jackrabbit.core.security.authorization.principalbased.ACLProvider$CompiledPermissionImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.