You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2008/03/19 14:57:11 UTC

svn commit: r638834 [7/14] - in /jackrabbit/trunk: jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/ jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/ jackr...

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/ACLImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/ACLImpl.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/ACLImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/ACLImpl.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,147 @@
+/*
+ * 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.combined;
+
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.util.Text;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+import javax.jcr.Item;
+import java.security.Principal;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * <code>ACLImpl</code>...
+ */
+class ACLImpl {
+
+    private final Set acPaths;
+    private final Map principalToEntryArray;
+
+    private int privileges = -1;
+
+    ACLImpl(Map principalToEntryArray, Set acPaths) {
+        this.acPaths = acPaths;
+        this.principalToEntryArray = principalToEntryArray;
+    }
+
+    Set getAcPaths() {
+        return acPaths;
+    }
+
+    /**
+     * @param target Existing target item for which the permissions will be
+     * evaluated.
+     * @param protectsACL
+     * @return
+     * @throws RepositoryException
+     */
+    int getPermissions(Item target, boolean protectsACL) throws RepositoryException {
+        int allows = 0;
+        int denies = 0;
+        for (Iterator it = principalToEntryArray.keySet().iterator();
+             it.hasNext() && allows != Permission.ALL;) {
+            Principal princ = (Principal) it.next();
+            PolicyEntryImpl[] aces = (PolicyEntryImpl[]) principalToEntryArray.get(princ);
+            // loop over all entries and evaluate allows/denies for those
+            // matching the given jcrPath
+            for (int i = 0; i < aces.length; i++) {
+                PolicyEntryImpl entr = aces[i];
+                // TODO: check again if correct
+                if (entr.matches(target)) {
+                    int privs = entr.getPrivilegeBits();
+                    int permissions = Permission.calculatePermissions(privs, privs, protectsACL);
+                    if (entr.isAllow()) {
+                        allows |= Permission.diff(permissions, denies);
+                    } else {
+                        denies |= Permission.diff(permissions, allows);
+                    }
+                }
+            }
+        }
+        return allows;
+    }
+
+    /**
+     *
+     * @param parent Existing parent of the target to be evaluated.
+     * @param targetName name of a non-existing child item to calculate the
+     * permissions for.
+     * @param protectsACL
+     * @return
+     * @throws RepositoryException
+     */
+    int getPermissions(Node parent, String targetName, boolean protectsACL) throws RepositoryException {
+        int allows = 0;
+        int denies = 0;
+        String jcrPath = parent.getPath() + "/" + targetName;
+        for (Iterator it = principalToEntryArray.keySet().iterator();
+             it.hasNext() && allows != Permission.ALL;) {
+            Principal princ = (Principal) it.next();
+            PolicyEntryImpl[] aces = (PolicyEntryImpl[]) principalToEntryArray.get(princ);
+            // loop over all entries and evaluate allows/denies for those
+            // matching the given jcrPath
+            // TODO: check if correct
+            for (int i = 0; i < aces.length; i++) {
+                PolicyEntryImpl entr = aces[i];
+                if (entr.matches(jcrPath)) {
+                    int privs = entr.getPrivilegeBits();
+                    int permissions = Permission.calculatePermissions(privs, privs, protectsACL);
+                    if (entr.isAllow()) {
+                        allows |= Permission.diff(permissions, denies);
+                    } else {
+                        denies |= Permission.diff(permissions, allows);
+                    }
+                }
+            }
+        }
+        return allows;
+    }
+
+    int getPrivileges(String nodePath) throws RepositoryException {
+        if (privileges == -1) {
+            int allows = 0;
+            int denies = 0;
+            for (Iterator it = principalToEntryArray.keySet().iterator();
+                 it.hasNext() && allows != Permission.ALL;) {
+                Principal princ = (Principal) it.next();
+                PolicyEntryImpl[] aces = (PolicyEntryImpl[]) principalToEntryArray.get(princ);
+                // loop over all entries and evaluate allows/denies for those
+                // matching the given jcrPath
+                for (int i = 0; i < aces.length; i++) {
+                    PolicyEntryImpl entr = aces[i];
+                    // TODO: check again which ACEs must be respected.
+                    // TODO: maybe ancestor-defs only if glob = *?
+                    String np = entr.getNodePath();
+                    if (np.equals(nodePath) || Text.isDescendant(np, nodePath)) {
+                        if (entr.isAllow()) {
+                            allows |= PrivilegeRegistry.diff(entr.getPrivilegeBits(), denies);
+                        } else {
+                            denies |= PrivilegeRegistry.diff(entr.getPrivilegeBits(), allows);
+                        }
+                    }
+                }
+            }
+            privileges = allows;
+        }
+        return privileges;
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/ACLImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/ACLImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedEditor.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedEditor.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedEditor.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,359 @@
+/*
+ * 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.combined;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.core.security.authorization.AccessControlEditor;
+import org.apache.jackrabbit.core.security.authorization.PolicyTemplate;
+import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.core.security.authorization.acl.ACLEditor;
+import org.apache.jackrabbit.core.security.jsr283.security.AccessControlException;
+import org.apache.jackrabbit.core.security.jsr283.security.Privilege;
+import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.core.security.principal.ItemBasedPrincipal;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <code>CombinedEditor</code>...
+ */
+class CombinedEditor extends ACLEditor {
+
+    // TODO: must make sure, that store paths/globs do not contain remapped prefixes from the session
+
+    private static Logger log = LoggerFactory.getLogger(CombinedEditor.class);
+
+    private final SessionImpl session;
+    private final NamePathResolver systemResolver;
+    private final Path acRootPath;
+
+    CombinedEditor(SessionImpl session, NamePathResolver systemResolver,
+                   Path acRootPath) throws RepositoryException {
+        super(session);
+        this.session = session;
+        this.systemResolver = systemResolver;
+        this.acRootPath = acRootPath;
+    }
+
+    PolicyTemplateImpl editPolicyTemplate(Principal principal) throws RepositoryException {
+        if (!session.getPrincipalManager().hasPrincipal(principal.getName())) {
+            throw new AccessControlException("Unknown principal.");
+        }
+        NodeId nid = getAcId(principal);
+        if (nid == null) {
+            nid = createAcNode(principal).getNodeId();
+        }
+
+        PolicyTemplate pt = getPolicyTemplate(nid);
+        if (pt instanceof PolicyTemplateImpl) {
+            return (PolicyTemplateImpl) pt;
+        } else {
+            // should never get here.
+            throw new AccessControlException();
+        }
+    }
+
+    PolicyTemplateImpl getPolicyTemplate(Principal principal) throws RepositoryException {
+        if (!session.getPrincipalManager().hasPrincipal(principal.getName())) {
+            throw new AccessControlException("Unknown principal.");
+        }
+
+        NodeId nid = getAcId(principal);
+        if (nid != null) {
+            PolicyTemplate pt = getPolicyTemplate(nid);
+            if (pt instanceof PolicyTemplateImpl) {
+                return (PolicyTemplateImpl) pt;
+            }
+        }
+
+        // no policy for the given principal
+        log.debug("No combined policy template for Principal " + principal.getName());
+        return null;
+    }
+
+    //------------------------------------------------< AccessControlEditor >---
+    /**
+     * @see AccessControlEditor#getPolicyTemplate(NodeId)
+     */
+    public PolicyTemplate getPolicyTemplate(NodeId id) throws AccessControlException, ItemNotFoundException, RepositoryException {
+        checkProtectsNode(id);
+
+        NodeImpl acNode = getAcNode(id);
+        if (acNode != null) {
+            if (isAccessControlled(acNode)) {
+                return buildTemplate(acNode);
+            } else {
+                log.debug("No local policy defined for Node " + id);
+                return null;
+            }
+        } else {
+            // nodeID not below rep:accesscontrol -> delegate to ACLEditor
+            return super.getPolicyTemplate(id);
+        }
+    }
+
+    /**
+     * @see AccessControlEditor#editPolicyTemplate(NodeId)
+     */
+    public PolicyTemplate editPolicyTemplate(NodeId id) throws AccessControlException, ItemNotFoundException, RepositoryException {
+        checkProtectsNode(id);
+
+        NodeImpl acNode = getAcNode(id);
+        if (acNode != null) {
+            return buildTemplate(acNode);
+        } else {
+            // nodeID not below rep:accesscontrol -> delegate to ACLEditor
+            return super.editPolicyTemplate(id);
+        }
+    }
+
+    /**
+     * @see AccessControlEditor#setPolicyTemplate(NodeId, PolicyTemplate)
+     */
+    public void setPolicyTemplate(NodeId id, PolicyTemplate template) throws AccessControlException, ItemNotFoundException, RepositoryException {
+        checkProtectsNode(id);
+
+        if (template instanceof PolicyTemplateImpl) {
+            PolicyTemplateImpl at = (PolicyTemplateImpl) template;
+            if (!id.equals(at.getNodeId())) {
+                throw new AccessControlException("Attempt to store PolicyTemplate to a wrong node.");
+            }
+            NodeImpl acNode = getAcNode(id);
+            if (acNode == null) {
+                throw new ItemNotFoundException("No such node " + id);
+            }
+
+            /*
+             in order to assert that the parent (ac-controlled node) gets
+             modified an existing ACL node is removed first and the recreated.
+             this also asserts that all ACEs are cleared without having to
+             access and removed the explicitely
+            */
+            NodeImpl aclNode;
+            if (acNode.hasNode(N_POLICY)) {
+                aclNode = acNode.getNode(N_POLICY);
+                removeSecurityItem(aclNode);
+            }
+            /* now (re) create it */
+            aclNode = addSecurityNode(acNode, N_POLICY, NT_REP_ACL);
+
+            /* add all entries defined on the template */
+            PolicyEntryImpl[] aces = (PolicyEntryImpl[]) template.getEntries();
+            for (int i = 0; i < aces.length; i++) {
+                PolicyEntryImpl ace = aces[i];
+
+                // create the ACE node
+                Name nodeName = getUniqueNodeName(aclNode, "entry");
+                Name ntName = (ace.isAllow()) ? NT_REP_GRANT_ACE : NT_REP_DENY_ACE;
+                NodeImpl aceNode = addSecurityNode(aclNode, nodeName, ntName);
+
+                ValueFactory vf = session.getValueFactory();
+                // write the rep:principalName property
+                setSecurityProperty(aceNode, P_PRINCIPAL_NAME, vf.createValue(ace.getPrincipal().getName()));
+                // ... and the rep:privileges property
+                Privilege[] privs = ace.getPrivileges();
+                Value[] vs = new Value[privs.length];
+                for (int j = 0; j < privs.length; j++) {
+                    vs[i] = vf.createValue(privs[j].getName());
+                }
+                setSecurityProperty(aceNode, P_PRIVILEGES, vs);
+                setSecurityProperty(aceNode, P_NODE_PATH, vf.createValue(ace.getNodePath()));                
+                setSecurityProperty(aceNode, P_GLOB, vf.createValue(ace.getGlob()));
+            }
+        } else {
+            // try super class
+            super.setPolicyTemplate(id, template);
+        }
+    }
+
+    /**
+     * @see AccessControlEditor#removePolicyTemplate(NodeId)
+     */
+    public PolicyTemplate removePolicyTemplate(NodeId id) throws AccessControlException, ItemNotFoundException, RepositoryException {
+        checkProtectsNode(id);
+
+        NodeImpl acNode = getAcNode(id);
+        if (acNode != null) {
+            if (isAccessControlled(acNode)) {
+                // build the template in order to have a return value
+                PolicyTemplate tmpl = buildTemplate(acNode);
+                removeSecurityItem(acNode.getNode(N_POLICY));
+                return tmpl;
+            } else {
+                log.debug("No policy present to remove at " + id);
+                return null;
+            }
+        } else {
+            // nodeID not below rep:accesscontrol -> delegate to ACLEditor
+            return super.removePolicyTemplate(id);
+        }
+    }
+
+    // TODO: check if get/add/remove entries are properly handled by super-class
+
+    //------------------------------------------------------------< private >---
+    /**
+     *
+     * @param nodeId
+     * @return
+     * @throws AccessControlException
+     * @throws RepositoryException
+     */
+    private NodeImpl getAcNode(NodeId nodeId) throws AccessControlException, RepositoryException {
+        NodeImpl n = session.getNodeById(nodeId);
+        Path p = session.getHierarchyManager().getPath(n.getNodeId());
+        if (p.isDescendantOf(acRootPath)) {
+            return n;
+        } else {
+            // node outside of rep:accesscontrol tree -> not handled by this editor.
+            return null;
+        }
+    }
+
+    private NodeId getAcId(Principal principal) throws RepositoryException {
+        Path acPath = session.getQPath(getPathToAcNode(principal));
+        return session.getHierarchyManager().resolveNodePath(acPath);
+    }
+
+    private NodeImpl createAcNode(Principal principal) throws RepositoryException {
+        String acPath = getPathToAcNode(principal);
+        String[] segms = Text.explode(acPath, '/', false);
+        NodeImpl node = (NodeImpl) session.getRootNode();
+        for (int i = 0; i < segms.length; i++) {
+            Name nName = session.getQName(segms[i]);
+            if (node.hasNode(nName)) {
+                node = node.getNode(nName);
+                if (!node.isNodeType(NT_REP_ACCESS_CONTROL)) {
+                    // should never get here.
+                    throw new RepositoryException("Internal error: Unexpected nodetype " + node.getPrimaryNodeType().getName() + " below /rep:accessControl");
+                }
+            } else {
+                node = addSecurityNode(node, nName, NT_REP_ACCESS_CONTROL);
+            }
+        }
+        return node;
+    }
+
+    /**
+     * Test if the Node identified by <code>id</code> is itself part of ACL
+     * defining content. It this case setting or modifying an AC-policy is
+     * obviously not possible.
+     *
+     * @param id
+     * @throws AccessControlException If the given id identifies a Node that
+     * represents a ACL or ACE item.
+     * @throws RepositoryException
+     */
+    private void checkProtectsNode(NodeId id) throws RepositoryException {
+        NodeImpl node = session.getNodeById(id);
+        if (node.isNodeType(NT_REP_ACL) || node.isNodeType(NT_REP_ACE)) {
+            throw new AccessControlException("Node " + id + " defines ACL or ACE.");
+        }
+    }
+
+    private String getPathToAcNode(Principal principal) throws RepositoryException {
+        StringBuffer princPath = new StringBuffer(session.getJCRPath(acRootPath));
+        if (principal instanceof ItemBasedPrincipal) {
+            princPath.append(((ItemBasedPrincipal) principal).getPath());
+        } else {
+            princPath.append("/");
+            princPath.append(Text.escapeIllegalJcrChars(principal.getName()));
+        }
+        return princPath.toString();
+    }
+
+    /**
+     *
+     * @param node
+     * @return
+     * @throws RepositoryException
+     */
+    private boolean isAccessControlled(NodeImpl node) throws RepositoryException {
+        return node.isNodeType(NT_REP_ACCESS_CONTROL) && node.hasNode(N_POLICY);
+    }
+
+    private PolicyTemplate buildTemplate(NodeImpl acNode) throws RepositoryException {
+        Principal principal;
+        String principalName = Text.unescapeIllegalJcrChars(acNode.getName());
+        PrincipalManager pMgr = ((SessionImpl) acNode.getSession()).getPrincipalManager();
+        if (pMgr.hasPrincipal(principalName)) {
+            principal = pMgr.getPrincipal(principalName);
+        } else {
+            log.warn("Principal with name " + principalName + " unknown to PrincipalManager.");
+            // TODO: rather throw?
+            principal = new PrincipalImpl(principalName);
+        }
+        return new PolicyTemplateImpl(getEntries(acNode, principal), principal, acNode.getNodeId());
+    }
+
+    private List getEntries(NodeImpl acNode, Principal principal) throws RepositoryException {
+        List entries = new ArrayList();
+        if (acNode.isNodeType(NT_REP_ACCESS_CONTROL) && acNode.hasNode(N_POLICY)) {
+            NodeImpl aclNode = acNode.getNode(N_POLICY);
+            // loop over all entries in the aclNode for the princ-Principal
+            // and compare if they apply to the Node with 'nodeId'
+            for (NodeIterator aceNodes = aclNode.getNodes(); aceNodes.hasNext();) {
+                NodeImpl aceNode = (NodeImpl) aceNodes.nextNode();
+                PolicyEntryImpl ace = createFromNode(aceNode, principal);
+                if (ace != null) {
+                    entries.add(ace);
+                }
+            }
+        }
+        return entries;
+    }
+
+    private PolicyEntryImpl createFromNode(NodeImpl node, Principal principal) throws RepositoryException {
+        if (!node.isNodeType(AccessControlConstants.NT_REP_ACE)) {
+            log.warn("Unexpected nodetype. Was not rep:ACE.");
+            return null;
+        }
+
+        boolean allow = node.isNodeType(NT_REP_GRANT_ACE);
+
+        Value[] pValues = node.getProperty(P_PRIVILEGES).getValues();
+        String[] pNames = new String[pValues.length];
+        for (int i = 0; i < pValues.length; i++) {
+            pNames[i] = pValues[i].getString();
+        }
+        int privileges = PrivilegeRegistry.getBits(pNames);
+
+        String nodePath = node.getProperty(P_NODE_PATH).getString();
+        String glob = node.getProperty(P_GLOB).getString();
+
+        // TODO: mk sure principal and principal-name in node match
+
+        return new PolicyEntryImpl(principal, privileges, allow, nodePath, glob);
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedEditor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedEditor.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,352 @@
+/*
+ * 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.combined;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.core.security.authorization.AbstractAccessControlProvider;
+import org.apache.jackrabbit.core.security.authorization.AbstractCompiledPermissions;
+import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
+import org.apache.jackrabbit.core.security.authorization.AccessControlEditor;
+import org.apache.jackrabbit.core.security.authorization.AccessControlProvider;
+import org.apache.jackrabbit.core.security.authorization.CompiledPermissions;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.core.security.authorization.GlobPattern;
+import org.apache.jackrabbit.core.security.authorization.acl.ACLEditor;
+import org.apache.jackrabbit.core.security.jsr283.security.AccessControlEntry;
+import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.util.Text;
+import org.apache.commons.collections.map.ListOrderedMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Node;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.ObservationManager;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.EventIterator;
+import java.security.Principal;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * <code>CombinedProvider</code>...
+ */
+public class CombinedProvider extends AbstractAccessControlProvider implements AccessControlConstants {
+
+    private static Logger log = LoggerFactory.getLogger(CombinedProvider.class);
+
+    // TODO: add means to show effective-policy to a user.
+    // TODO: TOBEFIXED add means to create user-based ACLs (currently editor is not exposed in the API)
+    // TODO: TOBEFIXED proper evaluation of permissions respecting resource-based ACLs.
+    // TODO: TOBEFIXED assert proper evaluation order of group/non-group principal-ACLs
+
+    private SessionImpl session;
+    private ObservationManager obsMgr;
+
+    private CombinedEditor editor;
+    private NodeImpl acRoot;
+
+    protected CombinedProvider() {
+        super("Combined AC policy", "Policy evaluating user-based and resource-based ACLs.");
+    }
+    //----------------------------------------------< AccessControlProvider >---
+    /**
+     * @see AccessControlProvider#init(javax.jcr.Session, java.util.Map)
+     */
+    public void init(Session systemSession, Map options) throws RepositoryException {
+        if (initialized) {
+            throw new IllegalStateException("already initialized");
+        }
+        if (!(systemSession instanceof SessionImpl)) {
+            throw new RepositoryException("SessionImpl (system session) expected.");
+        }
+        session = (SessionImpl) systemSession;
+        obsMgr = session.getWorkspace().getObservationManager();
+
+        String rootPath = acRoot.getPath();
+        editor = new CombinedEditor(session, session.getNamePathResolver(),
+                session.getQPath(rootPath));
+        try {
+            log.info("Install initial ACL:...");
+
+            PrincipalManager pMgr = session.getPrincipalManager();
+            log.info("... Privilege.ALL for administrators.");
+            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);
+            }
+
+            String glob = GlobPattern.WILDCARD_ALL;
+            PolicyTemplateImpl pt = editor.editPolicyTemplate(administrators);
+            pt.setEntry(new PolicyEntryImpl(administrators, PrivilegeRegistry.ALL, true, rootPath, glob));
+            editor.setPolicyTemplate(pt.getNodeId(), pt);
+
+            Principal everyone = pMgr.getEveryone();
+            // TODO: to be improved. how to define where everyone has read-access
+            log.info("... Privilege.READ for everyone.");
+            pt = editor.editPolicyTemplate(everyone);
+            pt.setEntry(new PolicyEntryImpl(everyone, PrivilegeRegistry.READ, true, rootPath, glob));
+            editor.setPolicyTemplate(pt.getNodeId(), pt);
+
+            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;
+        }
+
+
+        NodeImpl root = (NodeImpl) session.getRootNode();
+        if (root.hasNode(N_ACCESSCONTROL)) {
+            // TODO: make sure its a node with the correct nodetype
+            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);
+        }
+        initialized = true;
+    }
+
+    /**
+     * @see AccessControlProvider#getAccessControlEntries(org.apache.jackrabbit.core.NodeId)
+     */
+    public AccessControlEntry[] getAccessControlEntries(NodeId nodeId) throws RepositoryException {
+        checkInitialized();
+        // TODO: TOBEFIXED
+        return new AccessControlEntry[0];
+    }
+
+    /**
+     * @see AccessControlProvider#getEditor(javax.jcr.Session)
+     */
+    public AccessControlEditor getEditor(Session editingSession) {
+        checkInitialized();
+        if (editingSession instanceof SessionImpl) {
+            try {
+                return new CombinedEditor((SessionImpl) editingSession,
+                        session.getNamePathResolver(),
+                        session.getQPath(acRoot.getPath()));
+            } catch (RepositoryException e) {
+                // should never get here
+                log.error("Internal error:", e.getMessage());
+            }
+        }
+
+        log.debug("Unable to createFromNode " + CombinedEditor.class.getName() + ".");
+        return null;
+    }
+
+    /**
+     * @see AccessControlProvider#compilePermissions(Set)
+     */
+    public CompiledPermissions compilePermissions(Set principals) throws ItemNotFoundException, RepositoryException {
+        checkInitialized();
+        if (isAdminOrSystem(principals)) {
+            return getAdminPermissions();
+        } else {
+            // TODO: include the resource-based ACLs!
+            return new CompiledPermissionImpl(principals);
+        }
+    }
+
+    //----------------------------------------< private | package protected >---
+    /**
+     * Test if the given path points to a Node (or an existing or non existing
+     * direct decendant of an existing Node) that stores AC-information
+     *
+     * @param path
+     * @return
+     * @throws RepositoryException
+     */
+    private boolean isAccessControlItem(Path path) throws ItemNotFoundException, RepositoryException {
+        NodeImpl node;
+        String absPath = session.getJCRPath(path);
+        if (session.nodeExists(absPath)) {
+            node = (NodeImpl) session.getNode(absPath);
+        } else {
+            // path points to existing prop or non-existing item (node or prop).
+            String parentPath = Text.getRelativeParent(absPath, 1);
+            if (session.nodeExists(parentPath)) {
+                node = (NodeImpl) session.getNode(parentPath);
+            } else {
+                throw new ItemNotFoundException("No item exists at " + absPath + " nor at its direct ancestor.");
+            }
+        }
+        return node.isNodeType(ACLEditor.NT_REP_ACL) || node.isNodeType(ACLEditor.NT_REP_ACE);
+    }
+
+    /**
+     *
+     * @param principals
+     * @return
+     * @throws RepositoryException
+     */
+    private ACLImpl getACL(Set principals) throws RepositoryException {
+        // 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.
+        Map princToACEs = new ListOrderedMap();
+        Set acPaths = new HashSet();
+        // build acl-hierarchy assuming that principal-order determines the
+        // acl-inheritance.
+        for (Iterator it = principals.iterator(); it.hasNext();) {
+            Principal princ = (Principal) it.next();
+            PolicyTemplateImpl at = editor.getPolicyTemplate(princ);
+            if (at == null) {
+                log.debug("No matching ACL node found for principal " + princ.getName() + " -> principal ignored.");
+            } else {
+                // retrieve the ACEs from the node
+                PolicyEntryImpl[] aces = (PolicyEntryImpl[]) at.getEntries();
+                princToACEs.put(princ, aces);
+
+                Path p = session.getHierarchyManager().getPath(at.getNodeId());
+                acPaths.add(session.getJCRPath(p));
+            }
+        }
+        return new ACLImpl(princToACEs, acPaths);
+    }
+
+    //-----------------------------------------------------< CompiledPolicy >---
+    /**
+     *
+     */
+    private class CompiledPermissionImpl extends AbstractCompiledPermissions
+            implements EventListener {
+
+        private final Set principals;
+        private ACLImpl acl;
+
+        /**
+         * @param principals
+         * @throws RepositoryException
+         */
+        private CompiledPermissionImpl(Set principals) throws RepositoryException {
+
+            this.principals = principals;
+            acl = getACL(principals);
+
+            // TODO: describe
+            // TODO: rather on CombinedProvider? -> but must keep references to the CompiledPermission then....?
+            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)
+            };
+            obsMgr.addEventListener(this, events, acRoot.getPath(), true, null, ntNames, true);
+        }
+
+        //------------------------------------< AbstractCompiledPermissions >---
+        /**
+         * @see AbstractCompiledPermissions#buildResult(Path)
+         */
+        protected Result buildResult(Path absPath) throws RepositoryException {
+            if (!absPath.isAbsolute()) {
+                throw new RepositoryException("Absolute path expected.");
+            }
+
+            String jcrPath = session.getJCRPath(absPath);
+            boolean isAclItem = isAccessControlItem(absPath);
+            
+            int permissions;
+            if (session.itemExists(jcrPath)) {
+                permissions = acl.getPermissions(session.getItem(jcrPath), isAclItem);
+            } else {
+                Node parent = session.getNode(Text.getRelativeParent(jcrPath, 1));
+                String name = session.getJCRName(absPath.getNameElement().getName());
+                permissions = acl.getPermissions(parent, name, isAclItem);
+            }
+            /* privileges can only be determined for existing nodes.
+               not for properties and neither for non-existing nodes. */
+            int privileges = (session.nodeExists(jcrPath)) ? acl.getPrivileges(jcrPath) : PrivilegeRegistry.NO_PRIVILEGE;
+            return new Result(permissions, privileges);
+        }
+
+        //--------------------------------------------< CompiledPermissions >---
+        /**
+         * @see CompiledPermissions#close()
+         */
+        public void close() {
+            try {
+                obsMgr.removeEventListener(this);
+            } catch (RepositoryException e) {
+                log.error("Internal error: ", e.getMessage());
+            }
+            super.close();
+        }
+
+        //--------------------------------------------------< EventListener >---
+        /**
+         * @see EventListener#onEvent(EventIterator)
+         */
+        public void onEvent(EventIterator events) {
+            Set acPaths = acl.getAcPaths();
+            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
+                            reload = false;
+                            break;
+                    }
+
+                }
+
+                // eventually reload the ACL and clear the cache
+                if (reload) {
+                    // reload the acl
+                    acl = getACL(principals);
+                    clearCache();
+                }
+            } catch (RepositoryException e) {
+                // should never get here
+                log.warn("Internal error: ", e.getMessage());
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/PolicyEntryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/PolicyEntryImpl.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/PolicyEntryImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/PolicyEntryImpl.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,172 @@
+/*
+ * 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.combined;
+
+import org.apache.jackrabbit.core.security.authorization.PolicyEntry;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.core.security.authorization.GlobPattern;
+import org.apache.jackrabbit.core.security.jsr283.security.Privilege;
+import org.apache.jackrabbit.core.security.jsr283.security.AccessControlEntry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Item;
+import java.security.Principal;
+
+/**
+ * <code>PolicyEntryImpl</code>...
+ */
+class PolicyEntryImpl implements PolicyEntry {
+
+    private static Logger log = LoggerFactory.getLogger(PolicyEntryImpl.class);
+
+    /**
+     * Privileges defined for this entry.
+     */
+    private final int privileges;
+
+    /**
+     * If the actions contained are allowed or denied
+     */
+    private final boolean allow;
+
+    /**
+     * The Principal of this entry
+     */
+    private final Principal principal;
+
+    private final String nodePath;
+    private final String glob;
+
+    /**
+     * Globbing pattern
+     */
+    private final GlobPattern pattern;
+
+    /**
+     * Hash code being calculated on demand.
+     */
+    private int hashCode = -1;
+
+    /**
+     * Constructs an new entry.
+     *
+     * @param principal
+     * @param privileges
+     * @param allow
+     */
+    PolicyEntryImpl(Principal principal, int privileges, boolean allow,
+                    String nodePath, String glob) {
+        if (principal == null || nodePath == null) {
+            throw new IllegalArgumentException("Neither principal nor nodePath must be null.");
+        }
+        this.principal = principal;
+        this.privileges = privileges;
+        this.allow = allow;
+        this.nodePath = nodePath;
+        this.glob = (glob == null) ? GlobPattern.WILDCARD_ALL : glob;
+
+        pattern = GlobPattern.create(nodePath + "/" +glob);
+    }
+
+    int getPrivilegeBits() {
+        return privileges;
+    }
+
+    String getNodePath() {
+        return nodePath;
+    }
+
+    String getGlob() {
+        return glob;
+    }
+
+    boolean matches(String jcrPath) throws RepositoryException {
+        return pattern.matches(jcrPath);
+    }
+
+    boolean matches(Item item) throws RepositoryException {
+        return pattern.matches(item);
+    }
+
+    //-------------------------------------------------< AccessControlEntry >---
+    /**
+     * @see AccessControlEntry#getPrincipal()
+     */
+    public Principal getPrincipal() {
+        return principal;
+    }
+
+    /**
+     * @see AccessControlEntry#getPrivileges()
+     */
+    public Privilege[] getPrivileges() {
+        return PrivilegeRegistry.getPrivileges(privileges);
+    }
+
+    //--------------------------------------------------------< PolicyEntry >---
+    /**
+     * @return true if all actions contained in this Entry are allowed
+     * @see PolicyEntry#isAllow()
+     */
+    public boolean isAllow() {
+        return allow;
+    }
+
+    //-------------------------------------------------------------< Object >---
+    /**
+     * @see Object#hashCode()
+     */
+    public int hashCode() {
+        if (hashCode == -1) {
+            int h = 17;
+            h = 37 * h + principal.getName().hashCode();
+            h = 37 * h + privileges;
+            h = 37 * h + Boolean.valueOf(allow).hashCode();
+            h = 37 * h + nodePath.hashCode();
+            h = 37 * h + glob.hashCode();
+            hashCode = h;
+        }
+        return hashCode;
+    }
+
+    /**
+     * Returns true if the principal, the allow-flag, all privileges and
+     * the nodepath and the glob string are equal or the same, respectively.
+     *
+     * @param obj
+     * @return
+     * @see Object#equals(Object)
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj instanceof PolicyEntryImpl) {
+            PolicyEntryImpl tmpl = (PolicyEntryImpl) obj;
+            // TODO: check again if comparing principal-name is sufficient
+            return principal.getName().equals(tmpl.principal.getName()) &&
+                   allow == tmpl.allow &&
+                   privileges == tmpl.privileges &&
+                   glob.equals(tmpl.glob);
+        }
+        return false;
+    }
+
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/PolicyEntryImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/PolicyEntryImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/PolicyTemplateImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/PolicyTemplateImpl.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/PolicyTemplateImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/PolicyTemplateImpl.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,133 @@
+/*
+ * 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.combined;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.security.authorization.PolicyEntry;
+import org.apache.jackrabbit.core.security.authorization.PolicyTemplate;
+import org.apache.jackrabbit.core.security.jsr283.security.AccessControlException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
+
+/**
+ * <code>PolicyTemplateImpl</code>...
+ */
+class PolicyTemplateImpl implements PolicyTemplate {
+
+    private static Logger log = LoggerFactory.getLogger(PolicyTemplateImpl.class);
+
+    private final Principal principal;
+    private final NodeId acNodeId;
+    private final List entries = new ArrayList();
+
+
+    PolicyTemplateImpl(List aceTemplates, Principal principal, NodeId acNodeId) {
+        this.principal = principal;
+        this.entries.addAll(aceTemplates);
+        this.acNodeId = acNodeId;
+    }
+
+    NodeId getNodeId() {
+        return acNodeId;
+    }
+
+    Principal getPrincipal() {
+        return principal;
+    }
+
+    //-----------------------------------------------------< PolicyTemplate >---
+
+    public boolean isEmpty() {
+        return entries.isEmpty();
+    }
+
+    public int size() {
+        return entries.size();
+    }
+
+    public PolicyEntry[] getEntries() {
+        return (PolicyEntry[]) entries.toArray(new PolicyEntry[entries.size()]);
+    }
+
+    public boolean setEntry(PolicyEntry entry) throws AccessControlException, RepositoryException {
+        if (entry instanceof PolicyEntryImpl &&
+            principal.equals(entry.getPrincipal())) {
+            return internalAddEntry((PolicyEntryImpl) entry);
+        } else {
+            throw new AccessControlException("Invalid entry.");
+        }
+    }
+
+    public boolean removeEntry(PolicyEntry entry) throws AccessControlException, RepositoryException {
+        return entries.remove(entry);
+    }
+
+    //------------------------------------------------< AccessControlPolicy >---
+    /**
+     * @see org.apache.jackrabbit.core.security.jsr283.security.AccessControlPolicy#getName()
+     */
+    public String getName() throws RepositoryException {
+        return getClass().getName();
+    }
+
+    /**
+     * @see org.apache.jackrabbit.core.security.jsr283.security.AccessControlPolicy#getName()
+     */
+    public String getDescription() throws RepositoryException {
+        return "Template for the user-based ACL: each ACL defining the access permissions for a single principal.";
+    }
+
+    //--------------------------------------------------------------------------
+    /**
+     *
+     * @param entry
+     * @return
+     */
+    private synchronized boolean internalAddEntry(PolicyEntryImpl entry) {
+        if (entries.contains(entry)) {
+            log.debug("Entry is already contained in policy -> no modification.");
+            return false;
+        }
+
+        PolicyEntryImpl existing = null;
+        for (Iterator it = entries.iterator(); it.hasNext() && existing == null;) {
+            PolicyEntryImpl ex = (PolicyEntryImpl) it.next();
+            if (ex.getNodePath().equals(entry.getNodePath()) &&
+                ex.getGlob().equals(entry.getGlob()) &&
+                ex.isAllow() == entry.isAllow()) {
+                log.debug("Replacing existing policy entry: NodePath = " +
+                        entry.getNodePath() +"; Glob = " +
+                        entry.getGlob() + "; Changing privileges from " +
+                        ex.getPrivilegeBits() + " to " + entry.getPrivilegeBits());
+                existing = ex;
+            }
+        }
+
+        if (existing != null) {
+            int index = entries.indexOf(existing);
+            return entries.set(index, entry) != null;
+        } else {
+            return entries.add(entry);
+        }
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/PolicyTemplateImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/PolicyTemplateImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlEntry.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlEntry.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlEntry.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,23 @@
+package org.apache.jackrabbit.core.security.jsr283.security;
+
+import java.security.Principal;
+
+/**
+ * An <code>AccessControlEntry</code> represents the association of one or more
+ * <code>Privilege</code> objects with a specific <code>Principal</code>.
+ *
+ * @since JCR 2.0
+ */
+public interface AccessControlEntry {
+    /**
+     * Returns the principal associated with this access control entry.
+     * @return a <code>Principal</code>.
+     */
+    public Principal getPrincipal();
+
+    /**
+     * Returns the privileges associated with this access control entry.
+     * @return an array of <code>Privilege</code>s.
+     */
+    public Privilege[] getPrivileges();
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlEntry.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlEntry.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlException.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlException.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlException.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlException.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,52 @@
+package org.apache.jackrabbit.core.security.jsr283.security;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Exception thrown by access control related methods of
+ * <code>AccessControlManager</code>.
+ *
+ * @since JCR 2.0
+ */
+public class AccessControlException extends RepositoryException {
+    
+    /**
+     * Constructs a new instance of this class with <code>null</code> as its
+     * detail message.
+     */
+    public AccessControlException() {
+        super();
+    }
+
+    /**
+     * Constructs a new instance of this class with the specified detail
+     * message.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public AccessControlException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new instance of this class with the specified detail
+     * message and root cause.
+     *
+     * @param message   the detail message. The detail message is saved for
+     *                  later retrieval by the {@link #getMessage()} method.
+     * @param rootCause root failure cause
+     */
+    public AccessControlException(String message, Throwable rootCause) {
+        super(message, rootCause);
+    }
+
+    /**
+     * Constructs a new instance of this class with the specified root cause.
+     *
+     * @param rootCause root failure cause
+     */
+    public AccessControlException(Throwable rootCause) {
+        super(rootCause);
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlException.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlManager.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlManager.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlManager.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,330 @@
+package org.apache.jackrabbit.core.security.jsr283.security;
+
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.AccessDeniedException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import java.security.Principal;
+
+/**
+ * The <code>AccessControlManager</code> object is accessed via
+ * {@link javax.jcr.Session#getAccessControlManager()}. It provides methods for:
+ * <ul>
+ * <li>Access control discovery</li>
+ * <li>Assigning access control policies</li>
+ * <li>Assigning access control entries</li>
+ * </ul>
+ *
+ * @since JCR 2.0
+ */
+public interface AccessControlManager {
+
+    /**
+     * Returns the privileges supported for absolute path <code>absPath</code>,
+     * which must be an existing node.
+     * <p/>
+     * This method does not return the privileges held by the session. Instead,
+     * it returns the privileges that the repository supports.
+     *
+     * @param absPath an absolute path.
+     * @return an array of <code>Privilege</code>s.
+     * @throws PathNotFoundException if no node at <code>absPath</code> exists
+     *                               or the session does not have privilege to 
+     *                               retrieve the node.
+     * @throws RepositoryException   if another error occurs.
+     */
+    public Privilege[] getSupportedPrivileges(String absPath)
+            throws PathNotFoundException, RepositoryException;
+
+    /**
+     * Returns whether the session has the specified privileges for absolute
+     * path <code>absPath</code>, which must be an existing node.
+     * <p/>
+     * Testing an aggregate privilege is equivalent to testing each nonaggregate
+     * privilege among the set returned by calling
+     * <code>Privilege.getAggregatePrivileges()</code> for that privilege.
+     *
+     * @param absPath    an absolute path.
+     * @param privileges an array of <code>Privilege</code>s.
+     * @return <code>true</code> if the session has the specified privileges;
+     *         <code>false</code> otherwise.
+     * @throws PathNotFoundException if no node at <code>absPath</code> exists
+     *                               or the session does not have privilege to 
+     *                               retrieve the node.
+     * @throws RepositoryException   if another error occurs.
+     */
+    public boolean hasPrivileges(String absPath, Privilege[] privileges)
+            throws PathNotFoundException, RepositoryException;
+
+    /**
+     * Returns the privileges the session has for absolute path absPath, which
+     * must be an existing node.
+     * <p/>
+     * The returned privileges are those for which {@link #hasPrivileges} would
+     * return <code>true</code>.
+     * 
+     * @param absPath an absolute path.
+     * @return an array of <code>Privilege</code>s.
+     * @throws PathNotFoundException if no node at <code>absPath</code> exists
+     *                               or the session does not have privilege to 
+     *                               retrieve the node.
+     * @throws RepositoryException   if another error occurs.
+     */
+    public Privilege[] getPrivileges(String absPath)
+            throws PathNotFoundException, RepositoryException;
+
+    /**
+     * Returns the <code>AccessControlPolicy</code> that has been set to
+     * the node at <code>absPath</code> or <code>null</code> if no
+     * policy has been set. This method reflects the binding state including
+     * transient policy modifications.
+     * <p/>
+     * Use {@link #getEffectivePolicy(String)} in order to determine the
+     * policy that effectively applies at <code>absPath</code>.
+     *
+     * @param absPath an absolute path.
+     * @return an <code>AccessControlPolicy</code> object or <code>null</code>.
+     * @throws PathNotFoundException if no node at <code>absPath</code> exists
+     *                               or the session does not have privilege to 
+     *                               retrieve the node.
+     * @throws AccessDeniedException if the session lacks
+     *                               <code>GET_ACCESS_CONTROL</code> privilege 
+     *                               for the <code>absPath</code> node.
+     * @throws RepositoryException   if another error occurs.
+     */
+    public AccessControlPolicy getPolicy(String absPath)
+            throws PathNotFoundException, AccessDeniedException, RepositoryException;
+
+    /**
+     * Returns the <code>AccessControlPolicy</code> that currently is in effect 
+     * at the node at <code>absPath</code>. This may be an 
+     * <code>AccessControlPolicy</code> set through this API or some 
+     * implementation specific (default) policy.
+     * </p>
+     *
+     * @param absPath an absolute path.
+     * @return an <code>AccessControlPolicy</code> object.
+     * @throws PathNotFoundException if no node at <code>absPath</code> exists
+     *                               or the session does not have privilege to 
+     *                               retrieve the node.
+     * @throws AccessDeniedException if the session lacks
+     *                               <code>READ_ACCESS_CONTROL</code> privilege 
+     *                               for the <code>absPath</code> node.
+     * @throws RepositoryException   if another error occurs.
+     */
+    public AccessControlPolicy getEffectivePolicy(String absPath)
+            throws PathNotFoundException, AccessDeniedException, RepositoryException;
+
+    /**
+     * Returns the access control policies that are capable of being applied to
+     * the node at <code>absPath</code>.
+     *
+     * @param absPath an absolute path.
+     * @return an <code>AccessControlPolicyIterator</code> over the applicable
+     *         access control policies or an empty iterator if no policies are
+     *         applicable.
+     * @throws PathNotFoundException if no node at <code>absPath</code> exists
+     *                               or the session does not have privilege to 
+     *                               retrieve the node.
+     * @throws AccessDeniedException if the session lacks
+     *                               <code>READ_ACCESS_CONTROL</code> privilege 
+     *                               for the <code>absPath</code> node.
+     * @throws RepositoryException   if another error occurs.
+     */
+    public AccessControlPolicyIterator getApplicablePolicies(String absPath)
+            throws PathNotFoundException, AccessDeniedException, RepositoryException;
+
+    /**
+     * Binds the <code>policy</code> to the node at <code>absPath</code>.
+     * <p/>
+     * Only one policy may be bound at a time. If more than one policy per node 
+     * is required, the implementation should provide an appropriate aggregate 
+     * policy among those returned by <code>getApplicablePolicies(absPath)</code>.
+     * The access control policy does not take effect until a <code>save</code> 
+     * is performed.
+     * <p/>
+     * If the node has access control entries that were bound to it through the 
+     * JCR API prior to the <code>setPolicy</code> call, then these entries may 
+     * be deleted. Any implementation-specific (non-JCR) access control 
+     * settings may be changed in response to a successful call to 
+     * <code>setPolicy</code>.
+     *
+     * @param absPath an absolute path.
+     * @param policy  the <code>AccessControlPolicy</code> to be applied.
+     * @throws PathNotFoundException   if no node at <code>absPath</code> exists
+     *                                 or the session does not have privilege to 
+     *                                 retrieve the node.
+     * @throws AccessControlException  if the policy is not applicable.
+     * @throws AccessDeniedException   if the session lacks
+     *                                 <code>MODIFY_ACCESS_CONTROL</code> 
+     *                                 privilege for the <code>absPath</code> node.
+     * @throws RepositoryException     if another error occurs.
+     */
+    public void setPolicy(String absPath, AccessControlPolicy policy)
+            throws PathNotFoundException, AccessControlException,
+            AccessDeniedException, RepositoryException;
+
+    /**
+     * Removes the <code>AccessControlPolicy</code> from the node at absPath and
+     * returns it.
+     * <p/>
+     * 
+     * An <code>AccessControlPolicy</code> can only be removed if it was
+     * bound to the specified node through this API before. The effect of the 
+     * removal only takes place upon <code>Session.save()</code>. Whichever 
+     * defaults the implementation applies now take effect.
+     * Note, that an implementation default or any other effective 
+     * <code>AccessControlPolicy</code> that has not been applied to the node
+     * before may never be removed using this method.
+     *
+     * @param absPath an absolute path.
+     * @return the removed <code>AccessControlPolicy</code>.
+     * @throws PathNotFoundException   if no node at <code>absPath</code> exists
+     *                                 or the session does not have privilege to 
+     *                                 retrieve the node.
+     * @throws AccessControlException  if no policy exists.
+     * @throws AccessDeniedException   if the session lacks
+     *                                 <code>MODIFY_ACCESS_CONTROL</code> 
+     *                                 privilege for the <code>absPath</code> node.
+     * @throws RepositoryException     if another error occurs.
+     */
+    public AccessControlPolicy removePolicy(String absPath)
+            throws PathNotFoundException, AccessControlException,
+            AccessDeniedException, RepositoryException;
+
+    /**
+     * Returns all access control entries assigned to the node at <code>absPath</code>
+     * including transient modifications made to the entries at <code>absPath</code>.
+     * <p/>
+     * This method is only guaranteed to return an <code>AccessControlEntry</code>
+     * if that <code>AccessControlEntry</code> has been assigned <i>through this API</i>.
+     *
+     * @param absPath an absolute path
+     * @return all access control entries assigned at to specified node.
+     * @throws PathNotFoundException if no node at <code>absPath</code> exists
+     *                               or the session does not have privilege to 
+     *                               retrieve the node.
+     * @throws AccessDeniedException if the session lacks
+     *                               <code>READ_ACCESS_CONTROL</code> privilege 
+     *                               for the <code>absPath</code> node.
+     * @throws UnsupportedRepositoryOperationException if access control
+     *         is not supported.
+     * @throws RepositoryException   if another error occurs.
+     */
+    public AccessControlEntry[] getAccessControlEntries(String absPath)
+            throws PathNotFoundException, AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException;
+
+    /**
+     * Returns the access control entries that are effective at the node at
+     * <code>absPath</code>.
+     * <p/>
+     * This method is intended for information purpose only and should allow
+     * the user to determine which entries are currently used for access control
+     * evaluation.
+     * </p>
+     * If an implementation is not able to determine the effective entries
+     * present at the given node it returns <code>null</code> in order to indicate
+     * that entries exists but the implementation cannot find them. If there
+     * are no entries present at the given node an empty array will be returned.
+     *
+     * @param absPath an absolute path
+     * @return the access control entries that are currently effective at the
+     *         node at <code>absPath</code> or <code>null</code> if the
+     *         implementation is not able to determine the effective entries.
+     * @throws PathNotFoundException if no node at <code>absPath</code> exists
+     *         or the session does not have privilege to retrieve the node.
+     * @throws AccessDeniedException if the session lacks
+     *         <code>READ_ACCESS_CONTROL</code> privilege for the
+     *         <code>absPath</code> node.
+     * @throws UnsupportedRepositoryOperationException if access control
+     *         is not supported.
+     * @throws RepositoryException if another error occurs.
+     */
+    public AccessControlEntry[] getEffectiveAccessControlEntries(String absPath)
+            throws PathNotFoundException, AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException;
+
+
+    /**
+     * Adds the access control entry consisting of the specified
+     * <code>principal</code> and the specified <code>privileges</code> to the
+     * node at <code>absPath</code>.
+     * <p/>
+     * This method returns the <code>AccessControlEntry</code> object constructed from the
+     * specified <code>principal</code> and contains at least the given <code>privileges</code>.
+     * An implementation may return a resulting ACE that combines the given <code>privileges</code>
+     * with those added by a previous call to <code>addAccessControlEntry</code> for the same
+     * <code>Principal</code>. However, a call to <code>addAccessControlEntry</code> for a given
+     * <code>Principal</code> can never remove a <code>Privilege</code> added by a previous call
+     * to <code>addAccessControlEntry</code>.
+     * <p/>
+     * The access control entry does not take effect until a <code>save</code>
+     * is performed.
+     * <p/>
+     * This method is guaranteed to affect only the privileges of the specified
+     * <code>principal</code>.
+     * <p/>
+     * This method <i>may</i> affect the privileges granted to that principal with
+     * respect to nodes other than that specified. However, if it does, it is
+     * guaranteed to only affect the privileges of those other nodes in the
+     * same way as it affects the privileges of the specified node.
+     *
+     * @param absPath    an absolute path.
+     * @param principal  a <code>Principal</code>.
+     * @param privileges an array of <code>Privilege</code>s.
+     * @return the <code>AccessControlEntry</code> object constructed from the
+     *         specified <code>principal</code> and <code>privileges</code>.
+     * @throws PathNotFoundException      if no node at <code>absPath</code> exists
+     *                                    or the session does not have privilege to retrieve the node.
+     * @throws AccessControlException     if the specified principal does not exist,
+     *                                    if any of the specified privileges is not supported at
+     *                                    <code>absPath</code> or if some other access control related
+     *                                    exception occurs.
+     * @throws AccessDeniedException      if the session lacks
+     *                                    <code>MODIFY_ACCESS_CONTROL</code> privilege for the
+     *                                    <code>absPath</code> node.
+     * @throws UnsupportedRepositoryOperationException if access control
+     *         is not supported.
+     * @throws RepositoryException        if another error occurs.
+     */
+    public AccessControlEntry addAccessControlEntry(String absPath,
+                                                    Principal principal,
+                                                    Privilege[] privileges)
+            throws PathNotFoundException, AccessControlException,
+            AccessDeniedException, UnsupportedRepositoryOperationException,
+            RepositoryException;
+
+    /**
+     * Removes the specified <code>AccessControlEntry</code> from the node at
+     * <code>absPath</code>.
+     * <p/>
+     * This method is guaranteed to affect only the privileges of the principal
+     * defined within the passed <code>AccessControlEntry</code>.
+     * <p/>
+     * This method <i>may</i> affect the privileges granted to that principal
+     * with respect to nodes other than that specified. However, if it does,
+     * it is guaranteed to only affect the privileges of those other nodes in
+     * the same way as it affects the privileges of the specified node.
+     * <p/>
+     * Only exactly those entries obtained through 
+     * <code>getAccessControlEntries<code> can be removed. The effect of the 
+     * removal only takes effect upon <code>Session.save()</code>.
+     *
+     * @param absPath an absolute path.
+     * @param ace     the access control entry to be removed.
+     * @throws PathNotFoundException if no node at <code>absPath</code> exists
+     *                               or the session does not have privilege to retrieve the node.
+     * @throws AccessControlException
+     *                               if the specified entry is not
+     *                               present on the specified node.
+     * @throws AccessDeniedException if the session lacks
+     *                               <code>MODIFY_ACCESS_CONTROL</code> privilege for the
+     *                               <code>absPath</code> node.
+     * @throws UnsupportedRepositoryOperationException if access control
+     *         is not supported.
+     * @throws RepositoryException   if another error occurs.
+     */
+    public void removeAccessControlEntry(String absPath, AccessControlEntry ace)
+            throws PathNotFoundException, AccessControlException,
+            AccessDeniedException, UnsupportedRepositoryOperationException,
+            RepositoryException;
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlPolicy.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlPolicy.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlPolicy.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlPolicy.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,34 @@
+package org.apache.jackrabbit.core.security.jsr283.security;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * An <code>AccessControlPolicy</code> is an object with a name and an optional
+ * description. Examples of possible <code>AccessControlPolicy</code> 
+ * implementations include access control lists or role-responsibility 
+ * assignments.
+ *
+ * @since JCR 2.0
+ */
+public interface AccessControlPolicy {
+    /**
+     * Returns the name of the access control policy, which should be unique
+     * among the choices applicable to any particular node.
+     * It is presented to provide an easily identifiable choice for
+     * users choosing a policy to assign to a node.
+     *
+     * @return the name of the access control policy.
+     * @throws RepositoryException if an error occurs.
+     */
+    public String getName() throws RepositoryException;
+
+    /**
+     * Returns a human readable description of the access control policy which
+     * should be sufficient for allowing end users to chose between different
+     * policies to apply to a node.
+     *
+     * @return a human readable description of the access control policy.
+     * @throws RepositoryException if an error occurs.
+     */
+    public String getDescription() throws RepositoryException;
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlPolicy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlPolicy.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlPolicyIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlPolicyIterator.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlPolicyIterator.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlPolicyIterator.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,23 @@
+package org.apache.jackrabbit.core.security.jsr283.security;
+
+import javax.jcr.RangeIterator;
+
+/**
+ * Allows easy iteration through a list of <code>AccessControlPolicy</code>s
+ * with <code>nextAccessControlPolicy</code> as well as a <code>skip</code>
+ * method inherited from <code>RangeIterator</code>.
+ *
+ * @since JCR 2.0
+ */
+public interface AccessControlPolicyIterator extends RangeIterator {
+    
+    /**
+     * Returns the next <code>AccessControlPolicy</code> in the iteration.
+     *
+     * @return the next <code>AccessControlPolicy</code> in the iteration.
+     * @throws java.util.NoSuchElementException if iteration has no more
+     *         <code>AccessControlPolicy</code>s.
+    */
+   public AccessControlPolicy nextAccessControlPolicy();
+
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlPolicyIterator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/AccessControlPolicyIterator.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/Privilege.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/Privilege.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/Privilege.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/Privilege.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,131 @@
+package org.apache.jackrabbit.core.security.jsr283.security;
+
+/**
+ * A privilege represents the capability of performing a particular set
+ * of operations on items in the JCR repository. Each privilege is identified
+ * by a NAME that is unique across the set of privileges supported by a
+ * repository. JCR defines a set of standard privileges in the <code>jcr</code>
+ * namespace. Implementations may add additional privileges in namespaces other
+ * than <code>jcr</code>.
+ * <p/>
+ * A privilege may be an aggregate privilege. Aggregate privileges are sets of
+ * other privileges. Granting, denying, or testing an aggregate privilege is
+ * equivalent to individually granting, denying, or testing each privilege it
+ * contains. The privileges contained by an aggregate privilege may themselves
+ * be aggregate privileges if the resulting privilege graph is acyclic.
+ * <p/>
+ * A privilege may be an abstract privilege. Abstract privileges cannot
+ * themselves be granted or denied, but can be composed into aggregate privileges
+ * which are granted or denied.
+ * <p/>
+ * A privilege can be both aggregate and abstract.
+ *
+ * @since JCR 2.0
+ */
+public interface Privilege {
+
+    /**
+     * A constant representing <code>READ</code>, the privilege to retrieve
+     * a node and get its properties and their values.
+     */
+    public static final String READ = "javax.jcr.security.Privilege.READ";
+
+    /**
+     * A constant representing <code>MODIFY_PROPERTIES</code>, the privilege
+     * to create, modify and remove the properties of a node.
+     */
+    public static final String MODIFY_PROPERTIES = "javax.jcr.security.Privilege.MODIFY_PROPERTIES";
+
+    /**
+     * A constant representing <code>ADD_CHILD_NODES</code>, the privilege
+     * to create child nodes of a node.
+     */
+    public static final String ADD_CHILD_NODES = "javax.jcr.security.Privilege.ADD_CHILD_NODES";
+
+    /**
+     * A constant representing <code>REMOVE_CHILD_NODES</code>, the privilege
+     * to remove child nodes of a node.
+     */
+    public static final String REMOVE_CHILD_NODES = "javax.jcr.security.Privilege.REMOVE_CHILD_NODES";
+
+    /**
+     * A constant representing <code>WRITE</code>, an aggregate privilege that contains:
+     *<ul>
+     *  <li>MODIFY_PROPERTIES</li>
+     *  <li>ADD_CHILD_NODES</li>
+     *  <li>REMOVE_CHILD_NODES</li>
+     * </ul>
+     */
+    public static final String WRITE = "javax.jcr.security.Privilege.WRITE";
+
+    /**
+     * A constant representing <code>READ_ACCESS_CONTROL</code>, the privilege
+     * to get the access control policy of a node.
+     */
+    public static final String READ_ACCESS_CONTROL = "javax.jcr.security.Privilege.READ_ACCESS_CONTROL";
+
+    /**
+     * A constant representing <code>MODIFY_ACCESS_CONTROL</code>, the privilege
+     * to modify the access control policies of a node.
+     */
+    public static final String MODIFY_ACCESS_CONTROL = "javax.jcr.security.Privilege.MODIFY_ACCESS_CONTROL";
+
+    /**
+     * A constant representing <code>ALL</code>, an aggregate privilege that contains
+     * all predefined privileges:
+     * <ul>
+     *   <li>READ</li>
+     *   <li>WRITE</li>
+     *   <li>READ_ACCESS_CONTROL</li>
+     *   <li>MODIFY_ACCESS_CONTROL</li>
+     * </ul>
+     * It should in addition include all implementation-defined privileges.
+     */
+    public static final String ALL = "javax.jcr.security.Privilege.ALL";
+
+    /**
+     * Returns the name of this privilege.
+     *
+     * @return the name of this privilege.
+     */
+    public String getName();
+
+    /**
+     * Returns a description of this privilege.
+     *
+     * @return a description of this privilege.
+     */
+    public String getDescription();
+
+    /**
+     * Returns whether this privilege is an abstract privilege.
+     * @return <code>true</code> if this privilege is an abstract privilege;
+     *         <code>false</code> otherwise.
+     */
+    public boolean isAbstract();
+
+    /**
+     * Returns whether this privilege is an aggregate privilege.
+     * @return <code>true</code> if this privilege is an aggregate privilege;
+     *         <code>false</code> otherwise.
+     */
+    public boolean isAggregate();
+
+    /**
+     * If this privilege is an aggregate privilege, returns the privileges directly
+     * contained by the aggregate privilege. Otherwise returns an empty array.
+     *
+     * @return an array of <code>Privilege</code>s
+     */
+    public Privilege[] getDeclaredAggregatePrivileges();
+
+    /**
+     * If this privilege is an aggregate privilege, returns the privileges it
+     * contains, the privileges contained by any aggregate privileges among
+     * those, and so on (the transitive closure of privileges contained by this
+     * privilege). Otherwise returns an empty array.
+     *
+     * @return an array of <code>Privilege</code>s
+     */
+    public Privilege[] getAggregatePrivileges();
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/Privilege.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/jsr283/security/Privilege.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url