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 2023/03/09 12:25:28 UTC

[jackrabbit-oak] branch OAK-10135 created (now dde38356dc)

This is an automated email from the ASF dual-hosted git repository.

angela pushed a change to branch OAK-10135
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git


      at dde38356dc OAK-10135 : JackrabbitAccessControlManager.getEffectivePolicies(Set principals) should include ReadPolicy

This branch includes the following new commits:

     new dde38356dc OAK-10135 : JackrabbitAccessControlManager.getEffectivePolicies(Set principals) should include ReadPolicy

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[jackrabbit-oak] 01/01: OAK-10135 : JackrabbitAccessControlManager.getEffectivePolicies(Set principals) should include ReadPolicy

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

angela pushed a commit to branch OAK-10135
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git

commit dde38356dc8cb23910c10eb036726844674063d7
Author: angela <an...@adobe.com>
AuthorDate: Thu Mar 9 13:25:13 2023 +0100

    OAK-10135 : JackrabbitAccessControlManager.getEffectivePolicies(Set principals) should include ReadPolicy
---
 .../impl/PrincipalBasedAccessControlManager.java   |  7 ++-
 .../impl/AbstractPrincipalBasedTest.java           | 16 +++++++
 .../impl/AccessControlManagerLimitedUserTest.java  | 10 ++++
 .../principalbased/impl/EffectivePolicyTest.java   |  6 +--
 .../impl/ImmutablePrincipalPolicyTest.java         |  2 +-
 .../PrincipalBasedAccessControlManagerTest.java    | 26 +++++------
 .../impl/ReadablePathsAccessControlTest.java       |  6 ++-
 .../impl/TransientPrincipalTest.java               |  4 +-
 .../accesscontrol/AccessControlManagerImpl.java    |  6 ++-
 .../accesscontrol/PolicyComparator.java            | 33 ++++++++++----
 .../accesscontrol/AbstractAccessControlTest.java   |  8 ++++
 .../AccessControlManagerImplTest.java              | 28 ++++++------
 ...AccessControlManagerLimitedPermissionsTest.java | 53 +++++++++++++++++++---
 .../AccessControlWithUnknownPrincipalTest.java     | 11 ++---
 .../accesscontrol/PolicyComparatorTest.java        | 26 +++++++++++
 .../accesscontrol/ReadPolicyTest.java              | 53 ++++++++++++++++++++--
 .../authorization/accesscontrol/ReadPolicy.java    | 20 ++++++++
 .../authorization/accesscontrol/package-info.java  |  2 +-
 .../accesscontrol/ReadPolicyTest.java              | 20 ++++++++
 19 files changed, 268 insertions(+), 69 deletions(-)

diff --git a/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedAccessControlManager.java b/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedAccessControlManager.java
index 21876483c2..fe00e9695b 100644
--- a/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedAccessControlManager.java
+++ b/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedAccessControlManager.java
@@ -69,7 +69,6 @@ import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -145,13 +144,17 @@ class PrincipalBasedAccessControlManager extends AbstractAccessControlManager im
         // this implementation only takes effect if the complete set of principals can be handled. see also
         // PrincipalBasedAuthorizationConfiguration.getPermissionProvider
         if (canHandle(principals)) {
-            Set<AccessControlPolicy> effective = new HashSet<>(principals.size());
+            List<AccessControlPolicy> effective = new ArrayList<>(principals.size());
             for (Principal principal : principals) {
                 AccessControlPolicy policy = createPolicy(principal, true);
                 if (policy != null) {
                     effective.add(policy);
                 }
             }
+            // add read-policy if there are configured paths
+            if (ReadPolicy.canAccessReadPolicy(getPermissionProvider(), readPaths.toArray(new String[0]))) {
+                effective.add(ReadPolicy.INSTANCE);
+            }
             return effective.toArray(new AccessControlPolicy[0]);
         } else {
             return new JackrabbitAccessControlPolicy[0];
diff --git a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java
index b7d64f690b..68e06622f5 100644
--- a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java
+++ b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java
@@ -36,6 +36,7 @@ import org.apache.jackrabbit.oak.security.internal.SecurityProviderHelper;
 import org.apache.jackrabbit.oak.spi.mount.Mounts;
 import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
 import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
+import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.ReadPolicy;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
 import org.apache.jackrabbit.oak.spi.security.authorization.principalbased.FilterProvider;
 import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
@@ -46,6 +47,7 @@ import org.junit.Before;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
 import javax.jcr.security.Privilege;
 import java.security.Principal;
 import java.util.Collections;
@@ -54,6 +56,8 @@ import java.util.UUID;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.NT_OAK_UNSTRUCTURED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -220,4 +224,16 @@ public abstract class AbstractPrincipalBasedTest extends AbstractSecurityTest {
     PrincipalBasedAuthorizationConfiguration getPrincipalBasedAuthorizationConfiguration() {
         return principalBasedAuthorizationConfiguration;
     }
+    
+    static void assertEffectivePolicies(@NotNull AccessControlPolicy[] effective, int expectedPolicies, 
+                                        int principalPolicySize, boolean readPolicyExpected) {
+        assertEquals(expectedPolicies, effective.length);
+        if (principalPolicySize > -1) {
+            assertTrue(effective[0] instanceof ImmutablePrincipalPolicy);
+            assertEquals(principalPolicySize, ((ImmutablePrincipalPolicy) effective[0]).size());
+        }
+        if (readPolicyExpected) {
+            assertTrue(effective[effective.length-1] instanceof ReadPolicy);
+        }
+    }
 }
\ No newline at end of file
diff --git a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedUserTest.java b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedUserTest.java
index fca1d6dccc..52e43e5a5f 100644
--- a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedUserTest.java
+++ b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedUserTest.java
@@ -30,6 +30,7 @@ import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
 import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
 import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.ImmutableACL;
+import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.ReadPolicy;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -258,6 +259,15 @@ public class AccessControlManagerLimitedUserTest extends AbstractPrincipalBasedT
         root.commit();
         testRoot.refresh();
         assertPolicies(testAcMgr.getEffectivePolicies(ImmutableSet.of(systemPrincipal)), ImmutableACL.class, 1, 2);
+
+        // make sure test-user has read-accesscontrol permission on any readable-path
+        grant(testPrincipal, PathUtils.ROOT_PATH, JCR_READ_ACCESS_CONTROL);
+        root.commit();
+        testRoot.refresh();
+
+        AccessControlPolicy[] effective = testAcMgr.getEffectivePolicies(ImmutableSet.of(systemPrincipal));;
+        assertPolicies(effective, ImmutableACL.class, 2, 2);
+        assertTrue(effective[1] instanceof ReadPolicy);
     }
 
     @Test(expected = AccessDeniedException.class)
