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

Source Code of org.apache.jackrabbit.core.security.authorization.acl.CompiledPermissionsImpl

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.jackrabbit.core.security.authorization.acl;

import org.apache.commons.collections.map.LRUMap;
import org.apache.jackrabbit.core.ItemImpl;
import org.apache.jackrabbit.core.ItemManager;
import org.apache.jackrabbit.core.NodeImpl;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.id.ItemId;
import org.apache.jackrabbit.core.id.NodeId;
import org.apache.jackrabbit.core.id.PropertyId;
import org.apache.jackrabbit.core.security.authorization.AbstractCompiledPermissions;
import org.apache.jackrabbit.core.security.authorization.AccessControlListener;
import org.apache.jackrabbit.core.security.authorization.AccessControlModifications;
import org.apache.jackrabbit.core.security.authorization.AccessControlUtils;
import org.apache.jackrabbit.core.security.authorization.Permission;
import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.Path;
import org.apache.jackrabbit.util.Text;

import javax.jcr.ItemNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.security.AccessControlEntry;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* <code>CompiledPermissionsImpl</code>...
*/
class CompiledPermissionsImpl extends AbstractCompiledPermissions implements AccessControlListener {

    private final List<String> principalNames;
    private final SessionImpl session;
    private final EntryCollector entryCollector;
    private final AccessControlUtils util;

    /*
     * Start with initial map size of 1024 and grow up to 5000 before
     * removing LRU items.
     */
    @SuppressWarnings("unchecked")
    private final Map<ItemId, Boolean> readCache = new LRUMap(1024) {
        @Override
        protected boolean removeLRU(LinkEntry entry) {
            return size() > 5000;
        }
    };

    private final Object monitor = new Object();

    CompiledPermissionsImpl(Set<Principal> principals, SessionImpl session,
                            EntryCollector entryCollector, AccessControlUtils util,
                            boolean listenToEvents) throws RepositoryException {
        this.session = session;
        this.entryCollector = entryCollector;
        this.util = util;

        principalNames = new ArrayList<String>(principals.size());
        for (Principal princ : principals) {
            principalNames.add(princ.getName());
        }

        if (listenToEvents) {
            /*
            Make sure this AclPermission recalculates the permissions if
            any ACL concerning it is modified.
            */
            entryCollector.addListener(this);
        }
    }

    private Result buildResult(NodeImpl node, boolean isExistingNode, boolean isAcItem, EntryFilterImpl filter) throws RepositoryException {
        // retrieve all ACEs at path or at the direct ancestor of path that
        // apply for the principal names.
        NodeImpl n = ACLProvider.getNode(node, isAcItem);
        Iterator<AccessControlEntry> entries = entryCollector.collectEntries(n, filter).iterator();

        /*
        Calculate privileges and permissions:
        Since the ACEs only define privileges on a node and do not allow
        to add additional restrictions, the permissions can be determined
        without taking the given target name or target item into account.
        */
        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(filter.getPath(), 1);

        while (entries.hasNext()) {
            ACLTemplate.Entry ace = (ACLTemplate.Entry) entries.next();
            /*
            Determine if the ACE also takes effect on the parent:
            Some permissions (e.g. add-node or removal) must be determined
            from privileges defined for the parent.
            A 'local' entry defined on the target node never effects the
            parent. For inherited ACEs determine if the ACE matches the
            parent path.
            */
            int entryBits = ace.getPrivilegeBits();
            boolean isLocal = isExistingNode && ace.isLocal(node.getNodeId());
            boolean matchesParent = (!isLocal && ace.matches(parentPath));
            if (matchesParent) {
                if (ace.isAllow()) {
                    parentAllows |= Permission.diff(entryBits, parentDenies);
                } else {
                    parentDenies |= Permission.diff(entryBits, parentAllows);
                }
            }
            if (ace.isAllow()) {
                allowPrivileges |= Permission.diff(entryBits, denyPrivileges);
                int permissions = PrivilegeRegistry.calculatePermissions(allowPrivileges, parentAllows, true, isAcItem);
                allows |= Permission.diff(permissions, denies);
            } else {
                denyPrivileges |= Permission.diff(entryBits, allowPrivileges);
                int permissions = PrivilegeRegistry.calculatePermissions(denyPrivileges, parentDenies, false, isAcItem);
                denies |= Permission.diff(permissions, allows);
            }
        }
        return new Result(allows, denies, allowPrivileges, denyPrivileges);
    }

