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 2015/07/16 14:59:18 UTC

svn commit: r1691388 [1/2] - in /jackrabbit/oak/trunk: oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/ oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/...

Author: angela
Date: Thu Jul 16 12:59:17 2015
New Revision: 1691388

URL: http://svn.apache.org/r1691388
Log:
OAK-1268 : Add support for composite authorization setup (WIP), 

Added:
    jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermission.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/EmptyCugTreePermission.java
Modified:
    jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProvider.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugEvaluationTest.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProviderTest.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeAuthorizationConfiguration.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositePermissionProvider.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/AggregatedPermissionProvider.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/package-info.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBits.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/package-info.java

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProvider.java?rev=1691388&r1=1691387&r2=1691388&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProvider.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProvider.java Thu Jul 16 12:59:17 2015
@@ -23,7 +23,6 @@ import java.util.Set;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
-import javax.jcr.Session;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableSet;
@@ -36,40 +35,26 @@ import org.apache.jackrabbit.oak.commons
 import org.apache.jackrabbit.oak.plugins.tree.TreeLocation;
 import org.apache.jackrabbit.oak.spi.security.Context;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider;
-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.authorization.permission.RepositoryPermission;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.plugins.tree.RootFactory;
 import org.apache.jackrabbit.oak.util.TreeUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-class CugPermissionProvider implements PermissionProvider, AggregatedPermissionProvider, CugConstants {
+class CugPermissionProvider implements AggregatedPermissionProvider, CugConstants {
 
     private static final Logger log = LoggerFactory.getLogger(CugPermissionProvider.class);
 
-    private static final Set<String> READ_NAMES = ImmutableSet.of(
-            Session.ACTION_READ,
-            Permissions.PERMISSION_NAMES.get(Permissions.READ),
-            Permissions.PERMISSION_NAMES.get(Permissions.READ_NODE),
-            Permissions.PERMISSION_NAMES.get(Permissions.READ_PROPERTY));
-
     private static final Set<String> READ_PRIVILEGE_NAMES = ImmutableSet.of(
             PrivilegeConstants.JCR_READ,
             PrivilegeConstants.REP_READ_NODES,
             PrivilegeConstants.REP_READ_PROPERTIES
     );
 
-    private static final Set<PrivilegeBits> READ_PRIVILEGE_BITS = ImmutableSet.of(
-            PrivilegeBits.BUILT_IN.get(PrivilegeConstants.JCR_READ),
-            PrivilegeBits.BUILT_IN.get(PrivilegeConstants.REP_READ_NODES),
-            PrivilegeBits.BUILT_IN.get(PrivilegeConstants.REP_READ_PROPERTIES)
-    );
-
     private final Root root;
     private final Set<String> principalNames;
 
@@ -95,36 +80,6 @@ class CugPermissionProvider implements P
         this.ctx = ctx;
     }
 
-    //---------------------------------------< AggregatedPermissionProvider >---
-    @Override
-    public boolean handles(@Nonnull String path, @Nonnull String jcrAction) {
-        return isReadAction(jcrAction) && includesCug(immutableRoot.getTree(path), path);
-    }
-
-    @Override
-    public boolean handles(@Nonnull Tree tree, @Nonnull PrivilegeBits privilegeBits) {
-        return READ_PRIVILEGE_BITS.contains(privilegeBits) && includesCug(tree, tree.getPath());
-    }
-
-    @Override
-    public boolean handles(@Nonnull Tree tree, long permission) {
-        return isRead(permission) && includesCug(tree, tree.getPath());
-    }
-
-    @Override
-    public boolean handles(@Nonnull TreePermission treePermission, long permission) {
-        if (isRead(permission)) {
-            return treePermission instanceof CugTreePermission;
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public boolean handlesRepositoryPermissions() {
-        return false;
-    }
-
     //-------------------------------------------------< PermissionProvider >---
     @Override
     public void refresh() {
@@ -157,7 +112,7 @@ class CugPermissionProvider implements P
     @Nonnull
     @Override
     public RepositoryPermission getRepositoryPermission() {
-        throw new UnsupportedOperationException("Not supported");
+        return RepositoryPermission.EMPTY;
     }
 
     @Nonnull
@@ -170,7 +125,7 @@ class CugPermissionProvider implements P
 
         TreePermission tp;
         if (parentPermission instanceof CugTreePermission) {
-            tp =  new CugTreePermission(immutableTree, ((CugTreePermission) parentPermission).allow);
+            tp =  new CugTreePermission(immutableTree, ((CugTreePermission) parentPermission));
             if (hasCug(immutableTree)) {
                 // a new (nested) cug starts off here
                 tp = createCugPermission(immutableTree, tp);
@@ -180,7 +135,7 @@ class CugPermissionProvider implements P
             if (supportedPaths.includes(path)) {
                 tp =  createCugPermission(immutableTree, null);
             } else if (supportedPaths.mayContainCug(path)) {
-                tp =  new EmptyCugPermission(immutableTree);
+                tp =  new EmptyCugTreePermission(immutableTree, this);
             } else {
                 tp = TreePermission.EMPTY;
             }
@@ -203,18 +158,75 @@ class CugPermissionProvider implements P
         boolean isAcContent = isAcContent(location);
         long permissions = Permissions.getPermissions(jcrActions, location, isAcContent);
 
+        return isGranted(location, permissions);
+    }
+
+    //---------------------------------------< AggregatedPermissionProvider >---
+    @Override
+    public PrivilegeBits supportedPrivileges(@Nullable Tree tree, @Nullable PrivilegeBits privilegeBits) {
+        if (tree == null) {
+            return PrivilegeBits.EMPTY;
+        }
+
+        PrivilegeBits pb;
+        if (privilegeBits == null) {
+            pb = PrivilegeBits.BUILT_IN.get(PrivilegeConstants.JCR_READ);
+        } else {
+            pb = PrivilegeBits.getInstance(privilegeBits);
+            pb.retain(PrivilegeBits.BUILT_IN.get(PrivilegeConstants.JCR_READ));
+        }
+
+        if (pb.isEmpty() || !includesCug(tree, tree.getPath())) {
+            return PrivilegeBits.EMPTY;
+        } else {
+            return pb;
+        }
+    }
+
+    @Override
+    public long supportedPermissions(@Nullable Tree tree, @Nullable PropertyState property, long permissions) {
+        if (tree == null) {
+            // repository level permissions are not supported
+            return Permissions.NO_PERMISSION;
+        }
+
+        long supported = permissions & Permissions.READ;
+        if (supported != Permissions.NO_PERMISSION && includesCug(tree, tree.getPath())) {
+            return supported;
+        } else {
+            return Permissions.NO_PERMISSION;
+        }
+    }
+
+    @Override
+    public long supportedPermissions(@Nonnull TreeLocation location, long permissions) {
+        long supported = permissions & Permissions.READ;
+        if (supported != Permissions.NO_PERMISSION && includesCug(getTreeFromLocation(location, location.getProperty()), location.getPath())) {
+            return supported;
+        } else {
+            return Permissions.NO_PERMISSION;
+        }
+    }
+
+    @Override
+    public long supportedPermissions(@Nonnull TreePermission treePermission, long permissions) {
+        long supported = permissions & Permissions.READ;
+        if (supported != Permissions.NO_PERMISSION && (treePermission instanceof CugTreePermission)) {
+            return supported;
+        } else {
+            return Permissions.NO_PERMISSION;
+        }
+    }
+
+    @Override
+    public boolean isGranted(@Nonnull TreeLocation location, long permissions) {
         if (isRead(permissions)) {
             PropertyState property = location.getProperty();
-            Tree tree = (property == null) ? location.getTree() : location.getParent().getTree();
-            while (tree == null && !PathUtils.denotesRoot(location.getPath())) {
-                location = location.getParent();
-                tree = location.getTree();
-            }
+            Tree tree = getTreeFromLocation(location, property);
             if (tree != null) {
                 return isGranted(tree, property, permissions);
             }
         }
-
         return false;
     }
 
@@ -223,10 +235,6 @@ class CugPermissionProvider implements P
         return permission == Permissions.READ_NODE || permission == Permissions.READ_PROPERTY || permission == Permissions.READ;
     }
 
-    private static boolean isReadAction(@Nonnull String jcrAction) {
-        return READ_NAMES.contains(jcrAction);
-    }
-
     private static boolean hasCug(@Nonnull Tree tree) {
         return tree.exists() && tree.hasChild(REP_CUG_POLICY);
     }
@@ -239,8 +247,8 @@ class CugPermissionProvider implements P
         return ctx.definesLocation(location);
     }
 
-    private boolean includesCug(@Nonnull Tree tree, @Nonnull String path) {
-        return getCugRoot(tree, path) != null;
+    private boolean includesCug(@CheckForNull Tree tree, @Nonnull String path) {
+        return tree != null && getCugRoot(tree, path) != null;
     }
 
     /**
@@ -291,6 +299,16 @@ class CugPermissionProvider implements P
         return TreeUtil.isReadOnlyTree(tree) ? tree : immutableRoot.getTree(tree.getPath());
     }
 
+    @CheckForNull
+    private static Tree getTreeFromLocation(@Nonnull TreeLocation location, @CheckForNull PropertyState property) {
+        Tree tree = (property == null) ? location.getTree() : location.getParent().getTree();
+        while (tree == null && !PathUtils.denotesRoot(location.getPath())) {
+            location = location.getParent();
+            tree = location.getTree();
+        }
+        return tree;
+    }
+
     @Nonnull
     private TreePermission createCugPermission(@Nonnull Tree tree, @Nullable TreePermission fallback) {
         Tree cugTree = tree.getChild(REP_CUG_POLICY);
@@ -304,112 +322,11 @@ class CugPermissionProvider implements P
                         break;
                     }
                 }
-                return new CugTreePermission(tree, allow);
+                return new CugTreePermission(tree, allow, this);
             } else {
                 log.warn("Tree at {0} doesn't represent a valid CUG.", cugTree.getPath());
             }
         }
-        return (fallback == null) ? new EmptyCugPermission(tree) : fallback;
-    }
-
-    //--------------------------------------------------------------------------
-
-    /**
-     * Same as {@link org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission#EMPTY}
-     * from a permission point of view but indicating that
-     */
-    private final class EmptyCugPermission implements TreePermission {
-
-        private Tree tree;
-
-        private EmptyCugPermission(@Nonnull Tree tree) {
-            this.tree = tree;
-        }
-
-        @Nonnull
-        @Override
-        public TreePermission getChildPermission(@Nonnull String childName, @Nonnull NodeState childState) {
-            return getTreePermission(tree.getChild(childName), this);
-        }
-
-        @Override
-        public boolean canRead() {
-            return false;
-        }
-
-        @Override
-        public boolean canRead(@Nonnull PropertyState property) {
-            return false;
-        }
-
-        @Override
-        public boolean canReadAll() {
-            return false;
-        }
-
-        @Override
-        public boolean canReadProperties() {
-            return false;
-        }
-
-        @Override
-        public boolean isGranted(long permissions) {
-            return false;
-        }
-
-        @Override
-        public boolean isGranted(long permissions, @Nonnull PropertyState property) {
-            return false;
-        }
-    }
-
-    /**
-     * {@code TreePermission} implementation for all items located with a CUG.
-     */
-    private final class CugTreePermission implements TreePermission {
-
-        private final Tree tree;
-        private final boolean allow;
-
-        private CugTreePermission(@Nonnull Tree tree, boolean allow) {
-            this.tree = tree;
-            this.allow = allow;
-        }
-
-        @Nonnull
-        @Override
-        public TreePermission getChildPermission(@Nonnull String childName, @Nonnull NodeState childState) {
-            return getTreePermission(tree.getChild(childName), this);
-        }
-
-        @Override
-        public boolean canRead() {
-            return allow;
-        }
-
-        @Override
-        public boolean canRead(@Nonnull PropertyState property) {
-            return allow;
-        }
-
-        @Override
-        public boolean canReadAll() {
-            return false;
-        }
-
-        @Override
-        public boolean canReadProperties() {
-            return false;
-        }
-
-        @Override
-        public boolean isGranted(long permissions) {
-            return allow && permissions == Permissions.READ_NODE;
-        }
-
-        @Override
-        public boolean isGranted(long permissions, @Nonnull PropertyState property) {
-            return allow && permissions == Permissions.READ_PROPERTY;
-        }
+        return (fallback == null) ? new EmptyCugTreePermission(tree, this) : fallback;
     }
 }
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermission.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermission.java?rev=1691388&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermission.java (added)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermission.java Thu Jul 16 12:59:17 2015
@@ -0,0 +1,85 @@
+/*
+ * 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.cug.impl;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Tree;
+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.authorization.permission.TreePermission;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+/**
+ * {@code TreePermission} implementation for all items located with a CUG.
+ */
+final class CugTreePermission implements TreePermission {
+
+    private final Tree tree;
+    private final boolean allow;
+    private final PermissionProvider permissionProvider;
+
+    CugTreePermission(@Nonnull Tree tree, boolean allow, @Nonnull PermissionProvider permissionProvider) {
+        this.tree = tree;
+        this.allow = allow;
+        this.permissionProvider = permissionProvider;
+    }
+
+    CugTreePermission(@Nonnull Tree tree, @Nonnull CugTreePermission parent) {
+        this.tree = tree;
+        this.allow = parent.allow;
+        this.permissionProvider = parent.permissionProvider;
+    }
+
+    //-----------------------------------------------------< TreePermission >---
+    @Nonnull
+    @Override
+    public TreePermission getChildPermission(@Nonnull String childName, @Nonnull NodeState childState) {
+        return permissionProvider.getTreePermission(tree.getChild(childName), this);
+    }
+
+    @Override
+    public boolean canRead() {
+        return allow;
+    }
+
+    @Override
+    public boolean canRead(@Nonnull PropertyState property) {
+        return allow;
+    }
+
+    @Override
+    public boolean canReadAll() {
+        return false;
+    }
+
+    @Override
+    public boolean canReadProperties() {
+        return false;
+    }
+
+    @Override
+    public boolean isGranted(long permissions) {
+        return allow && permissions == Permissions.READ_NODE;
+    }
+
+    @Override
+    public boolean isGranted(long permissions, @Nonnull PropertyState property) {
+        return allow && permissions == Permissions.READ_PROPERTY;
+    }
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/EmptyCugTreePermission.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/EmptyCugTreePermission.java?rev=1691388&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/EmptyCugTreePermission.java (added)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/EmptyCugTreePermission.java Thu Jul 16 12:59:17 2015
@@ -0,0 +1,81 @@
+/*
+ * 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.cug.impl;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+/**
+ * Same as {@link org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission#EMPTY}
+ * from a permission point of view but indicating that it refers to a tree that
+ * potentially contains a CUG in the subtree thus forcing continued evaluation,
+ * where as {@link org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission#EMPTY}
+ * indicates that this permission model will never grant access in the subtree
+ * and thus can be ignored.
+ */
+final class EmptyCugTreePermission implements TreePermission {
+
+    private final Tree tree;
+    private final PermissionProvider permissionProvider;
+
+    EmptyCugTreePermission(@Nonnull Tree tree, @Nonnull PermissionProvider permissionProvider) {
+        this.tree = tree;
+        this.permissionProvider = permissionProvider;
+    }
+
+    //-----------------------------------------------------< TreePermission >---
+    @Nonnull
+    @Override
+    public TreePermission getChildPermission(@Nonnull String childName, @Nonnull NodeState childState) {
+        return permissionProvider.getTreePermission(tree.getChild(childName), this);
+    }
+
+    @Override
+    public boolean canRead() {
+        return false;
+    }
+
+    @Override
+    public boolean canRead(@Nonnull PropertyState property) {
+        return false;
+    }
+
+    @Override
+    public boolean canReadAll() {
+        return false;
+    }
+
+    @Override
+    public boolean canReadProperties() {
+        return false;
+    }
+
+    @Override
+    public boolean isGranted(long permissions) {
+        return false;
+    }
+
+    @Override
+    public boolean isGranted(long permissions, @Nonnull PropertyState property) {
+        return false;
+    }
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugEvaluationTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugEvaluationTest.java?rev=1691388&r1=1691387&r2=1691388&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugEvaluationTest.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugEvaluationTest.java Thu Jul 16 12:59:17 2015
@@ -34,16 +34,17 @@ import org.apache.jackrabbit.oak.api.Con
 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.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
 import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
 import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
 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.principal.PrincipalConfiguration;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
 import org.apache.jackrabbit.oak.util.NodeUtil;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
@@ -65,6 +66,7 @@ public class CugEvaluationTest extends A
     public void before() throws Exception {
         super.before();
 
+        // create testGroup with 'testuser2' being a declared member (testUser is not)
         Group testGroup = getUserManager(root).createGroup(TEST_GROUP_ID);
         testGroupPrincipal = testGroup.getPrincipal();
         User testUser2 = getUserManager(root).createUser(TEST_USER2_ID, TEST_USER2_ID);
@@ -82,7 +84,9 @@ public class CugEvaluationTest extends A
         createCug("/content/a/b/c", EveryonePrincipal.getInstance());
         createCug("/content2", EveryonePrincipal.getInstance());
 
-        // setup regular acl at /content
+        // setup regular acl at /content:
+        // - testUser  ; allow ; jcr:read
+        // - testGroup ; allow ; jcr:read, jcr:write, jcr:readAccessControl
         AccessControlManager acMgr = getAccessControlManager(root);
         AccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, "/content");
         acl.addAccessControlEntry(getTestUser().getPrincipal(), privilegesFromNames(
@@ -202,11 +206,16 @@ public class CugEvaluationTest extends A
 
     @Test
     public void testWrite2() throws Exception {
+        Set<Principal> principalSet = (Set<Principal>) getConfig(PrincipalConfiguration.class).getPrincipalProvider(root, NamePathMapper.DEFAULT).getPrincipals(TEST_USER2_ID);
+        PermissionProvider pp = createPermissionProvider(principalSet);
+        assertTrue(pp.isGranted(root.getTree("/content/writeTest"), null, Permissions.ADD_NODE));
+        assertTrue(pp.isGranted(root.getTree("/content/a/b/c/writeTest"), null, Permissions.ADD_NODE));
+
         ContentSession cs = login(new SimpleCredentials(TEST_USER2_ID, TEST_USER2_ID.toCharArray()));
         Root r = cs.getLatestRoot();
         try {
-            List<String> readOnly = ImmutableList.of("/content", "/content/a/b/c");
-            for (String p : readOnly) {
+            List<String> paths = ImmutableList.of("/content", "/content/a/b/c");
+            for (String p : paths) {
                 NodeUtil content = new NodeUtil(r.getTree(p));
                 content.addChild("writeTest", NT_OAK_UNSTRUCTURED);
                 r.commit();
@@ -401,10 +410,10 @@ public class CugEvaluationTest extends A
         assertTrue(pp.hasPrivileges(root.getTree("/content/a/b/c"), PrivilegeConstants.JCR_ALL));
     }
 
-    @Ignore() // FIXME
     @Test
     public void testGetPrivileges() throws Exception {
         Tree content = root.getTree("/content");
+        Tree content2 = root.getTree("/content2");
         Tree a = root.getTree("/content/a");
         Tree c = root.getTree("/content/a/b/c");
 
@@ -419,6 +428,7 @@ public class CugEvaluationTest extends A
         assertEquals(r_w_rac, pp.getPrivileges(content));
         assertEquals(r_w_rac, pp.getPrivileges(a));
         assertEquals(w_rac, pp.getPrivileges(c));
+        assertTrue(pp.getPrivileges(content2).isEmpty());
 
         // everyone
         principals = ImmutableSet.<Principal>of(EveryonePrincipal.getInstance());
@@ -426,7 +436,8 @@ public class CugEvaluationTest extends A
 
         assertTrue(pp.getPrivileges(content).isEmpty());
         assertTrue(pp.getPrivileges(a).isEmpty());
-        assertTrue(pp.getPrivileges(c).isEmpty());
+        assertEquals(r, pp.getPrivileges(c));
+        assertEquals(r, pp.getPrivileges(content2));
 
         // testGroup + everyone
         principals = ImmutableSet.of(testGroupPrincipal, EveryonePrincipal.getInstance());
@@ -435,6 +446,7 @@ public class CugEvaluationTest extends A
         assertEquals(r_w_rac, pp.getPrivileges(content));
         assertEquals(r_w_rac, pp.getPrivileges(a));
         assertEquals(r_w_rac, pp.getPrivileges(c));
+        assertEquals(r, pp.getPrivileges(content2));
 
         // testUser + everyone
         principals = ImmutableSet.of(getTestUser().getPrincipal(), EveryonePrincipal.getInstance());
@@ -443,5 +455,6 @@ public class CugEvaluationTest extends A
         assertEquals(r, pp.getPrivileges(content));
         assertTrue(pp.getPrivileges(a).isEmpty());
         assertEquals(r, pp.getPrivileges(c));
+        assertEquals(r, pp.getPrivileges(content2));
     }
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProviderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProviderTest.java?rev=1691388&r1=1691387&r2=1691388&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProviderTest.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProviderTest.java Thu Jul 16 12:59:17 2015
@@ -21,20 +21,25 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import javax.annotation.Nonnull;
 import javax.jcr.AccessDeniedException;
 import javax.jcr.Session;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.Group;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.plugins.tree.TreeLocation;
 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.authorization.permission.RepositoryPermission;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission;
 import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
 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.NodeUtil;
 import org.junit.Before;
@@ -50,6 +55,39 @@ public class CugPermissionProviderTest e
 
     private static final String TEST_GROUP_ID = "testGroupForCugTest";
 
+    private static final Map<String, Boolean> PATH_INCUG_MAP = new HashMap<String, Boolean>();
+    static {
+        PATH_INCUG_MAP.put(SUPPORTED_PATH, false);
+        PATH_INCUG_MAP.put("/content/a", true);
+        PATH_INCUG_MAP.put("/content/a/rep:cugPolicy", true);
+        PATH_INCUG_MAP.put("/content/a/b", true);
+        PATH_INCUG_MAP.put("/content/a/b/c/jcr:primaryType", true);
+        PATH_INCUG_MAP.put("/content/aa", false);
+        PATH_INCUG_MAP.put("/content/aa/bb/cc", true);
+        // paths that may not contain cugs anyway
+        PATH_INCUG_MAP.put(NODE_TYPES_PATH, false);
+        PATH_INCUG_MAP.put("/", false);
+        PATH_INCUG_MAP.put(UNSUPPORTED_PATH, false);
+        PATH_INCUG_MAP.put(INVALID_PATH, false);
+    }
+
+    private static final List<String> READABLE_PATHS = ImmutableList.of(
+            "/content/a/b/c", "/content/a/b/c/jcr:primaryType",
+            "/content/a/b/c/nonExisting", "/content/a/b/c/nonExisting/jcr:primaryType");
+
+    private static final List<String> NOT_READABLE_PATHS = ImmutableList.of(
+            "/", "/jcr:primaryType",
+            UNSUPPORTED_PATH, UNSUPPORTED_PATH + "/jcr:primaryType",
+            "/content", "/content/jcr:primaryType",
+            "/content/a", "/content/a/jcr:primaryType",
+            "/content/a/b", "/content/a/b/jcr:primaryType",
+            "/content/a/b/c/rep:cugPolicy", "/content/a/b/c/rep:cugPolicy/jcr:primaryType", "/content/a/b/c/rep:cugPolicy/rep:principalNames",
+            "/content/a/b/c/rep:cugPolicy/nonExisting", "/content/a/b/c/rep:cugPolicy/nonExisting/jcr:primaryType",
+            "/content/aa", "/content/aa/jcr:primaryType",
+            "/content/bb", "/content/bb/jcr:primaryType",
+            "/content/aa/bb/rep:cugPolicy", "/content/aa/bb/rep:cugPolicy/jcr:primaryType", "/content/aa/bb/rep:cugPolicy/rep:principalNames",
+            "/content/nonExisting", "/content/nonExisting/jcr:primaryType");
+
     private Principal testGroupPrincipal;
     private CugPermissionProvider cugPermProvider;
 
@@ -96,60 +134,156 @@ public class CugPermissionProviderTest e
         }
     }
 
-    @Test
-    public void testHandlesPath() {
-        Map<String, Boolean> pathMap = new HashMap<String, Boolean>();
-        pathMap.put(SUPPORTED_PATH, false);
-        pathMap.put("/content/a", true);
-        pathMap.put("/content/a/rep:cugPolicy", true);
-        pathMap.put("/content/a/b", true);
-        pathMap.put("/content/a/b/c/jcr:primaryType", true);
-        pathMap.put("/content/aa", false);
-        pathMap.put("/content/aa/bb/cc", true);
-        // paths that may not contain cugs anyway
-        pathMap.put(NODE_TYPES_PATH, false);
-        pathMap.put("/", false);
-        pathMap.put(UNSUPPORTED_PATH, false);
-        pathMap.put(INVALID_PATH, false);
+    //---------------------------------------< AggregatedPermissionProvider >---
+    /**
+     * @see org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider#supportedPrivileges(org.apache.jackrabbit.oak.api.Tree, org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits)
+     */
+    @Test
+    public void testSupportedPrivileges() {
+        PrivilegeBits readBits = PrivilegeBits.BUILT_IN.get(PrivilegeConstants.JCR_READ);
+        PrivilegeBits readNodeBits = PrivilegeBits.BUILT_IN.get(PrivilegeConstants.REP_READ_NODES);
+        PrivilegeBits readPropBits = PrivilegeBits.BUILT_IN.get(PrivilegeConstants.REP_READ_PROPERTIES);
+        PrivilegeBitsProvider provider = new PrivilegeBitsProvider(root);
+
+        for (String path : PATH_INCUG_MAP.keySet()) {
+            boolean isInCug = PATH_INCUG_MAP.get(path);
+            Tree tree = root.getTree(path);
+            if (isInCug) {
+                assertPrivilegeBits(readBits, cugPermProvider.supportedPrivileges(tree, readBits));
+                assertPrivilegeBits(readNodeBits, cugPermProvider.supportedPrivileges(tree, readNodeBits));
+                assertPrivilegeBits(readPropBits, cugPermProvider.supportedPrivileges(tree, readPropBits));
+
+                assertPrivilegeBits(readBits, cugPermProvider.supportedPrivileges(tree, provider.getBits(PrivilegeConstants.JCR_ALL)));
+                assertPrivilegeBits(readNodeBits, cugPermProvider.supportedPrivileges(tree, provider.getBits(PrivilegeConstants.REP_READ_NODES, PrivilegeConstants.JCR_READ_ACCESS_CONTROL)));
+
+            } else {
+                assertTrue(cugPermProvider.supportedPrivileges(tree, readBits).isEmpty());
+                assertTrue(cugPermProvider.supportedPrivileges(tree, readNodeBits).isEmpty());
+                assertTrue(cugPermProvider.supportedPrivileges(tree, readPropBits).isEmpty());
 
-        for (String path : pathMap.keySet()) {
-            boolean expected = pathMap.get(path);
+                assertTrue(cugPermProvider.supportedPrivileges(tree, provider.getBits(PrivilegeConstants.JCR_ALL)).isEmpty());
+                assertTrue(cugPermProvider.supportedPrivileges(tree, provider.getBits(PrivilegeConstants.REP_READ_NODES, PrivilegeConstants.JCR_READ_ACCESS_CONTROL)).isEmpty());
+            }
 
-            assertEquals(path, expected, cugPermProvider.handles(path, Session.ACTION_READ));
-            assertFalse(cugPermProvider.handles(path, Session.ACTION_ADD_NODE));
+            assertTrue(cugPermProvider.supportedPrivileges(tree, provider.getBits(PrivilegeConstants.REP_WRITE)).isEmpty());
+            assertTrue(cugPermProvider.supportedPrivileges(tree, provider.getBits(PrivilegeConstants.JCR_ADD_CHILD_NODES, PrivilegeConstants.JCR_REMOVE_CHILD_NODES, PrivilegeConstants.JCR_REMOVE_NODE)).isEmpty());
+            assertTrue(cugPermProvider.supportedPrivileges(tree, provider.getBits(PrivilegeConstants.JCR_READ_ACCESS_CONTROL)).isEmpty());
         }
     }
 
+    private static void assertPrivilegeBits(@Nonnull PrivilegeBits expected, @Nonnull PrivilegeBits toTest) {
+        assertEquals(expected, toTest.unmodifiable());
+    }
+
+    /**
+     * @see org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider#supportedPrivileges(org.apache.jackrabbit.oak.api.Tree, org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits)
+     */
     @Test
-    public void testHandlesTree() {
-        Map<Tree, Boolean> pathMap = new HashMap<Tree, Boolean>();
-        pathMap.put(root.getTree(SUPPORTED_PATH), false);
-        pathMap.put(root.getTree("/content/a"), true);
-        pathMap.put(root.getTree("/content/a/rep:cugPolicy"), true);
-        pathMap.put(root.getTree("/content/a/b"), true);
-        pathMap.put(root.getTree("/content/a/b/c/jcr:primaryType"), true);
-        pathMap.put(root.getTree("/content/aa"), false);
-        pathMap.put(root.getTree("/content/aa/bb/cc"), true);
-        // paths that may not contain cugs anyway
-        pathMap.put(root.getTree(NODE_TYPES_PATH), false);
-        pathMap.put(root.getTree("/"), false);
-        pathMap.put(root.getTree(UNSUPPORTED_PATH), false);
-        pathMap.put(root.getTree(INVALID_PATH), false);
+    public void testSupportedPrivilegesForNullTree() {
+        PrivilegeBits readBits = PrivilegeBits.BUILT_IN.get(PrivilegeConstants.JCR_READ);
+        PrivilegeBits readNodeBits = PrivilegeBits.BUILT_IN.get(PrivilegeConstants.REP_READ_NODES);
+        PrivilegeBits readPropBits = PrivilegeBits.BUILT_IN.get(PrivilegeConstants.REP_READ_PROPERTIES);
+        PrivilegeBitsProvider provider = new PrivilegeBitsProvider(root);
+
 
-        for (Tree tree : pathMap.keySet()) {
-            boolean expected = pathMap.get(tree);
+        assertTrue(cugPermProvider.supportedPrivileges(null, readBits).isEmpty());
+        assertTrue(cugPermProvider.supportedPrivileges(null, readNodeBits).isEmpty());
+        assertTrue(cugPermProvider.supportedPrivileges(null, readPropBits).isEmpty());
 
-            assertEquals(tree.getPath(), expected, cugPermProvider.handles(tree, PrivilegeBits.BUILT_IN.get(PrivilegeConstants.JCR_READ)));
-            assertEquals(tree.getPath(), expected, cugPermProvider.handles(tree, Permissions.READ));
-            assertEquals(tree.getPath(), expected, cugPermProvider.handles(tree, Permissions.READ_PROPERTY));
-            assertEquals(tree.getPath(), expected, cugPermProvider.handles(tree, Permissions.READ_NODE));
+        assertTrue(cugPermProvider.supportedPrivileges(null, provider.getBits(PrivilegeConstants.JCR_ALL)).isEmpty());
+        assertTrue(cugPermProvider.supportedPrivileges(null, provider.getBits(PrivilegeConstants.REP_READ_NODES, PrivilegeConstants.JCR_READ_ACCESS_CONTROL)).isEmpty());
 
-            assertFalse(cugPermProvider.handles(tree, Permissions.ADD_NODE|Permissions.REMOVE));
+        assertTrue(cugPermProvider.supportedPrivileges(null, provider.getBits(PrivilegeConstants.REP_WRITE)).isEmpty());
+        assertTrue(cugPermProvider.supportedPrivileges(null, provider.getBits(PrivilegeConstants.JCR_ADD_CHILD_NODES, PrivilegeConstants.JCR_REMOVE_CHILD_NODES, PrivilegeConstants.JCR_REMOVE_NODE)).isEmpty());
+        assertTrue(cugPermProvider.supportedPrivileges(null, provider.getBits(PrivilegeConstants.JCR_READ_ACCESS_CONTROL)).isEmpty());
+    }
+
+    /**
+     * @see org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider#supportedPermissions(org.apache.jackrabbit.oak.api.Tree, org.apache.jackrabbit.oak.api.PropertyState, long)
+     */
+    @Test
+    public void testSupportedPermissionsByTree() {
+        for (String path : PATH_INCUG_MAP.keySet()) {
+            boolean isInCug = PATH_INCUG_MAP.get(path);
+            Tree tree = root.getTree(path);
+
+            if (isInCug) {
+                assertEquals(Permissions.READ, cugPermProvider.supportedPermissions(tree, null, Permissions.READ));
+                assertEquals(Permissions.READ_NODE, cugPermProvider.supportedPermissions(tree, null, Permissions.READ_NODE));
+                assertEquals(Permissions.READ_PROPERTY, cugPermProvider.supportedPermissions(tree, null, Permissions.READ_PROPERTY));
+
+                assertEquals(Permissions.READ, cugPermProvider.supportedPermissions(tree, null, Permissions.ALL));
+                assertEquals(Permissions.READ_NODE, cugPermProvider.supportedPermissions(tree, null, Permissions.READ_NODE | Permissions.READ_ACCESS_CONTROL));
+
+            } else {
+                assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tree, null, Permissions.READ));
+                assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tree, null, Permissions.READ_NODE));
+                assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tree, null, Permissions.READ_PROPERTY));
+
+                assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tree, null, Permissions.ALL));
+                assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tree, null, Permissions.READ_NODE | Permissions.READ_ACCESS_CONTROL));
+            }
+
+            assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tree, null, Permissions.WRITE));
+            assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tree, null, Permissions.ADD_NODE|Permissions.REMOVE));
+            assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tree, null, Permissions.READ_ACCESS_CONTROL));
         }
     }
 