diff --git a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/EffectivePolicyTest.java b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/EffectivePolicyTest.java
index d12f18b39b..b77477fa57 100644
--- a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/EffectivePolicyTest.java
+++ b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/EffectivePolicyTest.java
@@ -96,8 +96,7 @@ public class EffectivePolicyTest extends AbstractPrincipalBasedTest {
     @Test
     public void testEffectivePolicyByPrincipal() throws Exception {
         AccessControlPolicy[] effective = acMgr.getEffectivePolicies(ImmutableSet.of(validPrincipal));
-        assertEquals(1, effective.length);
-        assertTrue(effective[0] instanceof ImmutablePrincipalPolicy);
+        assertEffectivePolicies(effective, 2, 2, true);
 
         List<JackrabbitAccessControlEntry> entries = ((ImmutablePrincipalPolicy)effective[0]).getEntries();
         assertEquals(2, entries.size());
@@ -113,8 +112,7 @@ public class EffectivePolicyTest extends AbstractPrincipalBasedTest {
     @Test
     public void testEffectivePolicyByPrincipal2() throws Exception {
         AccessControlPolicy[] effective = acMgr.getEffectivePolicies(ImmutableSet.of(validPrincipal2));
-        assertEquals(1, effective.length);
-        assertTrue(effective[0] instanceof ImmutablePrincipalPolicy);
+        assertEffectivePolicies(effective, 2, 2, true);
 
         List<JackrabbitAccessControlEntry> entries = ((ImmutablePrincipalPolicy)effective[0]).getEntries();
         assertEquals(2, entries.size());
diff --git a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ImmutablePrincipalPolicyTest.java b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ImmutablePrincipalPolicyTest.java
index e17d8af0ff..d36fb64714 100644
--- a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ImmutablePrincipalPolicyTest.java
+++ b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ImmutablePrincipalPolicyTest.java
@@ -64,7 +64,7 @@ public class ImmutablePrincipalPolicyTest extends AbstractPrincipalBasedTest {
         int expectedHashCode = immutable.hashCode();
         ImmutablePrincipalPolicy ipp = new ImmutablePrincipalPolicy(policy.getPrincipal(), policy.getOakPath(), policy.getEntries(), policy.getRestrictionProvider(), policy.getNamePathMapper());
         assertEquals(expectedHashCode, ipp.hashCode());
-        assertEquals(expectedHashCode, new ImmutablePrincipalPolicy(policy).hashCode());
+        assertEquals(ipp.hashCode(), new ImmutablePrincipalPolicy(policy).hashCode());
     }
 
     @Test
diff --git a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedAccessControlManagerTest.java b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedAccessControlManagerTest.java
index 7cdb2aba30..16fdc18b36 100644
--- a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedAccessControlManagerTest.java
+++ b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedAccessControlManagerTest.java
@@ -86,12 +86,6 @@ public class PrincipalBasedAccessControlManagerTest extends AbstractPrincipalBas
         return new PrincipalPolicyImpl(validPrincipal, oakPath, getMgrProvider(root));
     }
 
-    private static void assertEffectivePolicy(@NotNull AccessControlPolicy[] effective, int size) {
-        assertEquals(1, effective.length);
-        assertTrue(effective[0] instanceof ImmutablePrincipalPolicy);
-        assertEquals(size, ((ImmutablePrincipalPolicy) effective[0]).size());
-    }
-
     @Test(expected = AccessControlException.class)
     public void testGetApplicablePoliciesNullPrincipal() throws Exception {
         acMgr.getApplicablePolicies((Principal) null);
@@ -160,7 +154,8 @@ public class PrincipalBasedAccessControlManagerTest extends AbstractPrincipalBas
 
     @Test
     public void testGetEffectivePoliciesNothingSet() throws Exception {
-        assertEquals(0, acMgr.getEffectivePolicies(ImmutableSet.of(validPrincipal)).length);
+        AccessControlPolicy[] effective = acMgr.getEffectivePolicies(ImmutableSet.of(validPrincipal));
+        assertEffectivePolicies(effective, 1, -1, true);
     }
 
     @Test
@@ -171,12 +166,12 @@ public class PrincipalBasedAccessControlManagerTest extends AbstractPrincipalBas
 
         // transient changes => no effective policy
         AccessControlPolicy[] effective = acMgr.getEffectivePolicies(ImmutableSet.of(validPrincipal));
-        assertEquals(0, effective.length);
+        assertEffectivePolicies(effective, 1, -1, true);
 
         // after commit => effective policy present
         root.commit();
         effective = acMgr.getEffectivePolicies(ImmutableSet.of(validPrincipal));
-        assertEffectivePolicy(effective, 1);
+        assertEffectivePolicies(effective, 2, 1, true);
     }
 
     @Test
@@ -184,7 +179,8 @@ public class PrincipalBasedAccessControlManagerTest extends AbstractPrincipalBas
         JackrabbitAccessControlPolicy emptyPolicy = acMgr.getApplicablePolicies(validPrincipal)[0];
         acMgr.setPolicy(emptyPolicy.getPath(), emptyPolicy);
         root.commit();
-        assertEquals(0, acMgr.getEffectivePolicies(ImmutableSet.of(validPrincipal)).length);
+        AccessControlPolicy[] effective = acMgr.getEffectivePolicies(ImmutableSet.of(validPrincipal));
+        assertEffectivePolicies(effective, 1, -1, true);
     }
 
     @Test
@@ -197,7 +193,7 @@ public class PrincipalBasedAccessControlManagerTest extends AbstractPrincipalBas
         getUserManager(latestRoot).getAuthorizable(validPrincipal).remove();
         latestRoot.commit();
         try {
-            assertEquals(0, acMgr.getEffectivePolicies(ImmutableSet.of(validPrincipal)).length);
+            assertEffectivePolicies(acMgr.getEffectivePolicies(ImmutableSet.of(validPrincipal)), 1, -1, true);
         } finally {
             root.refresh();
             getUserManager(root).createSystemUser(id, INTERMEDIATE_PATH);
@@ -227,7 +223,7 @@ public class PrincipalBasedAccessControlManagerTest extends AbstractPrincipalBas
         latestRoot.getTree(getNamePathMapper().getOakPath(validPrincipal.getPath())).getChild(REP_PRINCIPAL_POLICY).remove();
         latestRoot.commit();
 
-        assertEquals(0, acMgr.getEffectivePolicies(ImmutableSet.of(validPrincipal)).length);
+        assertEffectivePolicies(acMgr.getEffectivePolicies(ImmutableSet.of(validPrincipal)), 1, -1, true);
     }
 
     @Test(expected = AccessControlException.class)
@@ -445,9 +441,9 @@ public class PrincipalBasedAccessControlManagerTest extends AbstractPrincipalBas
         addPrincipalBasedEntry(policy, PathUtils.ROOT_PATH, JCR_READ);
         root.commit();
 
-        assertEffectivePolicy(acMgr.getEffectivePolicies(testJcrPath), 2);
-        assertEffectivePolicy(acMgr.getEffectivePolicies(testContentJcrPath), 2);
-        assertEffectivePolicy(acMgr.getEffectivePolicies(PathUtils.ROOT_PATH), 1);
+        assertEffectivePolicies(acMgr.getEffectivePolicies(testJcrPath), 1,2, false);
+        assertEffectivePolicies(acMgr.getEffectivePolicies(testContentJcrPath), 1, 2, false);
+        assertEffectivePolicies(acMgr.getEffectivePolicies(PathUtils.ROOT_PATH), 1,1, false);
     }
 
     @Test
diff --git a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsAccessControlTest.java b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsAccessControlTest.java
index 0c94593be5..3f82bdbe7c 100644
--- a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsAccessControlTest.java
+++ b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsAccessControlTest.java
@@ -231,7 +231,9 @@ public class ReadablePathsAccessControlTest extends AbstractPrincipalBasedTest {
 
     @Test
     public void testGetEffectivePoliciesByPrincipal() throws Exception {
-        // NOTE: lookup by principal currently doesn't include READ_POLICY in accordance to default ac implementation
-        assertEquals(0, acMgr.getEffectivePolicies(Collections.singleton(testPrincipal)).length);
+        // OAK-10135 : include read-policy in effective policies by principal result
+        AccessControlPolicy[] effective = acMgr.getEffectivePolicies(Collections.singleton(testPrincipal));
+        assertEquals(1, effective.length);
+        assertTrue(effective[0] instanceof ReadPolicy);
     }
 }
\ No newline at end of file
diff --git a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/TransientPrincipalTest.java b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/TransientPrincipalTest.java
index eee533f016..0d17776c84 100644
--- a/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/TransientPrincipalTest.java
+++ b/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/TransientPrincipalTest.java
@@ -140,14 +140,14 @@ public class TransientPrincipalTest extends AbstractPrincipalBasedTest {
     @Test
     public void testGetEffectivePolicies() throws Exception {
         AccessControlPolicy[] effective = acMgr.getEffectivePolicies(ImmutableSet.of(principal));
-        assertEquals(0, effective.length);
+        assertEffectivePolicies(effective, 1, -1, true);
 
         PrincipalPolicyImpl policy = getApplicable();
         policy.addEntry(testJcrPath, privilegesFromNames(JCR_WRITE));
         acMgr.setPolicy(policy.getPath(), policy);
 
         effective = acMgr.getEffectivePolicies(ImmutableSet.of(principal));
-        assertEquals(0, effective.length);
+        assertEffectivePolicies(effective, 1, -1, true);
     }
 
     @Test
diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImpl.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImpl.java
index 4a040c2125..76e193a36f 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImpl.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImpl.java
@@ -370,7 +370,7 @@ public class AccessControlManagerImpl extends AbstractAccessControlManager imple
         
         Root r = getLatestRoot();
         Result aceResult = searchAces(principals, r);
-        Set<JackrabbitAccessControlList> effective = Sets.newTreeSet(new PolicyComparator());
+        Set<AccessControlPolicy> effective = Sets.newTreeSet(new PolicyComparator());
 
         Set<String> processed = Sets.newHashSet();
         Predicate<Tree> predicate = new PrincipalPredicate(principals);
@@ -394,6 +394,10 @@ public class AccessControlManagerImpl extends AbstractAccessControlManager imple
                 }
             }
         }