    //------------------------------------< AbstractCompiledPermissions >---
    /**
     * @see AbstractCompiledPermissions#buildResult(org.apache.jackrabbit.spi.Path)
     */
    @Override
    protected Result buildResult(Path absPath) throws RepositoryException {
        boolean existingNode = false;
        NodeImpl node;

        ItemManager itemMgr = session.getItemManager();
        try {
            ItemImpl item = itemMgr.getItem(absPath);
            if (item.isNode()) {
                node = (NodeImpl) item;
                existingNode = true;
            } else {
                node = (NodeImpl) item.getParent();
            }
        } catch (RepositoryException e) {
            // path points to a non-persisted item.
            // -> find the nearest persisted node starting from the root.
            Path.Element[] elems = absPath.getElements();
            NodeImpl parent = (NodeImpl) session.getRootNode();
            for (int i = 1; i < elems.length - 1; i++) {
                Name name = elems[i].getName();
                int index = elems[i].getIndex();
                if (!parent.hasNode(name, index)) {
                    // last persisted node reached
                    break;
                }
                parent = parent.getNode(name, index);

            }
            node = parent;
        }

        if (node == null) {
            // should never get here
            throw new ItemNotFoundException("Item out of hierarchy.");
        }

        boolean isAcItem = util.isAcItem(absPath);
        return buildResult(node, existingNode, isAcItem, new EntryFilterImpl(principalNames, absPath, session));
    }

    /**
     * @see AbstractCompiledPermissions#clearCache()
     */
    @Override
    protected void clearCache() {
        synchronized (monitor) {
            readCache.clear();
        }
        super.clearCache();
    }

    //--------------------------------------------< CompiledPermissions >---
    /**
     * @see org.apache.jackrabbit.core.security.authorization.CompiledPermissions#close()
     */
    @Override
    public void close() {
        entryCollector.removeListener(this);
        // NOTE: do not logout shared session.
        super.close();
    }

    /**
     * @see org.apache.jackrabbit.core.security.authorization.CompiledPermissions#canRead(Path, ItemId)
     */
    public boolean canRead(Path path, ItemId itemId) throws RepositoryException {
        ItemId id = (itemId == null) ? session.getHierarchyManager().resolvePath(path) : itemId;
        // no extra check for existence as method may only be called for existing items.
        boolean isExistingNode = id.denotesNode();
        boolean canRead;
        synchronized (monitor) {
            if (readCache.containsKey(id)) {
                canRead = readCache.get(id);
            } else {
                ItemManager itemMgr = session.getItemManager();
                NodeId nodeId = (isExistingNode) ? (NodeId) id : ((PropertyId) id).getParentId();
                NodeImpl node = (NodeImpl) itemMgr.getItem(nodeId);
                // TODO: check again if retrieving the path can be avoided
                Path absPath = (path == null) ? session.getHierarchyManager().getPath(id) : path;
                Result result = buildResult(node, isExistingNode, util.isAcItem(node), new EntryFilterImpl(principalNames, absPath, session));

                canRead = result.grants(Permission.READ);
                readCache.put(id, canRead);
            }
        }
        return canRead;
    }

    //----------------------------------------< ACLModificationListener >---
    /**
     * @see org.apache.jackrabbit.core.security.authorization.AccessControlListener#acModified(org.apache.jackrabbit.core.security.authorization.AccessControlModifications)
     */
    public void acModified(AccessControlModifications modifications) {
        // ignore the details of the modifications and clear all caches.
        clearCache();
    }
}
TOP

Related Classes of org.apache.jackrabbit.core.security.authorization.acl.CompiledPermissionsImpl

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.