+    /**
+     * @see org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider#supportedPermissions(org.apache.jackrabbit.oak.api.Tree, org.apache.jackrabbit.oak.api.PropertyState, long)
+     */
+    @Test
+    public void testSupportedPermissionsByNullTree() {
+        assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(null, null, Permissions.READ));
+        assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(null, null, Permissions.READ_NODE));
+        assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(null, null, Permissions.READ_PROPERTY));
+
+        assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(null, null, Permissions.ALL));
+        assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(null, null, Permissions.READ_NODE | Permissions.READ_ACCESS_CONTROL));
+
+        assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(null, null, Permissions.WRITE));
+        assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(null, null, Permissions.ADD_NODE|Permissions.REMOVE));
+        assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(null, null, Permissions.READ_ACCESS_CONTROL));
+    }
+
+    /**
+     * @see org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider#supportedPermissions(org.apache.jackrabbit.oak.plugins.tree.TreeLocation, long)
+     */
+    @Test
+    public void testSupportedPermissionsByLocation() {
+        for (String path : PATH_INCUG_MAP.keySet()) {
+            boolean isInCug = PATH_INCUG_MAP.get(path);
+            TreeLocation location = TreeLocation.create(root, path);
+
+            if (isInCug) {
+                assertEquals(path, Permissions.READ, cugPermProvider.supportedPermissions(location, Permissions.READ));
+                assertEquals(path, Permissions.READ_NODE, cugPermProvider.supportedPermissions(location, Permissions.READ_NODE));
+                assertEquals(path, Permissions.READ_PROPERTY, cugPermProvider.supportedPermissions(location, Permissions.READ_PROPERTY));
+
+                assertEquals(path, Permissions.READ, cugPermProvider.supportedPermissions(location, Permissions.ALL));
+                assertEquals(path, Permissions.READ_NODE, cugPermProvider.supportedPermissions(location, Permissions.READ_NODE | Permissions.READ_ACCESS_CONTROL));
+            } else {
+                assertEquals(path, Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(location, Permissions.READ));
+                assertEquals(path, Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(location, Permissions.READ_NODE));
+                assertEquals(path, Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(location, Permissions.READ_PROPERTY));
+
+                assertEquals(path, Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(location, Permissions.ALL));
+                assertEquals(path, Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(location, Permissions.READ_NODE | Permissions.READ_ACCESS_CONTROL));
+            }
+
+            assertEquals(path, Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(location, Permissions.READ_ACCESS_CONTROL));
+            assertEquals(path, Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(location, Permissions.MODIFY_ACCESS_CONTROL));
+            assertEquals(path, Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(location, Permissions.ADD_NODE));
+            assertEquals(path, Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(location, Permissions.WRITE));
+        }
+    }
+
+    /**
+     * @see org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider#supportedPermissions(org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission, long)
+     */
     @Test