+        // add read-policy if there are readable paths configured where the editing session has READ_ACCESS_CONTROL granted
+        if (ReadPolicy.canAccessReadPolicy(getPermissionProvider(), readPaths.toArray(new String[0]))) {
+            effective.add(ReadPolicy.INSTANCE);
+        }
         return effective.toArray(new AccessControlPolicy[0]);
     }
 
diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/PolicyComparator.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/PolicyComparator.java
index cfc17ef99b..9a7030ec35 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/PolicyComparator.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/PolicyComparator.java
@@ -20,27 +20,40 @@ import com.google.common.primitives.Ints;
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 
+import javax.jcr.security.AccessControlPolicy;
 import java.util.Comparator;
 
-final class PolicyComparator implements Comparator<JackrabbitAccessControlPolicy> {
+final class PolicyComparator implements Comparator<AccessControlPolicy> {
 
     @Override
-    public int compare(JackrabbitAccessControlPolicy policy1, JackrabbitAccessControlPolicy policy2) {
+    public int compare(AccessControlPolicy policy1, AccessControlPolicy policy2) {
         if (policy1.equals(policy2)) {
             return 0;
+        } else if (policy1 instanceof JackrabbitAccessControlPolicy && policy2 instanceof JackrabbitAccessControlPolicy) {
+            return compare((JackrabbitAccessControlPolicy) policy1, (JackrabbitAccessControlPolicy) policy2);
         } else {
-            String p1 = policy1.getPath();
-            String p2 = policy2.getPath();
-
-            if (p1 == null) {
+            if (policy1 instanceof JackrabbitAccessControlPolicy) {
                 return -1;
-            } else if (p2 == null) {
+            } else if (policy2 instanceof JackrabbitAccessControlPolicy) {
                 return 1;
             } else {
-                int depth1 = PathUtils.getDepth(p1);
-                int depth2 = PathUtils.getDepth(p2);
-                return (depth1 == depth2) ? p1.compareTo(p2) : Ints.compare(depth1, depth2);
+                return 0;
             }
         }
     }
+
+    private static int compare(JackrabbitAccessControlPolicy policy1, JackrabbitAccessControlPolicy policy2) {
+        String p1 = policy1.getPath();
+        String p2 = policy2.getPath();
+
+        if (p1 == null) {
+            return -1;
+        } else if (p2 == null) {
+            return 1;
+        } else {
+            int depth1 = PathUtils.getDepth(p1);
+            int depth2 = PathUtils.getDepth(p2);
+            return (depth1 == depth2) ? p1.compareTo(p2) : Ints.compare(depth1, depth2);
+        }
+    }
 }
\ No newline at end of file
diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AbstractAccessControlTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AbstractAccessControlTest.java
index 55a2b760bb..4b11e805dd 100644
--- a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AbstractAccessControlTest.java
+++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AbstractAccessControlTest.java
@@ -27,6 +27,7 @@ import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
 import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
 import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.ACE;
+import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.ReadPolicy;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.Restriction;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
@@ -179,7 +180,14 @@ public abstract class AbstractAccessControlTest extends AbstractSecurityTest {
     }
     
     static void assertPolicies(@Nullable AccessControlPolicy[] policies, long expectedSize) {
+        assertPolicies(policies, expectedSize, false);
+    }
+    
+    static void assertPolicies(@Nullable AccessControlPolicy[] policies, long expectedSize, boolean readPolicyExpected) {
         assertNotNull(policies);
         assertEquals(expectedSize, policies.length);
+        if (policies.length > 0) {
+            assertEquals(readPolicyExpected, policies[policies.length - 1] instanceof ReadPolicy);
+        }
     }
 }
diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImplTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImplTest.java
index fc0a33e344..12256cbe37 100644
--- a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImplTest.java
+++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImplTest.java
@@ -1591,14 +1591,14 @@ public class AccessControlManagerImplTest extends AbstractAccessControlTest impl
 
         for (Set<Principal> principals : principalSets) {
             AccessControlPolicy[] policies = acMgr.getEffectivePolicies(principals);
-            assertPolicies(policies, 0);
+            assertPolicies(policies, 1, true);
         }
 
         setupPolicy(testPath);
         // changes not yet persisted -> no effecitve policies found for testprincipal
         for (Set<Principal> principals : principalSets) {
             AccessControlPolicy[] policies = acMgr.getEffectivePolicies(principals);
-            assertPolicies(policies, 0);
+            assertPolicies(policies, 1, true);
         }
 
         root.commit();
@@ -1606,9 +1606,9 @@ public class AccessControlManagerImplTest extends AbstractAccessControlTest impl
         for (Set<Principal> principals : principalSets) {
             AccessControlPolicy[] policies = acMgr.getEffectivePolicies(principals);
             if (principals.contains(testPrincipal)) {
-                assertPolicies(policies, 1);
+                assertPolicies(policies, 2, true);
             } else {
-                assertPolicies(policies, 0);
+                assertPolicies(policies, 1, true);
             }
         }
 
@@ -1619,9 +1619,9 @@ public class AccessControlManagerImplTest extends AbstractAccessControlTest impl
         for (Set<Principal> principals : principalSets) {
             AccessControlPolicy[] policies = acMgr.getEffectivePolicies(principals);
             if (principals.contains(testPrincipal)) {
-                assertPolicies(policies, 1);
+                assertPolicies(policies, 2, true);
             } else {
-                assertPolicies(policies, 0);
+                assertPolicies(policies, 1, true);
             }
         }
 
@@ -1630,9 +1630,9 @@ public class AccessControlManagerImplTest extends AbstractAccessControlTest impl
         for (Set<Principal> principals : principalSets) {
             AccessControlPolicy[] policies = acMgr.getEffectivePolicies(principals);
             if (principals.contains(testPrincipal)) {
-                assertPolicies(policies, 2);
+                assertPolicies(policies, 3, true);
             } else {
-                assertPolicies(policies, 0);
+                assertPolicies(policies, 1, true);
             }
         }
     }
@@ -1651,7 +1651,7 @@ public class AccessControlManagerImplTest extends AbstractAccessControlTest impl
         root.commit();
 
         AccessControlPolicy[] policies = acMgr.getEffectivePolicies(principalSet);
-        assertPolicies(policies, 1);
+        assertPolicies(policies, 2, true);
 
         // add another policy
         Tree child = TreeUtil.addChild(root.getTree(testPath), "child", JcrConstants.NT_UNSTRUCTURED);
@@ -1659,7 +1659,7 @@ public class AccessControlManagerImplTest extends AbstractAccessControlTest impl
         setupPolicy(childPath);
         root.commit();
 
-        assertPolicies(acMgr.getEffectivePolicies(principalSet), 2);
+        assertPolicies(acMgr.getEffectivePolicies(principalSet), 3, true);
     }
 
     @Test
