jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r1432118 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/security/authorization/ main/java/org/apache/jackrabbit/oak/spi/security/authorization/ main/java/org/apache/jackrabbit/oak/spi/security/authorization/res...
Date Fri, 11 Jan 2013 16:04:37 GMT
Author: angela
Date: Fri Jan 11 16:04:37 2013
New Revision: 1432118

URL: http://svn.apache.org/viewvc?rev=1432118&view=rev
Log:
OAK-51 : Access Control Management (wip)

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/EmptyRestrictionProvider.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/ACETest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/ImmutableACLTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/ACL.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlManagerImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/ACE.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AbstractAccessControlList.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/ImmutableACL.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/NodeUtil.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/ACL.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/ACL.java?rev=1432118&r1=1432117&r2=1432118&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/ACL.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/ACL.java Fri Jan 11 16:04:37 2013
@@ -23,6 +23,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import javax.annotation.Nonnull;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 import javax.jcr.security.AccessControlEntry;
@@ -33,35 +34,37 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.oak.spi.security.authorization.AbstractAccessControlList;
 import org.apache.jackrabbit.oak.spi.security.authorization.ACE;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.Restriction;
-import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * ACL... TODO
  */
-class ACL extends AbstractAccessControlList {
+abstract class ACL extends AbstractAccessControlList {
 
     private static final Logger log = LoggerFactory.getLogger(ACL.class);
 
-    private final List<JackrabbitAccessControlEntry> entries;
+    private final List<JackrabbitAccessControlEntry> entries = new ArrayList<JackrabbitAccessControlEntry>();
 
-    ACL(String jcrPath, List<JackrabbitAccessControlEntry> entries, RestrictionProvider restrictionProvider) {
-        super(jcrPath, restrictionProvider);
-
-        this.entries = (entries == null) ? new ArrayList<JackrabbitAccessControlEntry>() : entries;
+    ACL(String jcrPath) {
+        this(jcrPath, null);
     }
 
-    JackrabbitAccessControlEntry[] getACEs() {
-        return entries.toArray(new JackrabbitAccessControlEntry[entries.size()]);
+    ACL(String jcrPath, List<JackrabbitAccessControlEntry> entries) {
+        super(jcrPath);
+        if (entries != null) {
+            this.entries.addAll(entries);
+        }
     }
 
-    //--------------------------------------------------< AccessControlList >---
+    @Nonnull
     @Override
-    public AccessControlEntry[] getAccessControlEntries() throws RepositoryException {
-        return getACEs();
+    public List<JackrabbitAccessControlEntry> getEntries() {
+        return entries;
     }
 
+    //--------------------------------------------------< AccessControlList >---
+
     @Override
     public void removeAccessControlEntry(AccessControlEntry ace) throws RepositoryException {
         JackrabbitAccessControlEntry entry = checkACE(ace);
@@ -71,15 +74,6 @@ class ACL extends AbstractAccessControlL
     }
 
     //----------------------------------------< JackrabbitAccessControlList >---
-    @Override
-    public boolean isEmpty() {
-        return entries.isEmpty();
-    }
-
-    @Override
-    public int size() {
-        return entries.size();
-    }
 
     @Override
     public boolean addEntry(Principal principal, Privilege[] privileges,
@@ -92,7 +86,7 @@ class ACL extends AbstractAccessControlL
         } else {
             rs = new HashSet<Restriction>(restrictions.size());
             for (String name : restrictions.keySet()) {
-                rs.add(restrictionProvider.createRestriction(jcrPath, name, restrictions.get(name)));
+                rs.add(getRestrictionProvider().createRestriction(getPath(), name, restrictions.get(name)));
             }
         }
         JackrabbitAccessControlEntry entry = new ACE(principal, privileges, isAllow, rs);
@@ -134,7 +128,6 @@ class ACL extends AbstractAccessControlL
      * This class is mutable and not meant to be used as a hash key.
      *
      * @return always zero
-     * @see Object#hashCode()
      */
     @Override
     public int hashCode() {
@@ -146,7 +139,6 @@ class ACL extends AbstractAccessControlL
      *
      * @param obj Object to test.
      * @return true if the path and the entries are equal; false otherwise.
-     * @see Object#equals(Object)
      */
     @Override
     public boolean equals(Object obj) {
@@ -155,7 +147,8 @@ class ACL extends AbstractAccessControlL
         }
         if (obj instanceof ACL) {
             ACL acl = (ACL) obj;
-            return ((jcrPath == null) ? acl.jcrPath == null : jcrPath.equals(acl.jcrPath))
+            String path = getPath();
+            return ((path == null) ? acl.getPath() == null : path.equals(acl.getPath()))
                     && entries.equals(acl.entries);
         }
         return false;
@@ -164,7 +157,7 @@ class ACL extends AbstractAccessControlL
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("ACL: ").append(jcrPath).append("; ACEs: ");
+        sb.append("ACL: ").append(getPath()).append("; ACEs: ");
         for (AccessControlEntry ace : entries) {
             sb.append(ace.toString()).append(';');
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlManagerImpl.java?rev=1432118&r1=1432117&r2=1432118&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlManagerImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlManagerImpl.java Fri Jan 11 16:04:37 2013
@@ -115,18 +115,12 @@ public class AccessControlManagerImpl im
 
     @Override
     public boolean hasPrivileges(String absPath, Privilege[] privileges) throws RepositoryException {
-        Tree tree = getTree(absPath);
-        checkPermission(tree);
-
         // TODO
         throw new UnsupportedOperationException("Not yet implemented");
     }
 
     @Override
     public Privilege[] getPrivileges(String absPath) throws PathNotFoundException, RepositoryException {
-        Tree tree = getTree(absPath);
-        checkPermission(tree);
-
         // TODO
         throw new UnsupportedOperationException("Not yet implemented");
     }
@@ -134,9 +128,6 @@ public class AccessControlManagerImpl im
     @Override
     public AccessControlPolicy[] getPolicies(String absPath) throws RepositoryException {
         Tree tree = getTree(absPath);
-        checkPermission(tree);
-        checkIsAccessControlContent(tree);
-
         AccessControlPolicy policy = readACL(absPath, tree, false);
         if (policy != null) {
             return new AccessControlPolicy[] {policy};
@@ -148,9 +139,6 @@ public class AccessControlManagerImpl im
     @Override
     public AccessControlPolicy[] getEffectivePolicies(String absPath) throws RepositoryException {
         Tree tree = getTree(absPath);
-        checkPermission(tree);
-        checkIsAccessControlContent(tree);
-
         List<AccessControlPolicy> effective = new ArrayList<AccessControlPolicy>();
         AccessControlPolicy policy = readACL(absPath, tree, true);
         if (policy != null) {
@@ -173,21 +161,18 @@ public class AccessControlManagerImpl im
     @Override
     public AccessControlPolicyIterator getApplicablePolicies(String absPath) throws RepositoryException {
         Tree tree = getTree(absPath);
-        checkPermission(tree);
-        checkIsAccessControlContent(tree);
-
         AccessControlPolicy policy = null;
         NodeUtil aclNode = getAclNode(absPath, tree);
         if (aclNode == null) {
             // create an empty acl unless the node is protected or cannot have
             // mixin set (e.g. due to a lock) or
             // has colliding rep:policy or rep:repoPolicy child node set.
-            String aclName = getAclName(absPath);
+            String aclName = getAclOakName(absPath);
             if (tree.hasChild(aclName)) {
                 // policy child node without node being access controlled
                 log.warn("Colliding policy child without node being access controllable ({}).", absPath);
             } else {
-                String mixinName = getMixinName(absPath);
+                String mixinName = getOakMixinName(absPath);
                 if (ntMgr.isNodeType(tree, mixinName) || ntMgr.getEffectiveNodeType(tree).supportsMixin(mixinName)) {
                     policy = new NodeACL(absPath);
                 } else {
@@ -212,9 +197,6 @@ public class AccessControlManagerImpl im
             throw new RepositoryException("not yet implemented");
         } else {
             Tree tree = getTree(absPath);
-            checkPermission(tree);
-            checkIsAccessControlContent(tree);
-
             NodeUtil aclNode = getAclNode(absPath, tree);
             if (aclNode != null) {
                 // remove all existing aces
@@ -226,9 +208,10 @@ public class AccessControlManagerImpl im
             }
 
             ACL acl = (ACL) policy;
-            for (JackrabbitAccessControlEntry ace : acl.getACEs()) {
-                String nodeName = generateAceName(aclNode, ace.isAllow());
-                String ntName = (ace.isAllow()) ? NT_REP_GRANT_ACE : NT_REP_DENY_ACE;
+            for (JackrabbitAccessControlEntry ace : acl.getEntries()) {
+                boolean isAllow = ace.isAllow();
+                String nodeName = generateAceName(aclNode, isAllow);
+                String ntName = (isAllow) ? NT_REP_GRANT_ACE : NT_REP_DENY_ACE;
 
                 NodeUtil aceNode = aclNode.addChild(nodeName, ntName);
                 aceNode.setString(REP_PRINCIPAL_NAME, ace.getPrincipal().getName());
@@ -247,9 +230,6 @@ public class AccessControlManagerImpl im
             throw new RepositoryException("not yet implemented");
         } else {
             Tree tree = getTree(absPath);
-            checkPermission(tree);
-            checkIsAccessControlContent(tree);
-
             NodeUtil aclNode = getAclNode(absPath, tree);
             if (aclNode != null) {
                 aclNode.getTree().remove();
@@ -299,18 +279,12 @@ public class AccessControlManagerImpl im
 
     @Override
     public boolean hasPrivileges(String absPath, Set<Principal> principals, Privilege[] privileges) throws RepositoryException {
-        Tree tree = getTree(absPath);
-        checkPermission(tree);
-
         // TODO
         throw new UnsupportedOperationException("Not yet implemented");
     }
 
     @Override
     public Privilege[] getPrivileges(String absPath, Set<Principal> principals) throws RepositoryException {
-        Tree tree = getTree(absPath);
-        checkPermission(tree);
-
         // TODO
         throw new UnsupportedOperationException("Not yet implemented");
     }
@@ -331,9 +305,15 @@ public class AccessControlManagerImpl im
         if (tree == null) {
             throw new PathNotFoundException("No tree at " +jcrPath);
         }
+        checkPermission(tree);
+        checkIsAccessControlContent(tree);
         return tree;
     }
 
+    private void checkPermission(Tree tree) throws AccessDeniedException {
+        // TODO
+    }
+
     private void checkValidPath(String jcrPath) throws RepositoryException {
         getTree(jcrPath);
     }
@@ -352,18 +332,12 @@ public class AccessControlManagerImpl im
         }
     }
 
-    private void checkPermission(Tree tree) throws AccessDeniedException {
-        // TODO
-    }
-
-    private void checkValidPolicy(String jcrPath, AccessControlPolicy policy) throws AccessControlException {
-        if (policy instanceof NodeACL) {
-            String path = ((NodeACL) policy).getPath();
+    private static void checkValidPolicy(String jcrPath, AccessControlPolicy policy) throws AccessControlException {
+        if (policy instanceof ACL) {
+            String path = ((ACL) policy).getPath();
             if ((path == null && jcrPath != null) || (path != null && !path.equals(jcrPath))) {
                 throw new AccessControlException("Invalid access control policy " + policy + ": path mismatch " + jcrPath);
             }
-        } if (policy instanceof PrincipalACL) {
-            // TODO: validate
         } else {
             throw new AccessControlException("Invalid access control policy " + policy);
         }
@@ -374,15 +348,16 @@ public class AccessControlManagerImpl im
     }
 
     private boolean isACE(Tree tree) throws RepositoryException {
-        return ntMgr.isNodeType(tree, NT_REP_ACE);
+        return ntMgr.isNodeType(tree, namePathMapper.getJcrName(NT_REP_ACE));
     }
 
     @CheckForNull
     private AccessControlList readACL(String jcrPath, Tree accessControlledTree,
                         boolean isReadOnly) throws RepositoryException {
         AccessControlList acl = null;
-        String aclName = getAclName(jcrPath);
-        String mixinName = getMixinName(jcrPath);
+        String aclName = getAclOakName(jcrPath);
+        String mixinName = getOakMixinName(jcrPath);
+
         if (isAccessControlled(accessControlledTree, mixinName) && accessControlledTree.hasChild(aclName)) {
             Tree aclTree = accessControlledTree.getChild(aclName);
             List<JackrabbitAccessControlEntry> entries = new ArrayList<JackrabbitAccessControlEntry>();
@@ -450,7 +425,8 @@ public class AccessControlManagerImpl im
     @Nonnull
     private NodeUtil createAclTree(String jcrPath, Tree tree) throws RepositoryException {
         NodeUtil node = new NodeUtil(tree);
-        String mixinName = getMixinName(jcrPath);
+        String mixinName = getOakMixinName(jcrPath);
+
         if (!isAccessControlled(tree, mixinName)) {
             PropertyState mixins = tree.getProperty(JcrConstants.JCR_MIXINTYPES);
             if (mixins == null) {
@@ -461,7 +437,7 @@ public class AccessControlManagerImpl im
                 tree.setProperty(pb.getPropertyState());
             }
         }
-        return node.addChild(getAclName(jcrPath), NT_REP_ACL);
+        return node.addChild(getAclOakName(jcrPath), namePathMapper.getJcrName(NT_REP_ACL));
     }
 
     @Nonnull
@@ -509,17 +485,17 @@ public class AccessControlManagerImpl im
 
     @CheckForNull
     private static NodeUtil getAclNode(String jcrPath, Tree accessControlledTree) {
-        Tree policyTree = accessControlledTree.getChild(getAclName(jcrPath));
+        Tree policyTree = accessControlledTree.getChild(getAclOakName(jcrPath));
         return (policyTree == null) ? null : new NodeUtil(policyTree);
     }
 
     @Nonnull
-    private static String getMixinName(String jcrPath) {
+    private static String getOakMixinName(String jcrPath) {
         return (jcrPath == null) ? MIX_REP_REPO_ACCESS_CONTROLLABLE : MIX_REP_ACCESS_CONTROLLABLE;
     }
 
     @Nonnull
-    private static String getAclName(String jcrPath) {
+    private static String getAclOakName(String jcrPath) {
         return (jcrPath == null) ? REP_REPO_POLICY : REP_POLICY;
     }
 
@@ -543,24 +519,36 @@ public class AccessControlManagerImpl im
     }
 
     //--------------------------------------------------------------------------
+    // TODO review again
     private class NodeACL extends ACL {
 
-        private NodeACL(String jcrPath) {
-            this(jcrPath, null);
+        NodeACL(String jcrPath) {
+            super(jcrPath);
         }
 
-        private NodeACL(String jcrPath, List<JackrabbitAccessControlEntry> entries) {
-            super(jcrPath, entries, AccessControlManagerImpl.this.restrictionProvider);
+        NodeACL(String jcrPath, List<JackrabbitAccessControlEntry> entries) {
+            super(jcrPath, entries);
         }
-    }
 
-    //--------------------------------------------------------------------------
-    // TODO review again
+        @Nonnull
+        @Override
+        public RestrictionProvider getRestrictionProvider() {
+            return restrictionProvider;
+        }
+    }
 
     private class PrincipalACL extends ACL {
 
+        private final RestrictionProvider restrictionProvider;
         private PrincipalACL(String jcrPath, List<JackrabbitAccessControlEntry> entries, RestrictionProvider restrictionProvider) {
-            super(jcrPath, entries, restrictionProvider);
+            super(jcrPath, entries);
+            this.restrictionProvider = restrictionProvider;
+        }
+
+        @Nonnull
+        @Override
+        public RestrictionProvider getRestrictionProvider() {
+            return restrictionProvider;
         }
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/ACE.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/ACE.java?rev=1432118&r1=1432117&r2=1432118&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/ACE.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/ACE.java Fri Jan 11 16:04:37 2013
@@ -18,9 +18,13 @@ package org.apache.jackrabbit.oak.spi.se
 
 import java.security.Principal;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
+import javax.jcr.security.AccessControlException;
 import javax.jcr.security.Privilege;
 
 import com.google.common.base.Function;
@@ -39,15 +43,29 @@ public class ACE implements JackrabbitAc
     private final boolean isAllow;
     private final Set<Restriction> restrictions;
 
+    private Set<String> aggrPrivNames;
     private int hashCode;
 
     public ACE(Principal principal, Privilege[] privileges,
-               boolean isAllow, Set<Restriction> restrictions) {
+               boolean isAllow, Set<Restriction> restrictions) throws AccessControlException {
         this(principal, ImmutableSet.copyOf(privileges), isAllow, restrictions);
     }
 
     public ACE(Principal principal, Set<Privilege> privileges,
-               boolean isAllow, Set<Restriction> restrictions) {
+               boolean isAllow, Set<Restriction> restrictions) throws AccessControlException {
+        if (principal == null || privileges == null) {
+            throw new AccessControlException();
+        }
+        // make sure no abstract privileges are passed.
+        for (Privilege privilege : privileges) {
+            if (privilege == null) {
+                throw new AccessControlException("Privilege " + privilege + " is null.");
+            }
+            if (privilege.isAbstract()) {
+                throw new AccessControlException("Privilege " + privilege + " is abstract.");
+            }
+        }
+
         this.principal = principal;
         this.privileges = ImmutableSet.copyOf(privileges);
         this.isAllow = isAllow;
@@ -55,11 +73,13 @@ public class ACE implements JackrabbitAc
     }
 
     //-------------------------------------------------< AccessControlEntry >---
+    @Nonnull
     @Override
     public Principal getPrincipal() {
         return principal;
     }
 
+    @Nonnull
     @Override
     public Privilege[] getPrivileges() {
         return privileges.toArray(new Privilege[privileges.size()]);
@@ -71,6 +91,7 @@ public class ACE implements JackrabbitAc
         return isAllow;
     }
 
+    @Nonnull
     @Override
     public String[] getRestrictionNames() throws RepositoryException {
         return Collections2.transform(restrictions, new Function<Restriction, String>() {
@@ -81,6 +102,7 @@ public class ACE implements JackrabbitAc
         }).toArray(new String[restrictions.size()]);
     }
 
+    @CheckForNull
     @Override
     public Value getRestriction(String restrictionName) throws RepositoryException {
         for (Restriction restriction : restrictions) {
@@ -97,15 +119,12 @@ public class ACE implements JackrabbitAc
      */
     @Override
     public int hashCode() {
-        if (hashCode == -1) {
+        if (hashCode == 0) {
             hashCode = buildHashCode();
         }
         return hashCode;
     }
 
-    /**
-     * @see Object#equals(Object)
-     */
     @Override
     public boolean equals(Object obj) {
         if (obj == this) {
@@ -114,16 +133,13 @@ public class ACE implements JackrabbitAc
         if (obj instanceof ACE) {
             ACE other = (ACE) obj;
             return principal.equals(other.principal) &&
-                   privileges.equals(other.privileges) &&
+                   aggrPrivNames().equals(other.aggrPrivNames()) &&
                    isAllow == other.isAllow &&
                    restrictions.equals(other.restrictions);
         }
         return false;
     }
 
-    /**
-     * @see Object#toString()
-     */
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -141,9 +157,27 @@ public class ACE implements JackrabbitAc
     private int buildHashCode() {
         int h = 17;
         h = 37 * h + principal.hashCode();
-        h = 37 * h + privileges.hashCode();
+        h = 37 * h + aggrPrivNames().hashCode();
         h = 37 * h + Boolean.valueOf(isAllow).hashCode();
         h = 37 * h + restrictions.hashCode();
         return h;
     }
+
+    private Set<String> aggrPrivNames() {
+        if (aggrPrivNames == null) {
+            aggrPrivNames = new HashSet<String>();
+            for (Privilege priv : privileges) {
+                if (priv.isAggregate()) {
+                    for (Privilege aggr : priv.getAggregatePrivileges()) {
+                        if (!aggr.isAggregate()) {
+                           aggrPrivNames.add(aggr.getName());
+                        }
+                    }
+                } else {
+                    aggrPrivNames.add(priv.getName());
+                }
+            }
+        }
+        return aggrPrivNames;
+    }
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AbstractAccessControlList.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AbstractAccessControlList.java?rev=1432118&r1=1432117&r2=1432118&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AbstractAccessControlList.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AbstractAccessControlList.java Fri Jan 11 16:04:37 2013
@@ -18,14 +18,19 @@ package org.apache.jackrabbit.oak.spi.se
 
 import java.security.Principal;
 import java.util.Collections;
+import java.util.List;
 import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
+import javax.jcr.security.AccessControlEntry;
 import javax.jcr.security.Privilege;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Collections2;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionDefinition;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
@@ -35,15 +40,21 @@ import org.apache.jackrabbit.oak.spi.sec
  */
 public abstract class AbstractAccessControlList implements JackrabbitAccessControlList {
 
-    protected final String jcrPath;
-    protected final RestrictionProvider restrictionProvider;
+    private final String jcrPath;
 
-    public AbstractAccessControlList(String jcrPath, RestrictionProvider restrictionProvider) {
+    public AbstractAccessControlList(String jcrPath) {
         this.jcrPath = jcrPath;
-        this.restrictionProvider = restrictionProvider;
     }
 
+    //------------------------------------------< AbstractAccessControlList >---
+    @Nonnull
+    public abstract List<JackrabbitAccessControlEntry> getEntries();
+
+    @Nonnull
+    public abstract RestrictionProvider getRestrictionProvider();
+
     //--------------------------------------< JackrabbitAccessControlPolicy >---
+    @CheckForNull
     @Override
     public String getPath() {
         return jcrPath;
@@ -52,14 +63,32 @@ public abstract class AbstractAccessCont
     //--------------------------------------------------< AccessControlList >---
 
     @Override
+    public AccessControlEntry[] getAccessControlEntries() throws RepositoryException {
+        List<JackrabbitAccessControlEntry> entries = getEntries();
+        return entries.toArray(new AccessControlEntry[entries.size()]);
+    }
+
+    @Override
     public boolean addAccessControlEntry(Principal principal, Privilege[] privileges) throws RepositoryException {
         return addEntry(principal, privileges, true, Collections.<String, Value>emptyMap());
     }
 
     //----------------------------------------< JackrabbitAccessControlList >---
+
+    @Override
+    public boolean isEmpty() {
+        return getEntries().isEmpty();
+    }
+
+    @Override
+    public int size() {
+        return getEntries().size();
+    }
+
+    @Nonnull
     @Override
     public String[] getRestrictionNames() throws RepositoryException {
-        Set<RestrictionDefinition> supported = restrictionProvider.getSupportedRestrictions(jcrPath);
+        Set<RestrictionDefinition> supported = getRestrictionProvider().getSupportedRestrictions(jcrPath);
         return Collections2.transform(supported, new Function<RestrictionDefinition, String>() {
             @Override
             public String apply(RestrictionDefinition definition) {
@@ -71,7 +100,7 @@ public abstract class AbstractAccessCont
 
     @Override
     public int getRestrictionType(String restrictionName) throws RepositoryException {
-        for (RestrictionDefinition definition : restrictionProvider.getSupportedRestrictions(jcrPath)) {
+        for (RestrictionDefinition definition : getRestrictionProvider().getSupportedRestrictions(jcrPath)) {
             if (definition.getJcrName().equals(restrictionName)) {
                 return definition.getRequiredType();
             }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/ImmutableACL.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/ImmutableACL.java?rev=1432118&r1=1432117&r2=1432118&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/ImmutableACL.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/ImmutableACL.java Fri Jan 11 16:04:37 2013
@@ -17,7 +17,6 @@
 package org.apache.jackrabbit.oak.spi.security.authorization;
 
 import java.security.Principal;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -28,7 +27,8 @@ import javax.jcr.security.AccessControlE
 import javax.jcr.security.Privilege;
 
 import com.google.common.collect.ImmutableList;
-import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.EmptyRestrictionProvider;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
 
 /**
@@ -37,31 +37,31 @@ import org.apache.jackrabbit.oak.spi.sec
  */
 public class ImmutableACL extends AbstractAccessControlList {
 
-    private final List<AccessControlEntry> entries;
+    private final List<JackrabbitAccessControlEntry> entries;
+    private final RestrictionProvider restrictionProvider;
 
     private int hashCode;
 
     /**
      * Construct a new {@code UnmodifiableAccessControlList}
      *
-     * @param jcrPath
-     * @param entries
-     * @param restrictionProvider
+     * @param jcrPath The JCR path of this policy.
+     * @param entries The access control entries contained in this policy.
+     * @param restrictionProvider The restriction provider.
      */
-    public ImmutableACL(String jcrPath, List<? extends AccessControlEntry> entries,
+    public ImmutableACL(String jcrPath, List<? extends JackrabbitAccessControlEntry> entries,
                         RestrictionProvider restrictionProvider) {
-        super(jcrPath, restrictionProvider);
-        this.entries = (entries == null) ? Collections.<AccessControlEntry>emptyList() : ImmutableList.copyOf(entries);
+        super(jcrPath);
+
+        this.entries = (entries == null) ?
+                Collections.<JackrabbitAccessControlEntry>emptyList() :
+                ImmutableList.copyOf(entries);
+        this.restrictionProvider = (restrictionProvider == null) ? new EmptyRestrictionProvider() : restrictionProvider;
     }
 
     //--------------------------------------------------< AccessControlList >---
 
     @Override
-    public AccessControlEntry[] getAccessControlEntries() throws RepositoryException {
-        return entries.toArray(new AccessControlEntry[entries.size()]);
-    }
-
-    @Override
     public void removeAccessControlEntry(AccessControlEntry ace)
             throws AccessControlException, RepositoryException {
         throw new AccessControlException("Immutable ACL. Use AccessControlManager#getApplicablePolicies in order to obtain an modifiable ACL.");
@@ -70,24 +70,25 @@ public class ImmutableACL extends Abstra
     //----------------------------------------< JackrabbitAccessControlList >---
 
     @Override
-    public boolean isEmpty() {
-        return entries.isEmpty();
+    public boolean addEntry(Principal principal, Privilege[] privileges,
+                            boolean isAllow, Map<String, Value> restrictions) throws AccessControlException {
+        throw new AccessControlException("Immutable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicies in order to obtain an modifiable ACL.");
     }
 
     @Override
-    public int size() {
-        return entries.size();
+    public void orderBefore(AccessControlEntry srcEntry, AccessControlEntry destEntry) throws AccessControlException {
+        throw new AccessControlException("Immutable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicy in order to obtain a modifiable ACL.");
     }
 
+    //------------------------------------------< AbstractAccessControlList >---
     @Override
-    public boolean addEntry(Principal principal, Privilege[] privileges,
-                            boolean isAllow, Map<String, Value> restrictions) throws AccessControlException {
-        throw new AccessControlException("Immutable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicies in order to obtain an modifiable ACL.");
+    public List<JackrabbitAccessControlEntry> getEntries() {
+        return entries;
     }
 
     @Override
-    public void orderBefore(AccessControlEntry srcEntry, AccessControlEntry destEntry) throws AccessControlException {
-        throw new AccessControlException("Immutable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicy in order to obtain a modifiable ACL.");
+    public RestrictionProvider getRestrictionProvider() {
+        return restrictionProvider;
     }
 
     //-------------------------------------------------------------< Object >---
@@ -109,14 +110,11 @@ public class ImmutableACL extends Abstra
         if (obj == this) {
             return true;
         }
-        if (obj instanceof JackrabbitAccessControlList) {
-            try {
-                JackrabbitAccessControlList acl = (JackrabbitAccessControlList) obj;
-                return ((jcrPath == null) ? acl.getPath() == null : jcrPath.equals(acl.getPath()))
-                        && entries.equals(Arrays.asList(acl.getAccessControlEntries()));
-            } catch (RepositoryException e) {
-                // failed to retrieve access control entries -> objects are not equal.
-            }
+        if (obj instanceof ImmutableACL) {
+            ImmutableACL other = (ImmutableACL) obj;
+            String path = getPath();
+            return ((path == null) ? other.getPath() == null : path.equals(other.getPath()))
+                    && entries.equals(other.entries);
         }
         return false;
     }

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/EmptyRestrictionProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/EmptyRestrictionProvider.java?rev=1432118&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/EmptyRestrictionProvider.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/EmptyRestrictionProvider.java Fri Jan 11 16:04:37 2013
@@ -0,0 +1,75 @@
+/*
+ * 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.oak.spi.security.authorization.restriction;
+
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.security.AccessControlException;
+
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * DefaultRestrictionProvider... TODO
+ */
+public class EmptyRestrictionProvider implements RestrictionProvider {
+
+    /**
+     * logger instance
+     */
+    private static final Logger log = LoggerFactory.getLogger(EmptyRestrictionProvider.class);
+
+    @Nonnull
+    @Override
+    public Set<RestrictionDefinition> getSupportedRestrictions(String jcrPath) {
+        return Collections.emptySet();
+    }
+
+    @Nonnull
+    @Override
+    public Restriction createRestriction(String jcrPath, String jcrName, Value value) throws RepositoryException {
+        throw new AccessControlException("Unsupported restriction " + jcrName);
+    }
+
+    @Nonnull
+    @Override
+    public Set<Restriction> readRestrictions(String jcrPath, Tree aceTree) throws AccessControlException {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public void writeRestrictions(String jcrPath, Tree aceTree, Set<Restriction> restrictions) throws AccessControlException {
+        if (!restrictions.isEmpty()) {
+            throw new AccessControlException("Implementation doesn't supported restrictions.");
+        }
+    }
+
+    @Override
+    public void writeRestrictions(String jcrPath, Tree aceTree, JackrabbitAccessControlEntry ace) throws AccessControlException {
+        throw new AccessControlException("Implementation doesn't supported restrictions.");
+    }
+
+    @Override
+    public void validateRestrictions(String jcrPath, Tree aceTree) throws AccessControlException {
+        // nothing to do.
+    }
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/NodeUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/NodeUtil.java?rev=1432118&r1=1432117&r2=1432118&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/NodeUtil.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/NodeUtil.java Fri Jan 11 16:04:37 2013
@@ -27,6 +27,7 @@ import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 import javax.jcr.ValueFactory;
 
+import com.google.common.base.Function;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import org.apache.jackrabbit.JcrConstants;
@@ -37,8 +38,10 @@ import org.apache.jackrabbit.oak.api.Typ
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.namepath.NameMapper;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryPropertyBuilder;
 import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
 import org.apache.jackrabbit.oak.plugins.value.Conversions;
+import org.apache.jackrabbit.oak.spi.state.PropertyBuilder;
 import org.apache.jackrabbit.util.Text;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -121,10 +124,20 @@ public class NodeUtil {
     }
 
     /**
-     * FIXME: workaround for OAK-426
-     * FIXME: does probably no work as intended
-     * rootNode.getOrAddTree("a/b/../../c/d/../../e/f", "");
-     * adds the three sub trees /a/b, /c/d and /e/f.
+     * TODO: clean up. workaround for OAK-426
+     *
+     * Create the tree at the specified relative path including all missing
+     * intermediate trees using the specified {@code primaryTypeName}. This
+     * method treats ".." parent element and "." as current element and
+     * resolves them accordingly; in case of a relative path containing parent
+     * elements this may lead to tree creating outside the tree structure
+     * defined by this {@code NodeUtil}.
+     *
+     * @param relativePath A relative OAK path that may contain parent and
+     * current elements.
+     * @param primaryTypeName A oak name of a primary node type that is used
+     * to create the missing trees.
+     * @return The node util of the tree at the specified {@code relativePath}.
      */
     @Nonnull
     public NodeUtil getOrAddTree(String relativePath, String primaryTypeName) {
@@ -135,13 +148,11 @@ public class NodeUtil {
             if (location.getTree() == null) {
                 NodeUtil target = this;
                 for (String segment : Text.explode(relativePath, '/')) {
-                    if (PathUtils.denotesCurrent(segment)) {
-                        continue;
-                    } else if (PathUtils.denotesParent(segment)) {
+                    if (PathUtils.denotesParent(segment)) {
                         target = target.getParent();
                     } else if (target.hasChild(segment)) {
                         target = target.getChild(segment);
-                    } else {
+                    } else if (!PathUtils.denotesCurrent(segment)) {
                         target = target.addChild(segment, primaryTypeName);
                     }
                 }
@@ -218,14 +229,14 @@ public class NodeUtil {
         }
     }
 
-    public void setName(String name, String value) {
+    public void setName(String propertyName, String value) {
         String oakName = getOakName(value);
-        tree.setProperty(name, oakName, NAME);
+        tree.setProperty(propertyName, oakName, NAME);
     }
 
     @CheckForNull
-    public String[] getNames(String name, String... defaultValues) {
-        String[] strings = getStrings(name);
+    public String[] getNames(String propertyName, String... defaultValues) {
+        String[] strings = getStrings(propertyName);
         if (strings == null) {
             strings = defaultValues;
         }
@@ -235,8 +246,13 @@ public class NodeUtil {
         return strings;
     }
 
-    public void setNames(String name, String... values) {
-        tree.setProperty(name, Arrays.asList(values), NAMES);
+    public void setNames(String propertyName, String... values) {
+        tree.setProperty(propertyName, Lists.transform(Arrays.asList(values), new Function<String, String>() {
+            @Override
+            public String apply(String jcrName) {
+                return getOakName(jcrName);
+            }
+        }), NAMES);
     }
 
     public void setDate(String name, long time) {
@@ -254,10 +270,6 @@ public class NodeUtil {
         }
     }
 
-    public void setLong(String name, long value) {
-        tree.setProperty(name, value);
-    }
-
     @Nonnull
     public List<NodeUtil> getNodes(String namePrefix) {
         List<NodeUtil> nodes = Lists.newArrayList();
@@ -278,10 +290,6 @@ public class NodeUtil {
         }
     }
 
-    public void setValues(String name, String[] values, int type) {
-        tree.setProperty(name, Arrays.asList(values), STRINGS);
-    }
-
     @CheckForNull
     public Value[] getValues(String name, ValueFactory vf) {
         PropertyState property = tree.getProperty(name);
@@ -303,11 +311,10 @@ public class NodeUtil {
 
     @Nonnull
     private String getOakName(String jcrName) {
-        String oakName = mapper.getOakName(jcrName);
+        String oakName = (jcrName == null) ? null : mapper.getOakName(jcrName);
         if (oakName == null) {
             throw new IllegalArgumentException(new RepositoryException("Invalid name:" + jcrName));
         }
         return oakName;
     }
-
 }

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/ACETest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/ACETest.java?rev=1432118&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/ACETest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/ACETest.java Fri Jan 11 16:04:37 2013
@@ -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.oak.spi.security.authorization;
+
+import java.security.AccessControlException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.Privilege;
+
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
+import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.security.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.security.authorization.AccessControlManagerImpl;
+import org.apache.jackrabbit.oak.security.privilege.PrivilegeConstants;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * ACETest... TODO
+ */
+public class ACETest extends AbstractSecurityTest {
+
+    private Principal testPrincipal;
+    private AccessControlManager acMgr;
+    private PrivilegeManager privMgr;
+
+    @Before
+    public void before() throws Exception {
+        super.before();
+        testPrincipal = new Principal() {
+            public String getName() {
+                return "TestPrincipal";
+            }
+        };
+        Root root = adminSession.getLatestRoot();
+        // TODO
+        //acMgr = securityProvider.getAccessControlConfiguration().getAccessControlManager(root, NamePathMapper.DEFAULT);
+        acMgr = new AccessControlManagerImpl(root, NamePathMapper.DEFAULT, getSecurityProvider());
+        privMgr = securityProvider.getPrivilegeConfiguration().getPrivilegeManager(root, NamePathMapper.DEFAULT);
+    }
+
+    private ACE createEntry(String[] privilegeNames, boolean isAllow)
+            throws RepositoryException {
+        Privilege[] privs = AccessControlUtils.privilegesFromNames(acMgr, privilegeNames);
+        return createEntry(testPrincipal, privs, isAllow);
+    }
+
+    private ACE createEntry(Principal principal, Privilege[] privileges, boolean isAllow) throws javax.jcr.security.AccessControlException {
+        return new ACE(principal, privileges, isAllow, null);
+    }
+
+    @Test
+    public void testIsAllow() throws RepositoryException {
+        ACE ace = createEntry(new String[] {PrivilegeConstants.JCR_READ}, true);
+        assertTrue(ace.isAllow());
+
+        ace = createEntry(new String[] {PrivilegeConstants.JCR_READ}, false);
+        assertFalse(ace.isAllow());
+    }
+
+    @Test
+    public void testGetPrincipal() throws RepositoryException {
+        ACE tmpl = createEntry(new String[] {PrivilegeConstants.JCR_READ}, true);
+        assertNotNull(tmpl.getPrincipal());
+        assertEquals(testPrincipal.getName(), tmpl.getPrincipal().getName());
+        assertSame(testPrincipal, tmpl.getPrincipal());
+    }
+
+    @Test
+    public void testGetPrivileges() throws RepositoryException {
+        ACE entry = createEntry(new String[] {PrivilegeConstants.JCR_READ}, true);
+
+        Privilege[] privs = entry.getPrivileges();
+        assertNotNull(privs);
+        assertEquals(1, privs.length);
+        assertEquals(privs[0], acMgr.privilegeFromName(PrivilegeConstants.JCR_READ));
+
+        entry = createEntry(new String[]{PrivilegeConstants.REP_WRITE}, true);
+        privs = entry.getPrivileges();
+        assertNotNull(privs);
+        assertEquals(1, privs.length);
+        assertEquals(privs[0], acMgr.privilegeFromName(PrivilegeConstants.REP_WRITE));
+
+        entry = createEntry(new String[] {PrivilegeConstants.JCR_ADD_CHILD_NODES,
+                PrivilegeConstants.JCR_REMOVE_CHILD_NODES}, true);
+        privs = entry.getPrivileges();
+        assertNotNull(privs);
+        assertEquals(2, privs.length);
+
+        Privilege[] expected = AccessControlUtils.privilegesFromNames(acMgr,
+                PrivilegeConstants.JCR_ADD_CHILD_NODES,
+                PrivilegeConstants.JCR_REMOVE_CHILD_NODES);
+        assertEquals(Arrays.asList(expected), Arrays.asList(privs));
+    }
+
+    @Test
+    public void testEquals() throws RepositoryException  {
+
+        Map<AccessControlEntry, AccessControlEntry> equalAces = new HashMap<AccessControlEntry, AccessControlEntry>();
+
+        ACE ace = createEntry(new String[] {PrivilegeConstants.JCR_ALL}, true);
+        // create same entry again
+        equalAces.put(ace, createEntry(new String[] {PrivilegeConstants.JCR_ALL}, true));
+
+        // create entry with declared aggregate privileges
+        Privilege[] declaredAllPrivs = acMgr.privilegeFromName(PrivilegeConstants.JCR_ALL).getDeclaredAggregatePrivileges();
+        equalAces.put(ace, createEntry(testPrincipal, declaredAllPrivs, true));
+
+        // create entry with aggregate privileges
+        Privilege[] aggregateAllPrivs = acMgr.privilegeFromName(PrivilegeConstants.JCR_ALL).getAggregatePrivileges();
+        equalAces.put(ace, createEntry(testPrincipal, aggregateAllPrivs, true));
+
+        // create entry with different privilege order
+        List<Privilege> reordered = new ArrayList<Privilege>(Arrays.asList(aggregateAllPrivs));
+        reordered.add(reordered.remove(0));
+        equalAces.put(createEntry(testPrincipal, reordered.toArray(new Privilege[reordered.size()]), true),
+                      createEntry(testPrincipal, aggregateAllPrivs, true));
+
+        // even if entries are build with aggregated or declared aggregate privileges
+        equalAces.put(createEntry(testPrincipal, declaredAllPrivs, true),
+                createEntry(testPrincipal, aggregateAllPrivs, true));
+
+        for (AccessControlEntry entry : equalAces.keySet()) {
+            assertEquals(entry, equalAces.get(entry));
+        }
+    }
+
+    @Test
+    public void testNotEquals() throws RepositoryException  {
+        ACE ace = createEntry(new String[] {PrivilegeConstants.JCR_ALL}, true);
+        List<JackrabbitAccessControlEntry> otherAces = new ArrayList<JackrabbitAccessControlEntry>();
+
+        try {
+            // ACE template with different principal
+            Principal princ = new Principal() {
+                public String getName() {
+                    return "a name";
+                }
+            };
+            Privilege[] privs = new Privilege[] {
+                    acMgr.privilegeFromName(PrivilegeConstants.JCR_ALL)
+            };
+            otherAces.add(createEntry(princ, privs, true));
+        } catch (RepositoryException e) {
+        }
+
+        // ACE template with different privileges
+        try {
+            otherAces.add(createEntry(new String[] {PrivilegeConstants.JCR_READ}, true));
+        } catch (RepositoryException e) {
+        }
+        // ACE template with different 'allow' flag
+        try {
+            otherAces.add(createEntry(new String[] {PrivilegeConstants.JCR_ALL}, false));
+        } catch (RepositoryException e) {
+        }
+        // ACE template with different privileges and 'allows
+        try {
+            otherAces.add(createEntry(new String[] {PrivilegeConstants.REP_WRITE}, false));
+        } catch (RepositoryException e) {
+        }
+
+        // other ace impl
+        final Privilege[] privs = new Privilege[] {
+                acMgr.privilegeFromName(PrivilegeConstants.JCR_ALL)
+        };
+
+        JackrabbitAccessControlEntry pe = new JackrabbitAccessControlEntry() {
+            public boolean isAllow() {
+                return true;
+            }
+            public String[] getRestrictionNames() {
+                return new String[0];
+            }
+            public Value getRestriction(String restrictionName) {
+                return null;
+            }
+            public Principal getPrincipal() {
+                return testPrincipal;
+            }
+            public Privilege[] getPrivileges() {
+                return privs;
+            }
+        };
+        otherAces.add(pe);
+
+        for (JackrabbitAccessControlEntry otherAce : otherAces) {
+            assertFalse(ace.equals(otherAce));
+        }
+    }
+
+    @Test
+    public void testHashCode() throws RepositoryException  {
+
+        Map<AccessControlEntry, AccessControlEntry> equivalent = new HashMap<AccessControlEntry, AccessControlEntry>();
+        JackrabbitAccessControlEntry ace = createEntry(new String[] {PrivilegeConstants.JCR_ALL}, true);
+        // create same entry again
+        equivalent.put(ace, createEntry(new String[] {PrivilegeConstants.JCR_ALL}, true));
+        // create entry with declared aggregate privileges
+        Privilege[] declaredAllPrivs = acMgr.privilegeFromName(PrivilegeConstants.JCR_ALL).getDeclaredAggregatePrivileges();
+        equivalent.put(ace, createEntry(testPrincipal, declaredAllPrivs, true));
+        // create entry with aggregate privileges
+        Privilege[] aggregateAllPrivs = acMgr.privilegeFromName(PrivilegeConstants.JCR_ALL).getAggregatePrivileges();
+        equivalent.put(ace, createEntry(testPrincipal, aggregateAllPrivs, true));
+        // create entry with different privilege order
+        List<Privilege> reordered = new ArrayList<Privilege>(Arrays.asList(aggregateAllPrivs));
+        reordered.add(reordered.remove(0));
+        equivalent.put(createEntry(testPrincipal, reordered.toArray(new Privilege[reordered.size()]), true),
+                      createEntry(testPrincipal, aggregateAllPrivs, true));
+        // even if entries are build with aggregated or declared aggregate privileges
+        equivalent.put(createEntry(testPrincipal, declaredAllPrivs, true),
+                      createEntry(testPrincipal, aggregateAllPrivs, true));
+
+        for (AccessControlEntry entry : equivalent.keySet()) {
+            AccessControlEntry eqv = equivalent.get(entry);
+            assertEquals(entry.hashCode(), eqv.hashCode());
+        }
+
+        // and the opposite:
+        List<JackrabbitAccessControlEntry> otherAces = new ArrayList<JackrabbitAccessControlEntry>();
+        try {
+            // ACE template with different principal
+            Principal princ = new Principal() {
+                public String getName() {
+                    return "a name";
+                }
+            };
+            Privilege[] privs = new Privilege[] {
+                    acMgr.privilegeFromName(PrivilegeConstants.JCR_ALL)
+            };
+            otherAces.add(createEntry(princ, privs, true));
+        } catch (RepositoryException e) {
+        }
+        // ACE template with different privileges
+        try {
+            otherAces.add(createEntry(new String[] {PrivilegeConstants.JCR_READ}, true));
+        } catch (RepositoryException e) {
+        }
+        // ACE template with different 'allow' flag
+        try {
+            otherAces.add(createEntry(new String[] {PrivilegeConstants.JCR_ALL}, false));
+        } catch (RepositoryException e) {
+        }
+        // ACE template with different privileges and 'allows
+        try {
+            otherAces.add(createEntry(new String[] {PrivilegeConstants.REP_WRITE}, false));
+        } catch (RepositoryException e) {
+        }
+        // other ace impl
+        final Privilege[] privs = new Privilege[] {
+                acMgr.privilegeFromName(PrivilegeConstants.JCR_ALL)
+        };
+        JackrabbitAccessControlEntry pe = new JackrabbitAccessControlEntry() {
+            public boolean isAllow() {
+                return true;
+            }
+            public String[] getRestrictionNames() {
+                return new String[0];
+            }
+            public Value getRestriction(String restrictionName) {
+                return null;
+            }
+            public Principal getPrincipal() {
+                return testPrincipal;
+            }
+            public Privilege[] getPrivileges() {
+                return privs;
+            }
+        };
+        otherAces.add(pe);
+
+        for (JackrabbitAccessControlEntry otherAce : otherAces) {
+            assertFalse(ace.hashCode() == otherAce.hashCode());
+        }
+
+    }
+
+    @Test
+    public void testNullPrincipal() throws RepositoryException {
+        try {
+            Privilege[] privs = new Privilege[] {
+                    acMgr.privilegeFromName(PrivilegeConstants.JCR_ALL)
+            };
+            createEntry(null, privs, true);
+            fail("Principal must not be null");
+        } catch (Exception e) {
+            // success
+        }
+    }
+
+    @Ignore // TODO review again if ACE must validate the privileges
+    @Test
+    public void testInvalidPrivilege() throws RepositoryException {
+        Privilege invalidPriv = new Privilege() {
+                public String getName() {
+                    return "";
+                }
+                public boolean isAbstract() {
+                    return false;
+                }
+                public boolean isAggregate() {
+                    return false;
+                }
+                public Privilege[] getDeclaredAggregatePrivileges() {
+                    return new Privilege[0];
+                }
+                public Privilege[] getAggregatePrivileges() {
+                    return new Privilege[0];
+                }
+            };
+        try {
+            Privilege[] privs = new Privilege[] {invalidPriv, privMgr.getPrivilege(PrivilegeConstants.JCR_READ)};
+            createEntry(testPrincipal, privs, true);
+            fail("Invalid privilege");
+        } catch (AccessControlException e) {
+            // success
+        }
+    }
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/ImmutableACLTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/ImmutableACLTest.java?rev=1432118&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/ImmutableACLTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/ImmutableACLTest.java Fri Jan 11 16:04:37 2013
@@ -0,0 +1,232 @@
+/*
+ * 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.oak.spi.security.authorization;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import javax.jcr.Value;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.Privilege;
+
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.security.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.oak.security.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * ImmutableACLTest... TODO
+ */
+public class ImmutableACLTest extends AbstractSecurityTest {
+
+    private PrivilegeManager privMgr;
+    private RestrictionProvider restrictionProvider;
+
+    private String testPath = "/testPath";
+    private Principal testPrincipal;
+    private Privilege[] testPrivileges;
+
+    @Before
+    public void before() throws Exception {
+        super.before();
+
+        Root root = adminSession.getLatestRoot();
+        NamePathMapper npMapper = NamePathMapper.DEFAULT;
+
+        privMgr = getSecurityProvider().getPrivilegeConfiguration().getPrivilegeManager(root, npMapper);
+        restrictionProvider = getSecurityProvider().getAccessControlConfiguration().getRestrictionProvider(npMapper);
+
+        testPrincipal = new PrincipalImpl("testPrincipal");
+        testPrivileges = new Privilege[] {
+                privMgr.getPrivilege(PrivilegeConstants.JCR_READ),
+                privMgr.getPrivilege(PrivilegeConstants.JCR_ADD_CHILD_NODES)
+        };
+    }
+
+    private ImmutableACL createACL(List<JackrabbitAccessControlEntry> entries) {
+        return createACL(entries, testPath);
+    }
+
+    private ImmutableACL createACL(List<JackrabbitAccessControlEntry> entries, String path) {
+        return new ImmutableACL(path, entries, restrictionProvider);
+    }
+
+    private void assertImmutable(JackrabbitAccessControlList acl) throws Exception {
+        String msg = "ACL should be immutable.";
+
+        try {
+            acl.addAccessControlEntry(testPrincipal, testPrivileges);
+            fail(msg);
+        } catch (AccessControlException e) {
+            // success
+        }
+
+        try {
+            acl.addEntry(testPrincipal, testPrivileges, true);
+            fail(msg);
+        } catch (AccessControlException e) {
+            // success
+        }
+
+        try {
+            acl.addEntry(testPrincipal, testPrivileges, false, Collections.<String, Value>emptyMap());
+            fail(msg);
+        } catch (AccessControlException e) {
+            // success
+        }
+
+        AccessControlEntry[] entries = acl.getAccessControlEntries();
+        if (entries.length > 1) {
+            try {
+                acl.orderBefore(entries[0], null);
+                fail(msg);
+            }  catch (AccessControlException e) {
+                // success
+            }
+
+            try {
+                acl.orderBefore(entries[1], entries[0]);
+                fail(msg);
+            }  catch (AccessControlException e) {
+                // success
+            }
+        }
+
+        for (AccessControlEntry ace : entries) {
+            try {
+                acl.removeAccessControlEntry(ace);
+                fail(msg);
+            }  catch (AccessControlException e) {
+                // success
+            }
+        }
+    }
+
+    @Test
+    public void testImmutable() throws Exception {
+        List<JackrabbitAccessControlEntry> entries = new ArrayList<JackrabbitAccessControlEntry>();
+        entries.add(new ACE(testPrincipal, testPrivileges, true, null));
+        entries.add(new ACE(testPrincipal, new Privilege[] {privMgr.getPrivilege(PrivilegeConstants.JCR_LIFECYCLE_MANAGEMENT)}, false, null));
+
+        ImmutableACL acl = createACL(entries);
+        assertFalse(acl.isEmpty());
+        assertEquals(2, acl.size());
+        assertEquals(testPath, acl.getPath());
+        assertImmutable(acl);
+    }
+
+    @Test
+    public void testEmptyIsImmutable() throws Exception {
+        ImmutableACL acl = createACL(Collections.<JackrabbitAccessControlEntry>emptyList());
+
+        assertTrue(acl.isEmpty());
+        assertEquals(0, acl.size());
+        assertEquals(testPath, acl.getPath());
+        assertImmutable(acl);
+    }
+
+    @Test
+    public void testEquals() throws Exception {
+        List<JackrabbitAccessControlEntry> entries = Collections.<JackrabbitAccessControlEntry>singletonList(new ACE(testPrincipal, testPrivileges, true, null));
+
+        JackrabbitAccessControlList empty = createACL(Collections.<JackrabbitAccessControlEntry>emptyList());
+        JackrabbitAccessControlList acl = createACL(entries);
+
+        assertEquals(empty, createACL(Collections.<JackrabbitAccessControlEntry>emptyList()));
+        assertEquals(acl, createACL(entries));
+
+        assertFalse(empty.equals(acl));
+        assertFalse(acl.equals(empty));
+        assertFalse(acl.equals(createACL(entries, "/anotherPath")));
+        assertFalse(acl.equals(new TestACL("/anotherPath", entries)));
+        assertFalse(acl.equals(new TestACL("/anotherPath", Collections.<JackrabbitAccessControlEntry>emptyList())));
+        assertFalse(acl.equals(new TestACL(testPath, entries)));
+        assertFalse(empty.equals(new TestACL(testPath, Collections.<JackrabbitAccessControlEntry>emptyList())));
+    }
+
+    /**
+     * Another JackrabbitAccessControlList
+     */
+    private final class TestACL extends AbstractAccessControlList {
+
+        private List<JackrabbitAccessControlEntry> entries = new ArrayList<JackrabbitAccessControlEntry>();
+
+        public TestACL(String jcrPath, List<JackrabbitAccessControlEntry> entries) {
+            super(jcrPath);
+            this.entries.addAll(entries);
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return entries.isEmpty();
+        }
+
+        @Override
+        public int size() {
+            return entries.size();
+        }
+
+        @Override
+        public boolean addEntry(Principal principal, Privilege[] privileges,
+                                boolean isAllow, Map<String, Value> restrictions) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void orderBefore(AccessControlEntry srcEntry, AccessControlEntry destEntry) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public AccessControlEntry[] getAccessControlEntries() {
+            return entries.toArray(new AccessControlEntry[entries.size()]);
+        }
+
+        @Override
+        public void removeAccessControlEntry(AccessControlEntry ace) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Nonnull
+        @Override
+        public List<JackrabbitAccessControlEntry> getEntries() {
+            return entries;
+        }
+
+        @Nonnull
+        @Override
+        public RestrictionProvider getRestrictionProvider() {
+            return restrictionProvider;
+        }
+    }
+}
\ No newline at end of file



Mime
View raw message