-    public void testHandlesTreePermission() {
+    public void testSupportedPermissionsByTreePermission() {
         TreePermission rootTp = cugPermProvider.getTreePermission(root.getTree("/"), TreePermission.EMPTY);
 
         Map<TreePermission, Boolean> tpMap = new HashMap<TreePermission, Boolean>();
@@ -177,40 +311,88 @@ public class CugPermissionProviderTest e
         tpMap.put(cugPermProvider.getTreePermission(root.getTree(UNSUPPORTED_PATH), rootTp), false);
 
         for (TreePermission tp : tpMap.keySet()) {
-            boolean expected = tpMap.get(tp);
-
-            assertEquals(expected, cugPermProvider.handles(tp, Permissions.READ));
-            assertEquals(expected, cugPermProvider.handles(tp, Permissions.READ_NODE));
-            assertEquals(expected, cugPermProvider.handles(tp, Permissions.READ_PROPERTY));
+            boolean isInCug = tpMap.get(tp);
 
-            assertFalse(cugPermProvider.handles(tp, Permissions.ADD_NODE|Permissions.REMOVE));
+            if (isInCug) {
+                assertEquals(Permissions.READ, cugPermProvider.supportedPermissions(tp, Permissions.READ));
+                assertEquals(Permissions.READ_NODE, cugPermProvider.supportedPermissions(tp, Permissions.READ_NODE));
+                assertEquals(Permissions.READ_PROPERTY, cugPermProvider.supportedPermissions(tp, Permissions.READ_PROPERTY));
+                assertEquals(Permissions.READ, cugPermProvider.supportedPermissions(tp, Permissions.ALL));
+                assertEquals(Permissions.READ_NODE, cugPermProvider.supportedPermissions(tp, Permissions.READ_NODE | Permissions.READ_ACCESS_CONTROL));
+            } else {
+                assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tp, Permissions.READ));
+                assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tp, Permissions.READ_NODE));
+                assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tp, Permissions.READ_PROPERTY));
+                assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tp, Permissions.ALL));
+                assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tp, Permissions.READ_NODE | Permissions.READ_ACCESS_CONTROL));
+            }
+            assertEquals(Permissions.NO_PERMISSION, cugPermProvider.supportedPermissions(tp, Permissions.ADD_NODE | Permissions.REMOVE));
         }
     }
 