@@ -1689,7 +1689,7 @@ public class AccessControlManagerImplTest extends AbstractAccessControlTest impl
             root.commit();
 
             AccessControlPolicy[] effectivePolicies = acMgr.getEffectivePolicies(principalSet);
-            assertPolicies(effectivePolicies, 3);
+            assertPolicies(effectivePolicies, 4, true);
 
             assertNull(((JackrabbitAccessControlPolicy) effectivePolicies[0]).getPath());
             assertEquals(testPath, ((JackrabbitAccessControlPolicy) effectivePolicies[1]).getPath());
@@ -1723,7 +1723,7 @@ public class AccessControlManagerImplTest extends AbstractAccessControlTest impl
 
         for (Principal princ : principals) {
             AccessControlPolicy[] policies = acMgr.getEffectivePolicies(ImmutableSet.of(princ));
-            assertPolicies(policies, 1);
+            assertPolicies(policies, 2, true);
             assertTrue(policies[0] instanceof AccessControlList);
 
             AccessControlList acl = (AccessControlList) policies[0];
@@ -1750,7 +1750,7 @@ public class AccessControlManagerImplTest extends AbstractAccessControlTest impl
 
         AccessControlManagerImpl mgr = createAccessControlManager(r, getNamePathMapper());
         AccessControlPolicy[] policies = mgr.getEffectivePolicies(ImmutableSet.of(testPrincipal));
-        assertPolicies(policies, 0);
+        assertPolicies(policies, 1, true);
     }
 
     @Test
