You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2014/08/12 14:58:15 UTC

svn commit: r1617463 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/ oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/ oak-jcr/src/test/java/org/apache/ja...

Author: angela
Date: Tue Aug 12 12:58:15 2014
New Revision: 1617463

URL: http://svn.apache.org/r1617463
Log:
OAK-2015: PermissionStore doesn't reflect dynamic nature of jcr:all

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/privilege/PrivilegeRegistrationTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java?rev=1617463&r1=1617462&r2=1617463&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java Tue Aug 12 12:58:15 2014
@@ -22,11 +22,9 @@ import javax.annotation.Nullable;
 import com.google.common.base.Objects;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionPattern;
-import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
 import org.apache.jackrabbit.util.Text;
 
@@ -57,14 +55,9 @@ final class PermissionEntry implements C
      */
     final RestrictionPattern restriction;
 
-    PermissionEntry(@Nonnull String path, @Nonnull Tree entryTree, @Nonnull RestrictionProvider restrictionsProvider) {
-        this(path, entryTree.getProperty(REP_IS_ALLOW).getValue(Type.BOOLEAN),
-                Integer.parseInt(entryTree.getName()),
-                PrivilegeBits.getInstance(entryTree.getProperty(REP_PRIVILEGE_BITS)),
-                restrictionsProvider.getPattern(path, entryTree));
-    }
-
-    PermissionEntry(@Nonnull String path, boolean isAllow, int index, @Nonnull PrivilegeBits privilegeBits, @Nonnull RestrictionPattern restriction) {
+    PermissionEntry(@Nonnull String path, boolean isAllow, int index,
+                    @Nonnull PrivilegeBits privilegeBits,
+                    @Nonnull RestrictionPattern restriction) {
         this.path = path;
         this.isAllow = isAllow;
         this.index = index;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java?rev=1617463&r1=1617462&r2=1617463&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java Tue Aug 12 12:58:15 2014
@@ -29,6 +29,8 @@ import javax.annotation.Nullable;
  */
 public interface PermissionStore {
 
+    long DYNAMIC_ALL_BITS = -1;
+
     /**
      * Loads the permission entries for the given principal and path. if the given {@code entries} is {@code null}, it
      * will be created automatically if needed. If a {@code entries} is given, it will reuse it and the same object is

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java?rev=1617463&r1=1617462&r2=1617463&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java Tue Aug 12 12:58:15 2014
@@ -25,7 +25,10 @@ import javax.annotation.Nonnull;
 import com.google.common.base.Objects;
 import com.google.common.base.Strings;
 import com.google.common.collect.Maps;
+import com.google.common.primitives.Longs;
+import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
 import org.apache.jackrabbit.oak.plugins.nodetype.TypePredicate;
 import org.apache.jackrabbit.oak.plugins.tree.ImmutableTree;
 import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
@@ -34,6 +37,7 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.util.Text;
@@ -54,8 +58,6 @@ final class PermissionStoreEditor implem
     final Map<String, List<AcEntry>> entries = Maps.<String, List<AcEntry>>newHashMap();
 
     private final NodeBuilder permissionRoot;
-    private final TypePredicate isACE;
-    private final RestrictionProvider restrictionProvider;
 
     PermissionStoreEditor(@Nonnull String aclPath, @Nonnull String name,
                           @Nonnull NodeState node, @Nonnull NodeBuilder permissionRoot,
@@ -63,9 +65,6 @@ final class PermissionStoreEditor implem
                           @Nonnull PrivilegeBitsProvider bitsProvider,
                           @Nonnull RestrictionProvider restrictionProvider) {
         this.permissionRoot = permissionRoot;
-        this.isACE = isACE;
-        this.restrictionProvider = restrictionProvider;
-
         if (name.equals(REP_REPO_POLICY)) {
             accessControlledPath = "";
         } else {
@@ -79,6 +78,7 @@ final class PermissionStoreEditor implem
             addAll(orderedChildNames, node.getChildNodeNames());
         }
 
+        PrivilegeBits jcrAll = bitsProvider.getBits(PrivilegeConstants.JCR_ALL);
         int index = 0;
         for (String childName : orderedChildNames) {
             NodeState ace = node.getChildNode(childName);
@@ -87,8 +87,9 @@ final class PermissionStoreEditor implem
                 PrivilegeBits privilegeBits = bitsProvider.getBits(ace.getNames(REP_PRIVILEGES));
                 Set<Restriction> restrictions = restrictionProvider.readRestrictions(Strings.emptyToNull(accessControlledPath), new ImmutableTree(ace));
 
-
-                AcEntry entry = new AcEntry(ace, accessControlledPath, index, isAllow, privilegeBits, restrictions);
+                AcEntry entry = (privilegeBits.equals(jcrAll)) ?
+                        new JcrAllAcEntry(ace, accessControlledPath, index, isAllow, privilegeBits, restrictions) :
+                        new AcEntry(ace, accessControlledPath, index, isAllow, privilegeBits, restrictions);
                 List<AcEntry> list = entries.get(entry.principalName);
                 if (list == null) {
                     list = new ArrayList<AcEntry>();
@@ -100,52 +101,6 @@ final class PermissionStoreEditor implem
         }
     }
 
-    void removePermissionEntry(@Nonnull String principalName, @Nonnull PermissionEntry permissionEntry) {
-        if (permissionRoot.hasChildNode(principalName)) {
-            NodeBuilder principalRoot = permissionRoot.getChildNode(principalName);
-
-            // find the ACL node that for this path and principal
-            NodeBuilder parent = principalRoot.getChildNode(nodeName);
-            if (!parent.exists()) {
-                log.error("Unable to remove permission entry {}: Parent for node " + nodeName + " missing.", this);
-                return;
-            }
-
-            // check if the node is the correct one
-            if (!PermissionUtil.checkACLPath(parent, accessControlledPath)) {
-                parent = null;
-                // find the right collision node
-                for (String childName : parent.getChildNodeNames()) {
-                    if (childName.charAt(0) != 'c') {
-                        continue;
-                    }
-                    NodeBuilder child = parent.getChildNode(childName);
-                    if (PermissionUtil.checkACLPath(child, accessControlledPath)) {
-                        parent = child;
-                        break;
-                    }
-                }
-                if (parent == null) {
-                    log.error("Unable to remove permission entry {}: Parent for node " + nodeName + " missing.", this);
-                    return;
-                }
-            }
-
-            for (String childName : parent.getChildNodeNames()) {
-                if (childName.charAt(0) == 'c') {
-                    continue;
-                }
-
-                NodeBuilder entryNode = parent.getChildNode(childName);
-                if (permissionEntry.equals(new PermissionEntry(accessControlledPath, new ImmutableTree(entryNode.getNodeState()), restrictionProvider))) {
-                    entryNode.remove();
-                }
-            }
-        } else {
-            log.error("Unable to remove permission entry {}: Principal root missing.", this);
-        }
-    }
-
     void removePermissionEntries() {
         for (String principalName : entries.keySet()) {
             if (permissionRoot.hasChildNode(principalName)) {
@@ -256,20 +211,35 @@ final class PermissionStoreEditor implem
         }
     }
 
-    final class AcEntry {
+    private final class JcrAllAcEntry extends AcEntry {
+
+        private JcrAllAcEntry(@Nonnull NodeState node,
+                              @Nonnull String accessControlledPath,
+                              int index, boolean isAllow,
+                              @Nonnull PrivilegeBits privilegeBits,
+                              @Nonnull Set<Restriction> restrictions) {
+            super(node, accessControlledPath, index, isAllow, privilegeBits, restrictions);
+        }
 
-        final String accessControlledPath;
-        final String principalName;
-        final PrivilegeBits privilegeBits;
-        final boolean isAllow;
-        final Set<Restriction> restrictions;
-        final int index;
-        int hashCode = -1;
+        @Override
+        protected PropertyState getPrivilegeBitsProperty() {
+            return PropertyStates.createProperty(REP_PRIVILEGE_BITS, Longs.asList(PermissionStore.DYNAMIC_ALL_BITS), Type.LONGS);
+        }
+    }
 
-        private TypePredicate isACE;
+    private class AcEntry {
 
-        AcEntry(@Nonnull NodeState node, @Nonnull String accessControlledPath, int index,
-                boolean isAllow, PrivilegeBits privilegeBits, Set<Restriction> restrictions) {
+        private final String accessControlledPath;
+        private final String principalName;
+        private final PrivilegeBits privilegeBits;
+        private final boolean isAllow;
+        private final Set<Restriction> restrictions;
+        private final int index;
+        private int hashCode = -1;
+
+        private AcEntry(@Nonnull NodeState node, @Nonnull String accessControlledPath, int index,
+                        boolean isAllow, @Nonnull PrivilegeBits privilegeBits,
+                        @Nonnull Set<Restriction> restrictions) {
             this.accessControlledPath = accessControlledPath;
             this.index = index;
 
@@ -279,20 +249,20 @@ final class PermissionStoreEditor implem
             this.restrictions = restrictions;
         }
 
-        PermissionEntry asPermissionEntry() {
-            return new PermissionEntry(accessControlledPath, isAllow, index, privilegeBits, restrictionProvider.getPattern(accessControlledPath, restrictions));
-        }
-
-        void writeToPermissionStore(NodeBuilder parent) {
+        private void writeToPermissionStore(NodeBuilder parent) {
             NodeBuilder n = parent.child(String.valueOf(index))
                     .setProperty(JCR_PRIMARYTYPE, NT_REP_PERMISSIONS, Type.NAME)
                     .setProperty(REP_IS_ALLOW, isAllow)
-                    .setProperty(privilegeBits.asPropertyState(REP_PRIVILEGE_BITS));
+                    .setProperty(getPrivilegeBitsProperty());
             for (Restriction restriction : restrictions) {
                 n.setProperty(restriction.getProperty());
             }
         }
 
+        protected PropertyState getPrivilegeBitsProperty() {
+            return privilegeBits.asPropertyState(REP_PRIVILEGE_BITS);
+        }
+
         //-------------------------------------------------------------< Object >---
         @Override
         public int hashCode() {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java?rev=1617463&r1=1617462&r2=1617463&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java Tue Aug 12 12:58:15 2014
@@ -25,10 +25,15 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
 import org.apache.jackrabbit.oak.util.TreeUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,7 +41,7 @@ import org.slf4j.LoggerFactory;
 /**
  * {@code PermissionStoreImpl}...
  */
-public class PermissionStoreImpl implements PermissionStore {
+public class PermissionStoreImpl implements PermissionStore, PermissionConstants {
 
     /**
      * default logger
@@ -49,17 +54,25 @@ public class PermissionStoreImpl impleme
 
     private final RestrictionProvider restrictionProvider;
 
+    private final PrivilegeBitsProvider privilegeBitsProvider;
+
+    private PrivilegeBits allBits;
+
     private final Map<String, Tree> principalTreeMap = new HashMap<String, Tree>();
 
     public PermissionStoreImpl(Root root, String workspaceName, RestrictionProvider restrictionProvider) {
         this.permissionsTree = PermissionUtil.getPermissionsRoot(root, workspaceName);
         this.workspaceName = workspaceName;
         this.restrictionProvider = restrictionProvider;
+        this.privilegeBitsProvider = new PrivilegeBitsProvider(root);
+
+        allBits = privilegeBitsProvider.getBits(PrivilegeConstants.JCR_ALL);
     }
 
     protected void flush(Root root) {
         this.permissionsTree = PermissionUtil.getPermissionsRoot(root, workspaceName);
         this.principalTreeMap.clear();
+        allBits = privilegeBitsProvider.getBits(PrivilegeConstants.JCR_ALL);
     }
 
     @CheckForNull
@@ -85,12 +98,12 @@ public class PermissionStoreImpl impleme
             if (principalRoot.hasChild(name)) {
                 Tree child = principalRoot.getChild(name);
                 if (PermissionUtil.checkACLPath(child, path)) {
-                    entries = loadPermissionEntries(path, entries, child, restrictionProvider);
+                    entries = loadPermissionEntries(path, entries, child);
                 } else {
                     // check for child node
                     for (Tree node : child.getChildren()) {
                         if (PermissionUtil.checkACLPath(node, path)) {
-                            entries = loadPermissionEntries(path, entries, node, restrictionProvider);
+                            entries = loadPermissionEntries(path, entries, node);
                         }
                     }
                 }
@@ -104,7 +117,7 @@ public class PermissionStoreImpl impleme
         Tree principalRoot = getPrincipalRoot(principalName);
         if (principalRoot != null) {
             for (Tree entryTree : principalRoot.getChildren()) {
-                loadPermissionEntries(entryTree, entries, restrictionProvider);
+                loadPermissionEntries(entryTree, entries);
             }
         }
     }
@@ -124,7 +137,7 @@ public class PermissionStoreImpl impleme
         Tree principalRoot = getPrincipalRoot(principalName);
         if (principalRoot != null) {
             for (Tree entryTree : principalRoot.getChildren()) {
-                loadPermissionEntries(entryTree, ret.getEntries(), restrictionProvider);
+                loadPermissionEntries(entryTree, ret.getEntries());
             }
         }
         ret.setFullyLoaded(true);
@@ -135,9 +148,8 @@ public class PermissionStoreImpl impleme
         return ret;
     }
 
-    private static void loadPermissionEntries(@Nonnull Tree tree,
-                                              @Nonnull Map<String, Collection<PermissionEntry>> pathEntryMap,
-                                              @Nonnull RestrictionProvider restrictionProvider) {
+    private void loadPermissionEntries(@Nonnull Tree tree,
+                                       @Nonnull Map<String, Collection<PermissionEntry>> pathEntryMap) {
         String path = TreeUtil.getString(tree, PermissionConstants.REP_ACCESS_CONTROLLED_PATH);
         Collection<PermissionEntry> entries = pathEntryMap.get(path);
         if (entries == null) {
@@ -146,26 +158,40 @@ public class PermissionStoreImpl impleme
         }
         for (Tree child : tree.getChildren()) {
             if (child.getName().charAt(0) == 'c') {
-                loadPermissionEntries(child, pathEntryMap, restrictionProvider);
+                loadPermissionEntries(child, pathEntryMap);
             } else {
-                entries.add(new PermissionEntry(path, child, restrictionProvider));
+                entries.add(createPermissionEntry(path, child));
             }
         }
     }
 
     @CheckForNull
-    private static Collection<PermissionEntry> loadPermissionEntries(@Nonnull String path,
-                                              @Nullable Collection<PermissionEntry> ret,
-                                              @Nonnull Tree tree,
-                                              @Nonnull RestrictionProvider restrictionProvider) {
+    private Collection<PermissionEntry> loadPermissionEntries(@Nonnull String path,
+                                                              @Nullable Collection<PermissionEntry> ret,
+                                                              @Nonnull Tree tree) {
         for (Tree ace : tree.getChildren()) {
             if (ace.getName().charAt(0) != 'c') {
                 if (ret == null) {
                     ret = new TreeSet<PermissionEntry>();
                 }
-                ret.add(new PermissionEntry(path, ace, restrictionProvider));
+                ret.add(createPermissionEntry(path, ace));
             }
         }
         return ret;
     }
+
+    private PermissionEntry createPermissionEntry(@Nonnull String path,
+                                                  @Nonnull Tree entryTree) {
+        PropertyState ps = entryTree.getProperty(REP_PRIVILEGE_BITS);
+        PrivilegeBits bits = (isJcrAll(ps)) ? allBits : PrivilegeBits.getInstance(ps);
+        return new PermissionEntry(path,
+                entryTree.getProperty(REP_IS_ALLOW).getValue(Type.BOOLEAN),
+                Integer.parseInt(entryTree.getName()),
+                bits,
+                restrictionProvider.getPattern(path, entryTree));
+    }
+
+    private static boolean isJcrAll(PropertyState property) {
+        return property.count() == 1 && property.getValue(Type.LONG, 0) == DYNAMIC_ALL_BITS;
+    }
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java?rev=1617463&r1=1617462&r2=1617463&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java Tue Aug 12 12:58:15 2014
@@ -20,22 +20,28 @@ import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.security.AccessControlEntry;
 import javax.jcr.security.AccessControlManager;
 
+import com.google.common.collect.ImmutableSet;
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
 import org.apache.jackrabbit.api.security.user.Group;
 import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
 import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
 import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AbstractAccessControlTest;
 import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions;
 import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
@@ -347,4 +353,58 @@ public class PermissionHookTest extends 
         principalRoot = getPrincipalRoot(EveryonePrincipal.NAME);
         assertEquals(2, cntEntries(principalRoot));
     }
+
+    /**
+     * @see <a href="https://issues.apache.org/jira/browse/OAK-2015">OAK-2015</a>
+     */
+    @Test
+    public void testDynamicJcrAll() throws Exception {
+        AccessControlManager acMgr = getAccessControlManager(root);
+
+        // grant 'everyone' jcr:all at the child path.
+        JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, childPath);
+        acl.addAccessControlEntry(EveryonePrincipal.getInstance(), privilegesFromNames(JCR_ALL));
+        acMgr.setPolicy(childPath, acl);
+        root.commit();
+
+        // verify that the permission store contains an entry for everyone at childPath
+        // and the privilegeBits for jcr:all are reflect with a placeholder value.
+        Tree allEntry = getEntry(EveryonePrincipal.NAME, childPath, 0);
+        assertTrue(allEntry.exists());
+        PropertyState ps = allEntry.getProperty(PermissionConstants.REP_PRIVILEGE_BITS);
+        assertEquals(1, ps.count());
+        assertEquals(PermissionStore.DYNAMIC_ALL_BITS, ps.getValue(Type.LONG, 0).longValue());
+
+        // verify that the permission provider still exposes the correct privilege
+        // (jcr:all) for the given childPath irrespective of the dynamic nature of
+        // the privilege bits in the persisted permission entry.
+        Set<Principal> principalSet = ImmutableSet.<Principal>of(EveryonePrincipal.getInstance());
+        PermissionProvider permissionProvider = getConfig(AuthorizationConfiguration.class).getPermissionProvider(root, root.getContentSession().getWorkspaceName(), principalSet);
+        Tree childTree = root.getTree(childPath);
+        assertTrue(permissionProvider.hasPrivileges(childTree, PrivilegeConstants.JCR_ALL));
+        assertTrue(permissionProvider.getPrivileges(childTree).contains(PrivilegeConstants.JCR_ALL));
+
+        // also verify the permission evaluation
+        long diff = Permissions.diff(Permissions.ALL, Permissions.REMOVE_NODE|Permissions.ADD_NODE);
+        assertFalse(permissionProvider.isGranted(childTree, null, Permissions.REMOVE_NODE));
+        assertFalse(permissionProvider.isGranted(childTree, null, Permissions.ADD_NODE));
+        assertTrue(permissionProvider.isGranted(childTree, null, diff));
+
+        // remove the ACE again
+        acl = AccessControlUtils.getAccessControlList(acMgr, childPath);
+        for (AccessControlEntry ace : acl.getAccessControlEntries()) {
+            if (EveryonePrincipal.NAME.equals(ace.getPrincipal().getName())) {
+                acl.removeAccessControlEntry(ace);
+            }
+        }
+        acMgr.setPolicy(childPath, acl);
+        root.commit();
+
+        // verify that the corresponding permission entry has been removed.
+        Tree everyoneRoot = getPrincipalRoot(EveryonePrincipal.NAME);
+        Tree parent = everyoneRoot.getChild(PermissionUtil.getEntryName(childPath));
+        if (parent.exists()) {
+            assertFalse(parent.getChild("0").exists());
+        }
+    }
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/privilege/PrivilegeRegistrationTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/privilege/PrivilegeRegistrationTest.java?rev=1617463&r1=1617462&r2=1617463&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/privilege/PrivilegeRegistrationTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/privilege/PrivilegeRegistrationTest.java Tue Aug 12 12:58:15 2014
@@ -16,12 +16,13 @@
  */
 package org.apache.jackrabbit.oak.jcr.security.privilege;
 
+import java.security.Principal;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-
+import java.util.Set;
 import javax.jcr.AccessDeniedException;
 import javax.jcr.InvalidItemStateException;
 import javax.jcr.NamespaceException;
@@ -33,6 +34,8 @@ import javax.jcr.Workspace;
 import javax.jcr.security.AccessControlException;
 import javax.jcr.security.Privilege;
 
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
 import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
 import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
 import org.apache.jackrabbit.oak.jcr.Jcr;
@@ -413,4 +416,26 @@ public class PrivilegeRegistrationTest e
             superuser.refresh(false);
         }
     }
+
+    /**
+     * @see <a href="https://issues.apache.org/jira/browse/OAK-2015">OAK-2015</a>
+     */
+    @Test
+    public void testJcrAllWithCustomPrivileges() throws Exception {
+        Node testNode = session.getRootNode().addNode("test");
+        String testPath = testNode.getPath();
+
+        AccessControlUtils.grantAllToEveryone(session, testPath);
+        session.save();
+
+        JackrabbitAccessControlManager acMgr = (JackrabbitAccessControlManager) session.getAccessControlManager();
+        Privilege[] allPrivileges = AccessControlUtils.privilegesFromNames(session, Privilege.JCR_ALL);
+        Set<Principal> principalSet = ImmutableSet.<Principal>of(EveryonePrincipal.getInstance());
+
+        assertTrue(acMgr.hasPrivileges(testPath, principalSet, allPrivileges));
+
+        privilegeManager.registerPrivilege("customPriv", false, null);
+
+        assertTrue(acMgr.hasPrivileges(testPath, principalSet, allPrivileges));
+    }
 }
\ No newline at end of file