-    @Test
-    public void testHandlesRepositoryPermissions() {
-        assertFalse(cugPermProvider.handlesRepositoryPermissions());
+    /**
+     * @see org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider#isGranted(org.apache.jackrabbit.oak.plugins.tree.TreeLocation, long)
+     */
+    @Test
+    public void testIsGrantedByLocation() throws Exception {
+        for (String p : NOT_READABLE_PATHS) {
+            TreeLocation location = TreeLocation.create(root, p);
+            assertFalse(cugPermProvider.isGranted(location, Permissions.READ));
+            assertFalse(cugPermProvider.isGranted(location, Permissions.READ_NODE));
+            assertFalse(cugPermProvider.isGranted(location, Permissions.READ_PROPERTY));
+
+            assertFalse(cugPermProvider.isGranted(location, Permissions.ALL));
+            assertFalse(cugPermProvider.isGranted(location, Permissions.ADD_NODE));
+            assertFalse(cugPermProvider.isGranted(location, Permissions.READ_ACCESS_CONTROL));
+        }
+
+        for (String p : READABLE_PATHS) {
+            TreeLocation location = TreeLocation.create(root, p);
+            assertTrue(cugPermProvider.isGranted(location, Permissions.READ));
+            assertTrue(cugPermProvider.isGranted(location, Permissions.READ_NODE));
+            assertTrue(cugPermProvider.isGranted(location, Permissions.READ_PROPERTY));
+
+            assertFalse(cugPermProvider.isGranted(location, Permissions.ALL));
+            assertFalse(cugPermProvider.isGranted(location, Permissions.ADD_NODE));
+            assertFalse(cugPermProvider.isGranted(location, Permissions.READ_ACCESS_CONTROL));
+        }
     }
 
+    //------------------------------------------------------< getPrivileges >---
+    /**
+     * @see PermissionProvider#getPrivileges(org.apache.jackrabbit.oak.api.Tree)
+     */
     @Test
     public void getPrivileges() {
-        List<String> paths = ImmutableList.of("/", UNSUPPORTED_PATH,
-                "/content", "/content/a", "/content/a/b",
-                "/content/aa", "/content/bb", "/content/aa/bb/rep:cugPolicy");
-        for (String p : paths) {
-            assertTrue(cugPermProvider.getPrivileges(root.getTree(p)).isEmpty());
+        for (String p : NOT_READABLE_PATHS) {
+            Tree tree = root.getTree(p);
+            if (tree.exists()) {
+                assertTrue(cugPermProvider.getPrivileges(root.getTree(p)).isEmpty());
+            }
         }
     }
 
+    /**
+     * @see PermissionProvider#getPrivileges(org.apache.jackrabbit.oak.api.Tree)
+     */
     @Test
     public void testGetPrivilegesAtCug() {
         Set<String> expected = ImmutableSet.of(
-                        PrivilegeConstants.JCR_READ,
-                        PrivilegeConstants.REP_READ_NODES,
-                        PrivilegeConstants.REP_READ_PROPERTIES);
-        assertEquals(expected, cugPermProvider.getPrivileges(root.getTree("/content/a/b/c")));
+                PrivilegeConstants.JCR_READ,
+                PrivilegeConstants.REP_READ_NODES,
+                PrivilegeConstants.REP_READ_PROPERTIES);
+
+        for (String p : READABLE_PATHS) {
+            Tree tree = root.getTree(p);
+            if (tree.exists()) {
+                assertEquals(expected, cugPermProvider.getPrivileges(tree));
+            }
+        }
     }
 
+    /**
+     * @see PermissionProvider#getPrivileges(org.apache.jackrabbit.oak.api.Tree)
+     */
     @Test
     public void testGetPrivilegesAtCug2() {
         PermissionProvider pp = new CugPermissionProvider(root, ImmutableSet.of(testGroupPrincipal), ImmutableSet.of(SUPPORTED_PATH), CugContext.INSTANCE);
@@ -225,118 +407,100 @@ public class CugPermissionProviderTest e
         assertTrue(pp.getPrivileges(root.getTree("/content/a/b/c")).isEmpty());
     }
 
+    //------------------------------------------------------< hasPrivileges >---
+    /**
+     * @see PermissionProvider#hasPrivileges(org.apache.jackrabbit.oak.api.Tree, String...)
+     */
     @Test
-    public void hasReadPrivileges() {
-        List<String> paths = ImmutableList.of("/", UNSUPPORTED_PATH,
-                "/content", "/content/a", "/content/a/b",
-                "/content/aa", "/content/bb", "/content/aa/bb/rep:cugPolicy");
-        for (String p : paths) {
-            Tree tree = root.getTree(p);
-            assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.JCR_READ));
-            assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.REP_READ_NODES));
-            assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.REP_READ_PROPERTIES));
-            assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.REP_READ_NODES, PrivilegeConstants.REP_READ_PROPERTIES));
-        }
-
-        Tree cugTree = root.getTree("/content/a/b/c");
-        assertTrue(cugPermProvider.hasPrivileges(cugTree, PrivilegeConstants.JCR_READ));
-        assertTrue(cugPermProvider.hasPrivileges(cugTree, PrivilegeConstants.REP_READ_NODES));
-        assertTrue(cugPermProvider.hasPrivileges(cugTree, PrivilegeConstants.REP_READ_PROPERTIES));
-        assertTrue(cugPermProvider.hasPrivileges(cugTree, PrivilegeConstants.REP_READ_NODES, PrivilegeConstants.REP_READ_PROPERTIES));
-    }
-
-    @Test
-    public void hasNonReadPrivileges() {
-        List<String> paths = ImmutableList.of("/", UNSUPPORTED_PATH,
-                "/content", "/content/a", "/content/a/b", "/content/a/b/c",
-                "/content/aa", "/content/bb", "/content/aa/bb/rep:cugPolicy");
-        for (String p : paths) {
+    public void testHasReadPrivileges() {
+        for (String p : NOT_READABLE_PATHS) {
             Tree tree = root.getTree(p);
-            assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.JCR_WRITE));
-            assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.JCR_LIFECYCLE_MANAGEMENT));
-            assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.JCR_READ, PrivilegeConstants.JCR_LIFECYCLE_MANAGEMENT));
-            assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.JCR_READ_ACCESS_CONTROL));
-            assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.JCR_ALL));
+            if (tree.exists()) {
+                assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.JCR_READ));
+                assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.REP_READ_NODES));
+                assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.REP_READ_PROPERTIES));
+                assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.REP_READ_NODES, PrivilegeConstants.REP_READ_PROPERTIES));
+            }
         }
     }
 