@@ -1770,7 +1770,7 @@ public class AccessControlManagerImplTest extends AbstractAccessControlTest impl
 
         AccessControlManagerImpl mgr = createAccessControlManager(r, getNamePathMapper());
         AccessControlPolicy[] policies = mgr.getEffectivePolicies(ImmutableSet.of(testPrincipal));
-        assertPolicies(policies, 0);
+        assertPolicies(policies, 1, true);
     }
     
     private static QueryEngine mockQueryEngine(@NotNull Tree aceTree) throws Exception {
diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerLimitedPermissionsTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerLimitedPermissionsTest.java
index 44aebe340a..68969133a6 100644
--- a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerLimitedPermissionsTest.java
+++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerLimitedPermissionsTest.java
@@ -54,6 +54,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
+import static org.apache.jackrabbit.oak.security.authorization.accesscontrol.AbstractAccessControlTest.assertPolicies;
 import static org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants.REP_POLICY;
 import static org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants.REP_RESTRICTIONS;
 import static org.junit.Assert.assertArrayEquals;
@@ -120,11 +121,6 @@ public class AccessControlManagerLimitedPermissionsTest extends AbstractSecurity
         return npMapper;
     }
 
-    private static void assertPolicies(@Nullable AccessControlPolicy[] policies, long expectedSize) {
-        assertNotNull(policies);
-        assertEquals(expectedSize, policies.length);
-    }
-
     private void setupPolicy(@Nullable String path, @Nullable Privilege... privileges) throws RepositoryException {
         Privilege[] privs = (privileges == null || privileges.length == 0) ? testPrivileges : privileges;
         TestUtility.setupPolicy(getAccessControlManager(root), path, testPrincipal, privs, true, TestUtility.getGlobRestriction("*", getValueFactory(root)), null);
@@ -515,7 +511,7 @@ public class AccessControlManagerLimitedPermissionsTest extends AbstractSecurity
         acMgr.setPolicy(testPath, acl);
 
         // grant access at childpath
-        setupPolicy(childPath, privilegesFromNames(PrivilegeConstants.JCR_READ, PrivilegeConstants.JCR_READ_ACCESS_CONTROL));
+        setupPolicy(childPath, privs);
         root.commit();
 
         testRoot.refresh();
@@ -524,4 +520,49 @@ public class AccessControlManagerLimitedPermissionsTest extends AbstractSecurity
         AccessControlPolicy[] policies = testAcMgr.getEffectivePolicies(principals);
         assertPolicies(policies, 1);
     }
+
+    @Test
+    public void testGetEffectivePoliciesByPrincipalsReadPolicy1() throws Exception {
+        // grant test-principal READ access at root node (but not READ_ACCESS_CONTROL)
+        setupPolicy(PathUtils.ROOT_PATH, privilegesFromNames(PrivilegeConstants.JCR_READ));
+        root.commit();
+
+        testRoot.refresh();
+
+        // effective policies must NOT include ReadPolicy 
+        Set<Principal> principals = ImmutableSet.of(testPrincipal, EveryonePrincipal.getInstance());
+        AccessControlPolicy[] policies = testAcMgr.getEffectivePolicies(principals);
+        assertPolicies(policies, 0, false);
+    }
+
+    @Test
+    public void testGetEffectivePoliciesByPrincipalsReadPolicy2() throws Exception {
+        // grant test-principal READ_ACCESS_CONTROL access at root node (but not READ)
+        setupPolicy(PathUtils.ROOT_PATH, privilegesFromNames(PrivilegeConstants.JCR_READ_ACCESS_CONTROL));
+        root.commit();
+
+        testRoot.refresh();
+
+        // effective policies must include ReadPolicy 
+        // but no path-not-found must be raised if the readable-path is not accessible
+        Set<Principal> principals = ImmutableSet.of(testPrincipal, EveryonePrincipal.getInstance());
+        AccessControlPolicy[] policies = testAcMgr.getEffectivePolicies(principals);
+        // since no other ac-setup exists for 'everyone' principal -> only ReadPolicy is found
+        assertPolicies(policies, 1, true);
+    }
+    
+    @Test
+    public void testGetEffectivePoliciesByPrincipalsIncludesReadPolicy3() throws Exception {
+        // grant test-principal READ and READ_ACCESS_CONTROL at root node 
+        setupPolicy(PathUtils.ROOT_PATH, privilegesFromNames(PrivilegeConstants.JCR_READ, PrivilegeConstants.JCR_READ_ACCESS_CONTROL));
+        root.commit();
+
+        testRoot.refresh();
+
+        // effective policies must include ReadPolicy 
+        Set<Principal> principals = ImmutableSet.of(testPrincipal, EveryonePrincipal.getInstance());
+        AccessControlPolicy[] policies = testAcMgr.getEffectivePolicies(principals);
+        // since no other ac-setup exists for 'everyone' principal -> only ReadPolicy is found
+        assertPolicies(policies, 1, true);
+    }
 }
diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlWithUnknownPrincipalTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlWithUnknownPrincipalTest.java
index 889970e8c7..e0a54ce1f9 100644
--- a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlWithUnknownPrincipalTest.java
+++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlWithUnknownPrincipalTest.java
@@ -16,13 +16,11 @@
  */
 package org.apache.jackrabbit.oak.security.authorization.accesscontrol;
 
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
 import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
 import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
-import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
 import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
 import org.apache.jackrabbit.oak.spi.xml.ImportBehavior;
 import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter;
@@ -33,7 +31,6 @@ import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
 import javax.jcr.RepositoryException;
-import javax.jcr.ValueFactory;
 import javax.jcr.security.AccessControlException;
 import javax.jcr.security.AccessControlPolicy;
 import java.security.Principal;