+    /**
+     * @see PermissionProvider#hasPrivileges(org.apache.jackrabbit.oak.api.Tree, String...)
+     */
     @Test
-    public void testIsGrantedRead() {
-        List<String> paths = ImmutableList.of("/", UNSUPPORTED_PATH,
-                "/content", "/content/a", "/content/a/b",
-                "/content/aa", "/content/bb", "/content/aa/bb/rep:cugPolicy");
-        for (String p : paths) {
+    public void testHasReadPrivilegesAtCug() {
+        for (String p : READABLE_PATHS) {
             Tree tree = root.getTree(p);
-            assertFalse(cugPermProvider.isGranted(tree, null, Permissions.READ));
-            assertFalse(cugPermProvider.isGranted(tree, tree.getProperty(JCR_PRIMARYTYPE), Permissions.READ_PROPERTY));
+            if (tree.exists()) {
+                assertTrue(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.JCR_READ));
+                assertTrue(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.REP_READ_NODES));
+                assertTrue(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.REP_READ_PROPERTIES));
+                assertTrue(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.REP_READ_NODES, PrivilegeConstants.REP_READ_PROPERTIES));
+            }
         }
-
-        Tree cugTree = root.getTree("/content/a/b/c");
-        assertTrue(cugPermProvider.isGranted(cugTree, null, Permissions.READ));
-        assertTrue(cugPermProvider.isGranted(cugTree, null, Permissions.READ_NODE));
-        assertTrue(cugPermProvider.isGranted(cugTree, cugTree.getProperty(JCR_PRIMARYTYPE), Permissions.READ_PROPERTY));
     }
 