@@ -63,7 +60,6 @@ public class AccessControlWithUnknownPrincipalTest extends AbstractAccessControl
     private final String importBehaviorName;
 
     private AccessControlManagerImpl acMgr;
-    private ValueFactory valueFactory;
 
     public AccessControlWithUnknownPrincipalTest(int importBehavior, String importBehaviorName) {
         this.importBehavior = importBehavior;
@@ -75,7 +71,6 @@ public class AccessControlWithUnknownPrincipalTest extends AbstractAccessControl
         super.before();
 
         acMgr = new AccessControlManagerImpl(root, getNamePathMapper(), getSecurityProvider());
-        valueFactory = getValueFactory(root);
     }
 
     @Override
@@ -180,8 +175,10 @@ public class AccessControlWithUnknownPrincipalTest extends AbstractAccessControl
             AccessControlPolicy[] effective = acMgr.getEffectivePolicies(Collections.singleton(unknown));
             switch (importBehavior) {
                 case ImportBehavior.IGNORE:
+                    assertPolicies(effective, 0, false);
+                    break;
                 case ImportBehavior.BESTEFFORT:
-                    assertEquals(0, effective.length);
+                    assertPolicies(effective, 1, true);
                     break;
                 case ImportBehavior.ABORT:
                 default:
@@ -196,7 +193,7 @@ public class AccessControlWithUnknownPrincipalTest extends AbstractAccessControl
     public void testGetEffectivePoliciesInternalPrincipal() throws Exception {
         Principal unknown = new PrincipalImpl(getUnknownPrincipalName());
         AccessControlPolicy[] effective = acMgr.getEffectivePolicies(Collections.singleton(unknown));
-        assertEquals(0, effective.length);
+        assertPolicies(effective, 1, true);
     }
 
     @Test
diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/PolicyComparatorTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/PolicyComparatorTest.java
index 5bed6417c4..87bf7e4f53 100644
--- a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/PolicyComparatorTest.java
+++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/PolicyComparatorTest.java
@@ -19,10 +19,14 @@ package org.apache.jackrabbit.oak.security.authorization.accesscontrol;
 import com.google.common.primitives.Ints;
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.ReadPolicy;
 import org.junit.Test;
 
+import javax.jcr.security.AccessControlPolicy;
+
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.when;
 
 public class PolicyComparatorTest {
@@ -97,4 +101,26 @@ public class PolicyComparatorTest {
         int expected = Ints.compare(PathUtils.getDepth("/path"), PathUtils.getDepth("/a/deeper/path"));
         assertEquals(expected, comparator.compare(policy1, policy2));
     }
+
+    @Test
+    public void testOneNonJackrabbitPolicy() {
+        JackrabbitAccessControlPolicy p1 = mock(JackrabbitAccessControlPolicy.class);
+        AccessControlPolicy p2 = mock(AccessControlPolicy.class);
+        
+        assertEquals(-1, comparator.compare(p1, p2));
+        assertEquals(1, comparator.compare(p2, p1));
+        
+        verifyNoInteractions(p1, p2);
+    }
+    
+    @Test
+    public void testNonJackrabbitPolicies() {
+        AccessControlPolicy p1 = mock(AccessControlPolicy.class);
+        AccessControlPolicy p2 = mock(AccessControlPolicy.class);
+        assertEquals(0, comparator.compare(p1, p2));
+        assertEquals(0, comparator.compare(p2, p1));
+        assertEquals(0, comparator.compare(p1, ReadPolicy.INSTANCE));
+        
+        verifyNoInteractions(p1, p2);
+    }
 }
\ No newline at end of file
diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/ReadPolicyTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/ReadPolicyTest.java
index 2ddd85fd9b..08e71d78eb 100644
--- a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/ReadPolicyTest.java
+++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/ReadPolicyTest.java
@@ -16,21 +16,31 @@
  */
 package org.apache.jackrabbit.oak.security.authorization.accesscontrol;
 
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
 import javax.jcr.security.AccessControlPolicy;
 import javax.jcr.security.NamedAccessControlPolicy;
 
+import com.google.common.collect.Lists;
+import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.AbstractSecurityTest;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
 import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
 import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.ReadPolicy;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
+import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
+import static org.apache.jackrabbit.oak.security.authorization.accesscontrol.AbstractAccessControlTest.assertPolicies;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -41,11 +51,27 @@ import static org.junit.Assert.fail;
  *
  * @since OAK 1.0
  */
+@RunWith(Parameterized.class)
 public class ReadPolicyTest extends AbstractSecurityTest {
 
+    private final Set<String> configuredPaths;
+
     private Set<String> readPaths;
     private Set<String> subTreePaths = new HashSet<>();
 
+    @Parameterized.Parameters(name = "Configured Readable Paths = {1}")
+    public static Collection<Object[]> parameters() {
+        return Lists.newArrayList(
+                new Object[] {null , "null => default set"},
+                new Object[] {Collections.emptySet(), "empty set"},
+                new Object[] {Collections.emptySet(), "/"+JcrConstants.JCR_SYSTEM}
+        );
+    }
+
+    public ReadPolicyTest(@Nullable Set<String> configuredPaths, @NotNull String name) {
+        this.configuredPaths = configuredPaths;
+    }
+    
     @Override
     @Before
     public void before() throws Exception {
@@ -63,6 +89,16 @@ public class ReadPolicyTest extends AbstractSecurityTest {
         }
     }
 
+    @Override
+    protected ConfigurationParameters getSecurityConfigParameters() {
+        if (configuredPaths != null) {
+            ConfigurationParameters params = ConfigurationParameters.of(PermissionConstants.PARAM_READ_PATHS, configuredPaths);
+            return ConfigurationParameters.of(AuthorizationConfiguration.NAME, params);
+        } else {
+            return super.getSecurityConfigParameters();
+        }
+    }
+
     @Test
     public void testGetPolicies() throws Exception {
         for (String path : readPaths) {
@@ -119,13 +155,22 @@ public class ReadPolicyTest extends AbstractSecurityTest {
             assertTrue(found);
         }
     }
+    
+    @Test
+    public void testGetEffectivePoliciesPrincipalSet() throws Exception {
+        AccessControlPolicy[] policies = getAccessControlManager(root).getEffectivePolicies(Collections.singleton(EveryonePrincipal.getInstance()));
+        long expSize = (readPaths.isEmpty()) ? 0 : 1;
+        assertPolicies(policies, expSize, true);
+    }
 
     @Test
     public void testGetName() throws Exception {
-        AccessControlPolicy[] policies = getAccessControlManager(root).getPolicies(readPaths.iterator().next());
-        assertEquals(1, policies.length);
-        assertTrue(policies[0] instanceof NamedAccessControlPolicy);
-        assertNotNull(((NamedAccessControlPolicy) policies[0]).getName());
+        if (!readPaths.isEmpty()) {
+            AccessControlPolicy[] policies = getAccessControlManager(root).getPolicies(readPaths.iterator().next());
+            assertEquals(1, policies.length);
+            assertTrue(policies[0] instanceof NamedAccessControlPolicy);
+            assertNotNull(((NamedAccessControlPolicy) policies[0]).getName());
+        }
     }
 
 }
\ No newline at end of file
diff --git a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/ReadPolicy.java b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/ReadPolicy.java
index 3ed3530eac..b905fb0ae6 100644
--- a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/ReadPolicy.java
+++ b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/ReadPolicy.java
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol;
 
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions;
 import org.apache.jackrabbit.util.Text;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -49,4 +51,22 @@ public final class ReadPolicy implements NamedAccessControlPolicy {
         }
         return false;
     }
+    
+    /**
+     * Evaluates if a {@code ReadPolicy} is accessible for a session object. Note that this method does not verify if 
+     * the specified paths point to existing/accessible trees.
+     * 
+     * @param permissionProvider A permission provider used for evaluating access
+     * @param oakPaths The set of configured readable paths.
+     * @return {@code true} if the given permission provider has READ_ACCESS_CONTROL granted on any of the specified 
+     * readable oak paths; {@code false} otherwise.
+     */
+    public static boolean canAccessReadPolicy(@NotNull PermissionProvider permissionProvider, @NotNull String... oakPaths) {
+        for (String path : oakPaths) {
+            if (permissionProvider.isGranted(path, Permissions.PERMISSION_NAMES.get(Permissions.READ_ACCESS_CONTROL))) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
\ No newline at end of file
diff --git a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/package-info.java b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/package-info.java
index fdd635b15e..fef70dc81f 100644
--- a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/package-info.java
+++ b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/package-info.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.10.0")
+@Version("1.11.0")
 package org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/ReadPolicyTest.java b/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/ReadPolicyTest.java
index 2e8d32b130..f3895e9744 100644
--- a/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/ReadPolicyTest.java
+++ b/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/ReadPolicyTest.java
@@ -18,6 +18,8 @@ package org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol;
 
 import com.google.common.collect.ImmutableSet;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions;
 import org.junit.Test;
 
 import java.util.Collections;
@@ -25,6 +27,8 @@ import java.util.Collections;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class ReadPolicyTest {
 
@@ -54,4 +58,20 @@ public class ReadPolicyTest {
         assertTrue(ReadPolicy.hasEffectiveReadPolicy(ImmutableSet.of("/another/path", "/some/random/path"), path));
         assertTrue(ReadPolicy.hasEffectiveReadPolicy(ImmutableSet.of("/another/path", PathUtils.ROOT_PATH), path));
     }
+    
+    @Test
+    public void testCanAccessReadPolicy() {
+        PermissionProvider pp = mock(PermissionProvider.class);
+        
+        assertFalse(ReadPolicy.canAccessReadPolicy(pp));
+        assertFalse(ReadPolicy.canAccessReadPolicy(pp, "/test/path"));
+        
+        when(pp.isGranted("/test/path", Permissions.PERMISSION_NAMES.get(Permissions.READ_ACCESS_CONTROL))).thenReturn(true);
+
+        assertFalse(ReadPolicy.canAccessReadPolicy(pp));
+        assertFalse(ReadPolicy.canAccessReadPolicy(pp, "/different/path"));
+
+        assertTrue(ReadPolicy.canAccessReadPolicy(pp, "/test/path"));
+        assertTrue(ReadPolicy.canAccessReadPolicy(pp, "/different/path", "/test/path"));
+    }
 }
\ No newline at end of file