+    /**
+     * @see PermissionProvider#hasPrivileges(org.apache.jackrabbit.oak.api.Tree, String...)
+     */
     @Test
-    public void testIsGrantedNonRead() {
-        List<String> paths = ImmutableList.of("/", UNSUPPORTED_PATH,
-                        "/content", "/content/a", "/content/a/b", "/content/a/b/c",
-                        "/content/aa", "/content/bb", "/content/aa/bb/rep:cugPolicy");
-        for (String p : paths) {
+    public void hasNonReadPrivileges() {
+        for (String p : Iterables.concat(READABLE_PATHS, NOT_READABLE_PATHS)) {
             Tree tree = root.getTree(p);
-            assertFalse(cugPermProvider.isGranted(tree, null, Permissions.ALL));
-            assertFalse(cugPermProvider.isGranted(tree, null, Permissions.READ|Permissions.READ_ACCESS_CONTROL));
-            assertFalse(cugPermProvider.isGranted(tree, null, Permissions.REMOVE_NODE));
+            if (tree.exists()) {
+                assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.JCR_WRITE));
+                assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.JCR_LIFECYCLE_MANAGEMENT));
+                assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.JCR_READ, PrivilegeConstants.JCR_LIFECYCLE_MANAGEMENT));
+                assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.JCR_READ_ACCESS_CONTROL));
+                assertFalse(cugPermProvider.hasPrivileges(tree, PrivilegeConstants.JCR_ALL));
+            }
         }
     }
 
-    @Test
-    public void testIsGrantedJcrActions() {
-        List<String> paths = ImmutableList.of("/", UNSUPPORTED_PATH,
-                "/content", "/content/a", "/content/a/b",
-                "/content/aa", "/content/bb", "/content/aa/bb/rep:cugPolicy");
-        for (String p : paths) {
-            assertFalse(cugPermProvider.isGranted(p, Session.ACTION_READ));
-            assertFalse(cugPermProvider.isGranted(p, Session.ACTION_ADD_NODE));
-            assertFalse(cugPermProvider.isGranted(p, Session.ACTION_READ + ',' + Session.ACTION_ADD_NODE));
-        }
-
-        assertTrue(cugPermProvider.isGranted("/content/a/b/c", Session.ACTION_READ));
-        assertFalse(cugPermProvider.isGranted("/content/a/b/c", Session.ACTION_ADD_NODE));
-        assertFalse(cugPermProvider.isGranted("/content/a/b/c", Session.ACTION_READ + ',' + Session.ACTION_ADD_NODE));
+    //--------------------------------------------< getRepositoryPermission >---
+    /**
+     * @see org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider#getRepositoryPermission()
+     */
+    @Test
+    public void testGetRepositoryPermissions() {
+        assertSame(RepositoryPermission.EMPTY, cugPermProvider.getRepositoryPermission());
     }
 
+    //--------------------------------------------------< getTreePermission >---
+    /**
+     * @see PermissionProvider#getTreePermission(org.apache.jackrabbit.oak.api.Tree, org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission)
+     */
     @Test
     public void testGetTreePermissions() throws AccessDeniedException {
         TreePermission rootTp = cugPermProvider.getTreePermission(root.getTree("/"), TreePermission.EMPTY);
-        assertTrue(rootTp.getClass().getName().endsWith("EmptyCugPermission"));
+        assertTrue(rootTp instanceof EmptyCugTreePermission);
 
         TreePermission contentTp = cugPermProvider.getTreePermission(root.getTree(SUPPORTED_PATH), rootTp);
-        assertTrue(contentTp.getClass().getName().endsWith("EmptyCugPermission"));
+        assertTrue(contentTp instanceof EmptyCugTreePermission);
 
         TreePermission aTp = cugPermProvider.getTreePermission(root.getTree("/content/a"), contentTp);
-        assertTrue(aTp.getClass().getName().endsWith("CugTreePermission"));
+        assertTrue(aTp instanceof CugTreePermission);
 
         TreePermission bTp = cugPermProvider.getTreePermission(root.getTree("/content/a/b"), aTp);
-        assertTrue(bTp.getClass().getName().endsWith("CugTreePermission"));
+        assertTrue(bTp instanceof CugTreePermission);
 
         TreePermission cTp = cugPermProvider.getTreePermission(root.getTree("/content/a/b/c"), bTp);
-        assertTrue(cTp.getClass().getName().endsWith("CugTreePermission"));
+        assertTrue(cTp instanceof CugTreePermission);
 
         TreePermission aaTp = cugPermProvider.getTreePermission(root.getTree("/content/aa"), contentTp);
-        assertTrue(aaTp.getClass().getName().endsWith("EmptyCugPermission"));
+        assertTrue(aaTp instanceof EmptyCugTreePermission);
 
         TreePermission bbTp = cugPermProvider.getTreePermission(root.getTree("/content/aa/bb"), aaTp);
-        assertTrue(bbTp.getClass().getName().endsWith("CugTreePermission"));
+        assertTrue(bbTp instanceof CugTreePermission);
 
         TreePermission ccTp = cugPermProvider.getTreePermission(root.getTree("/content/aa/bb/cc"), bbTp);
-        assertTrue(ccTp.getClass().getName().endsWith("CugTreePermission"));
+        assertTrue(ccTp instanceof CugTreePermission);
 
         // false cug-policy node (wrong nt)
         Tree aaTree = root.getTree("/content/aa");
         new NodeUtil(aaTree).addChild(CugConstants.REP_CUG_POLICY, NT_OAK_UNSTRUCTURED);
         TreePermission aaTp2 = cugPermProvider.getTreePermission(root.getTree("/content/aa"), contentTp);
-        assertTrue(aaTp2.getClass().getName().endsWith("EmptyCugPermission"));
+        assertTrue(aaTp2 instanceof EmptyCugTreePermission);
 
         TreePermission falseCugTp = cugPermProvider.getTreePermission(root.getTree("/content/aa/rep:cugPolicy"), aaTp2);
         assertNotSame(TreePermission.EMPTY, falseCugTp);
@@ -349,4 +513,62 @@ public class CugPermissionProviderTest e
         assertSame(TreePermission.EMPTY, cugPermProvider.getTreePermission(root.getTree("/jcr:system"), rootTp));
         assertSame(TreePermission.EMPTY, cugPermProvider.getTreePermission(root.getTree(UNSUPPORTED_PATH), rootTp));
     }
+
+    //-------------------------------< isGranted(Tree, PropertyState, long) >---
+    /**
+     * @see PermissionProvider#isGranted(org.apache.jackrabbit.oak.api.Tree, org.apache.jackrabbit.oak.api.PropertyState, long)
+     */
+    @Test
+    public void testIsGrantedNonRead() {
+        for (String p : Iterables.concat(READABLE_PATHS, NOT_READABLE_PATHS)) {
+            Tree tree = root.getTree(p);
+            if (tree.exists()) {
+                assertFalse(cugPermProvider.isGranted(tree, null, Permissions.ALL));
+                assertFalse(cugPermProvider.isGranted(tree, null, Permissions.READ|Permissions.READ_ACCESS_CONTROL));
+                assertFalse(cugPermProvider.isGranted(tree, null, Permissions.REMOVE_NODE));
+            }
+        }
+    }
+
+    /**
+     * @see PermissionProvider#isGranted(org.apache.jackrabbit.oak.api.Tree, org.apache.jackrabbit.oak.api.PropertyState, long)
+     */
+    @Test
+    public void testIsGrantedRead() {
+        for (String p : NOT_READABLE_PATHS) {
+            Tree tree = root.getTree(p);
+            if (tree.exists()) {
+                assertFalse(cugPermProvider.isGranted(tree, null, Permissions.READ));
+                assertFalse(cugPermProvider.isGranted(tree, tree.getProperty(JCR_PRIMARYTYPE), Permissions.READ_PROPERTY));
+            }
+        }
+
+        for (String p : READABLE_PATHS) {
+            Tree tree = root.getTree(p);
+            if (tree.exists()) {
+                assertTrue(cugPermProvider.isGranted(tree, null, Permissions.READ));
+                assertTrue(cugPermProvider.isGranted(tree, null, Permissions.READ_NODE));
+                assertTrue(cugPermProvider.isGranted(tree, tree.getProperty(JCR_PRIMARYTYPE), Permissions.READ_PROPERTY));
+            }
+        }
+    }
+
+    //------------------------------------------< isGranted(String, String) >---
+    /**
+     * @see PermissionProvider#isGranted(String, String)
+     */
+    @Test
+    public void testIsGrantedJcrActions() {
+        for (String p : NOT_READABLE_PATHS) {
+            assertFalse(cugPermProvider.isGranted(p, Session.ACTION_READ));
+            assertFalse(cugPermProvider.isGranted(p, Session.ACTION_ADD_NODE));
+            assertFalse(cugPermProvider.isGranted(p, Session.ACTION_READ + ',' + Session.ACTION_ADD_NODE));
+        }
+
+        for (String p : READABLE_PATHS) {
+            assertTrue(cugPermProvider.isGranted(p, Session.ACTION_READ));
+            assertFalse(cugPermProvider.isGranted(p, Session.ACTION_ADD_NODE));
+            assertFalse(cugPermProvider.isGranted(p, Session.ACTION_READ + ',' + Session.ACTION_ADD_NODE));
+        }
+    }
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeAuthorizationConfiguration.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeAuthorizationConfiguration.java?rev=1691388&r1=1691387&r2=1691388&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeAuthorizationConfiguration.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeAuthorizationConfiguration.java Thu Jul 16 12:59:17 2015
@@ -106,7 +106,7 @@ public class CompositeAuthorizationConfi
                         pp = aggrPermissionProviders.get(0);
                         break;
                     default :
-                        pp = new CompositePermissionProvider(root, aggrPermissionProviders);
+                        pp = new CompositePermissionProvider(root, aggrPermissionProviders, getContext());
                 }
                 return pp;
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositePermissionProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositePermissionProvider.java?rev=1691388&r1=1691387&r2=1691388&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositePermissionProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositePermissionProvider.java Thu Jul 16 12:59:17 2015
@@ -16,7 +16,6 @@
  */
 package org.apache.jackrabbit.oak.security.authorization.composite;
 
-import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -24,15 +23,15 @@ import java.util.Set;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
 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.plugins.tree.RootFactory;
+import org.apache.jackrabbit.oak.plugins.tree.TreeLocation;
 import org.apache.jackrabbit.oak.plugins.tree.impl.ImmutableTree;
 import org.apache.jackrabbit.oak.security.authorization.permission.PermissionUtil;
+import org.apache.jackrabbit.oak.spi.security.Context;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions;
@@ -41,7 +40,6 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
-import org.apache.jackrabbit.util.Text;
 
 /**
  * Permission provider implementation that aggregates a list of different
@@ -55,14 +53,17 @@ class CompositePermissionProvider implem
 
     private final Root root;
     private final List<AggregatedPermissionProvider> pps;
+    private final Context ctx;
+
     private final CompositeRepositoryPermission repositoryPermission;
 
     private Root immutableRoot;
     private PrivilegeBitsProvider privilegeBitsProvider;
 
-    CompositePermissionProvider(@Nonnull Root root, @Nonnull List<AggregatedPermissionProvider> pps) {
+    CompositePermissionProvider(@Nonnull Root root, @Nonnull List<AggregatedPermissionProvider> pps, @Nonnull Context acContext) {
         this.root = root;
         this.pps = pps;
+        this.ctx = acContext;
 
         repositoryPermission = new CompositeRepositoryPermission();
         immutableRoot = RootFactory.createReadOnlyRoot(root);
@@ -83,16 +84,24 @@ class CompositePermissionProvider implem
     @Nonnull
     @Override
     public Set<String> getPrivileges(@Nullable Tree tree) {
-        PrivilegeBits result = null;
         Tree immutableTree = PermissionUtil.getImmutableTree(tree, immutableRoot);
-        for (AggregatedPermissionProvider pp : filter(pps, immutableTree)) {
-            PrivilegeBits privs = privilegeBitsProvider.getBits(pp.getPrivileges(immutableTree));
-            if (result == null) {
-                result = PrivilegeBits.getInstance();
-                result.add(privs);
-            } else {
-                // FIXME: only retain privs that are handled by prev. pp (and thus are denied)
-                result.retain(privs);
+
+        PrivilegeBits result = PrivilegeBits.getInstance();
+        PrivilegeBits denied = PrivilegeBits.getInstance();
+
+        for (AggregatedPermissionProvider aggregatedPermissionProvider : pps) {
+            PrivilegeBits supported = aggregatedPermissionProvider.supportedPrivileges(immutableTree, null).modifiable();
+            if (doEvaluate(supported)) {
+                PrivilegeBits granted = privilegeBitsProvider.getBits(aggregatedPermissionProvider.getPrivileges(immutableTree));
+                // make sure privs denied by a previous provider are substracted
+                if (!denied.isEmpty()) {
+                    result.add(granted.modifiable().diff(denied));
+                } else {
+                    result.add(granted);
+                }
+                // update the set of denied privs by comparing the granted privs
+                // the complete set of supported privileges.
+                denied.add(supported.diff(granted));
             }
         }
         return privilegeBitsProvider.getPrivilegeNames(result);
@@ -100,22 +109,25 @@ class CompositePermissionProvider implem
 
     @Override
     public boolean hasPrivileges(@Nullable Tree tree, @Nonnull String... privilegeNames) {
-        final Tree immutableTree = PermissionUtil.getImmutableTree(tree, immutableRoot);
-        for (final String privName : privilegeBitsProvider.getAggregatedPrivilegeNames(privilegeNames)) {
-            Iterable<AggregatedPermissionProvider> providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
-                @Override
-                public boolean apply(AggregatedPermissionProvider pp) {
-                    // the permissionprovider is never null
-                    return (immutableTree == null) ? pp.handlesRepositoryPermissions() : pp.handles(immutableTree, privilegeBitsProvider.getBits(privName));
-                }
-            });
-            for (AggregatedPermissionProvider pp : providers) {
-                if (!pp.hasPrivileges(immutableTree, privName)) {
-                    return false;
+        Tree immutableTree = PermissionUtil.getImmutableTree(tree, immutableRoot);
+        PrivilegeBits privilegeBits = privilegeBitsProvider.getBits(privilegeNames);
+
+        boolean hasPrivileges = false;
+        PrivilegeBits coveredPrivs = PrivilegeBits.getInstance();
+
+        for (AggregatedPermissionProvider aggregatedPermissionProvider : pps) {
+            PrivilegeBits supported = aggregatedPermissionProvider.supportedPrivileges(immutableTree, privilegeBits);
+            if (doEvaluate(supported)) {
+                Set<String> supportedNames = privilegeBitsProvider.getPrivilegeNames(supported);
+                hasPrivileges = aggregatedPermissionProvider.hasPrivileges(immutableTree, supportedNames.toArray(new String[supportedNames.size()]));
+                coveredPrivs.add(supported);;
+
+                if (!hasPrivileges) {
+                    break;
                 }
             }
         }
-        return true;
+        return hasPrivileges && coveredPrivs.includes(privilegeBits);
     }
 
     @Nonnull
@@ -141,102 +153,68 @@ class CompositePermissionProvider implem
     @Override
     public boolean isGranted(@Nonnull Tree parent, @Nullable PropertyState property, long permissions) {
         Tree immParent = PermissionUtil.getImmutableTree(parent, immutableRoot);
-        if (Permissions.isAggregate(permissions)) {
-            for (final long permission : Permissions.aggregates(permissions)) {
-                if (!grantsPermission(immParent, property, permission, filter(parent, permission))) {
-                    return false;
+
+        boolean isGranted = false;
+        long coveredPermissions = Permissions.NO_PERMISSION;
+
+        for (AggregatedPermissionProvider aggregatedPermissionProvider : pps) {
+            long supportedPermissions = aggregatedPermissionProvider.supportedPermissions(immParent, property, permissions);
+            if (doEvaluate(supportedPermissions)) {
+                isGranted = aggregatedPermissionProvider.isGranted(immParent, property, supportedPermissions);
+                coveredPermissions |= supportedPermissions;
+
+                if (!isGranted) {
+                    break;
                 }
             }
-            return true;
-        } else {
-            return grantsPermission(immParent, property, permissions, filter(immParent, permissions));
         }
+        return isGranted && coveredPermissions == permissions;
     }
 
     @Override
     public boolean isGranted(@Nonnull String oakPath, @Nonnull String jcrActions) {
-        final String[] actions = Text.explode(jcrActions, ',', false);
-        switch (actions.length) {
-            case 0: return true;
-            case 1:
-                return grantsAction(oakPath, actions[0], filter(oakPath, actions[0]));
-            default:
-                for (final String action : actions) {
-                    if (!grantsAction(oakPath, action, filter(oakPath, action))) {
-                        return false;
-                    }
-                }
-                return true;
-        }
-    }
+        TreeLocation location = TreeLocation.create(immutableRoot, oakPath);
+        boolean isAcContent = ctx.definesLocation(location);
 
-    //--------------------------------------------------------------------------
+        long permissions = Permissions.getPermissions(jcrActions, location, isAcContent);
 
-    private Iterable<AggregatedPermissionProvider> filter(@Nonnull final Tree tree, final long permissions) {
-        return Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
-            @Override
-            public boolean apply(AggregatedPermissionProvider pp) {
-                // the permissionprovider is never null
-                return pp.handles(tree, permissions);
-            }
-        });
-    }
+        PropertyState property = location.getProperty();
+        Tree tree = (property == null) ? location.getTree() : location.getParent().getTree();
 
-    private Iterable<AggregatedPermissionProvider> filter(@Nonnull final String oakPath, final String actions) {
-        return Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
-            @Override
-            public boolean apply(AggregatedPermissionProvider pp) {
-                // the permissionprovider is never null
-                return pp.handles(oakPath, actions);
-            }
-        });
-    }
+        if (tree != null) {
+            return isGranted(tree, property, permissions);
+        } else {
+            boolean isGranted = false;
+            long coveredPermissions = Permissions.NO_PERMISSION;
 
-    private static Iterable<AggregatedPermissionProvider> filter(
-            @Nonnull final List<AggregatedPermissionProvider> providers,
-            @Nullable final Tree tree) {
-        return Iterables.filter(providers, new Predicate<AggregatedPermissionProvider>() {
-            @Override
-            public boolean apply(AggregatedPermissionProvider pp) {
-                // the permissionprovider is never null
-                return (tree != null) || pp.handlesRepositoryPermissions();
-            }
-        });
-    }
+            for (AggregatedPermissionProvider aggregatedPermissionProvider : pps) {
+                long supportedPermissions = aggregatedPermissionProvider.supportedPermissions(location, permissions);
+                if (doEvaluate(supportedPermissions)) {
+                    isGranted = aggregatedPermissionProvider.isGranted(location, supportedPermissions);
+                    coveredPermissions |= supportedPermissions;
 
-    private static boolean grantsPermission(@Nonnull final Tree parent,
-                                            @Nullable PropertyState property,
-                                            final long permission,
-                                            @Nonnull Iterable<AggregatedPermissionProvider> providers) {
-        Iterator<AggregatedPermissionProvider> it = providers.iterator();
-        boolean isGranted = false;
-        while (it.hasNext()) {
-            AggregatedPermissionProvider pp = it.next();
-            isGranted = pp.isGranted(parent, property, permission);
-            if (!isGranted) {
-                break;
+                    if (!isGranted) {
+                        break;
+                    }
+                }
             }
+            return isGranted && coveredPermissions == permissions;
         }
-        return isGranted;
     }
 
-    private static boolean grantsAction(@Nonnull final String oakPath,
-                                        @Nonnull final String action,
-                                        @Nonnull Iterable<AggregatedPermissionProvider> providers) {
-        Iterator<AggregatedPermissionProvider> it = providers.iterator();
-        boolean isGranted = false;
-        while (it.hasNext()) {
-            AggregatedPermissionProvider pp = it.next();
-            isGranted = pp.isGranted(oakPath, action);
-            if (!isGranted) {
-                return false;
-            }
-        }
-        return isGranted;
+    //------------------------------------------------------------< private >---
+    private static boolean doEvaluate(long supportedPermissions) {
+        return supportedPermissions != Permissions.NO_PERMISSION;
     }
 
-    //--------------------------------------------------------------------------
+    private static boolean doEvaluate(PrivilegeBits supportedPrivileges) {
+        return !supportedPrivileges.isEmpty();
+    }
 
+    //-----------------------------------------------------< TreePermission >---
+    /**
+     * {@code TreePermission} implementation that wraps multiple implementations.
+     */
     private final class CompositeTreePermission implements TreePermission {
 
         private final ImmutableTree tree;
@@ -274,16 +252,18 @@ class CompositePermissionProvider implem
         @Override
         public boolean canRead() {
             if (canRead == null) {
-                canRead = false;
+                boolean readable = false;
                 for (Map.Entry<AggregatedPermissionProvider, TreePermission> entry : map.entrySet()) {
                     TreePermission tp = entry.getValue();
-                    if (entry.getKey().handles(tp, Permissions.READ_NODE)) {
-                        canRead = entry.getValue().canRead();
-                        if (!canRead) {
+                    long supported = entry.getKey().supportedPermissions(tp, Permissions.READ_NODE);
+                    if (doEvaluate(supported)) {
+                        readable = tp.canRead();
+                        if (!readable) {
                             break;
                         }
                     }
                 }
+                canRead = readable;
             }
             return canRead;
         }
@@ -293,10 +273,11 @@ class CompositePermissionProvider implem
             boolean canReadProperty = false;
             for (Map.Entry<AggregatedPermissionProvider, TreePermission> entry : map.entrySet()) {
                 TreePermission tp = entry.getValue();
-                if (entry.getKey().handles(tp, Permissions.READ_PROPERTY)) {
-                    canReadProperty = entry.getValue().canRead(property);
+                long supported = entry.getKey().supportedPermissions(tp, Permissions.READ_PROPERTY);
+                if (doEvaluate(supported)) {
+                    canReadProperty = tp.canRead(property);
                     if (!canReadProperty) {
-                        return false;
+                        break;
                     }
                 }
             }
@@ -315,44 +296,31 @@ class CompositePermissionProvider implem
 
         @Override
         public boolean isGranted(long permissions) {
-            if (Permissions.isAggregate(permissions)) {
-                for (long permission : Permissions.aggregates(permissions)) {
-                    if (!grantsPermission(permission, null)) {
-                        return false;
-                    }
-                }
-                return true;
-            } else {
-                return grantsPermission(permissions, null);
-            }
+            return grantsPermission(permissions, null);
         }
 
         @Override
         public boolean isGranted(long permissions, @Nonnull PropertyState property) {
-            if (Permissions.isAggregate(permissions)) {
-                for (long permission : Permissions.aggregates(permissions)) {
-                    if (!grantsPermission(permission, property)) {
-                        return false;
-                    }
-                }
-                return true;
-            } else {
-                return grantsPermission(permissions, property);
-            }
+            return grantsPermission(permissions, property);
         }
 
-        private boolean grantsPermission(long permission, @Nullable PropertyState property) {
+        private boolean grantsPermission(long permissions, @Nullable PropertyState property) {
             boolean isGranted = false;
+            long coveredPermissions = Permissions.NO_PERMISSION;
+
             for (Map.Entry<AggregatedPermissionProvider, TreePermission> entry : map.entrySet()) {
-                if (entry.getKey().handles(this, permission)) {
+                long supportedPermissions = entry.getKey().supportedPermissions(tree, property, permissions);
+                if (doEvaluate(supportedPermissions)) {
                     TreePermission tp = entry.getValue();
-                    isGranted = (property == null) ? tp.isGranted(permission) : tp.isGranted(permission, property);
+                    isGranted = (property == null) ? tp.isGranted(supportedPermissions) : tp.isGranted(supportedPermissions, property);
+                    coveredPermissions |= supportedPermissions;
+
                     if (!isGranted) {
                         return false;
                     }
                 }
             }
-            return isGranted;
+            return isGranted && coveredPermissions == permissions;
         }
 
         @Nonnull
@@ -365,24 +333,28 @@ class CompositePermissionProvider implem
         }
     }
 
+    //-----------------------------------------------< RepositoryPermission >---
     /**
-     * TODO
+     * {@code RepositoryPermission} implementation that wraps multiple implementations.
      */
     private final class CompositeRepositoryPermission implements RepositoryPermission {
 
         @Override
         public boolean isGranted(long repositoryPermissions) {
-            Iterator<AggregatedPermissionProvider> it = filter(pps, null).iterator();
             boolean isGranted = false;
-            while (it.hasNext()) {
-                AggregatedPermissionProvider pp = it.next();
-                isGranted = pp.getRepositoryPermission().isGranted(repositoryPermissions);
-                if (!isGranted) {
-                    return false;
-                }
+            long coveredPermissions = Permissions.NO_PERMISSION;
 
+            for (AggregatedPermissionProvider aggregatedPermissionProvider : pps) {
+                long supportedPermissions = aggregatedPermissionProvider.supportedPermissions(null, null, repositoryPermissions);
+                if (doEvaluate(supportedPermissions)) {
+                    isGranted = aggregatedPermissionProvider.getRepositoryPermission().isGranted(supportedPermissions);
+                    coveredPermissions |= supportedPermissions;
+                    if (!isGranted) {
+                        break;
+                    }
+                }
             }
-            return isGranted;
+            return isGranted && coveredPermissions == repositoryPermissions;
         }
     }
 }