Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java	(revision 1652391)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java	(revision )
@@ -21,6 +21,7 @@
 import java.util.Set;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import javax.jcr.Session;
 
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.api.PropertyState;
@@ -120,6 +121,23 @@
             isGranted = compiledPermissions.isGranted(oakPath, permissions);
         }
         return isGranted;
+    }
+
+    @Override
+    public boolean canRead(@Nonnull String oakTreePath, @Nullable String propertyName) {
+        String path = (propertyName != null) ? oakTreePath + '/' + propertyName : oakTreePath;
+        if (isVersionStorePath(oakTreePath)) {
+            return isGranted(path, Session.ACTION_READ);
+        } else {
+            boolean isAcContent = acConfig.getContext().definesPath(oakTreePath, propertyName);
+            long permission;
+            if (isAcContent) {
+                permission = Permissions.READ_ACCESS_CONTROL;
+            } else {
+                permission = (propertyName == null) ? Permissions.READ_NODE : Permissions.READ_PROPERTY;
+            }
+            return compiledPermissions.isGranted(path, permission);
+        }
     }
 
     //---------------------------------------< AggregatedPermissionProvider >---
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/OpenPermissionProvider.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/OpenPermissionProvider.java	(revision 1652391)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/OpenPermissionProvider.java	(revision )
@@ -74,4 +74,9 @@
     public boolean isGranted(@Nonnull String oakPath, @Nonnull String jcrActions) {
         return true;
     }
+
+    @Override
+    public boolean canRead(@Nonnull String oakTreePath, @Nullable String propertyName) {
+        return true;
+    }
 }
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/EmptyPermissionProvider.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/EmptyPermissionProvider.java	(revision 1652391)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/EmptyPermissionProvider.java	(revision )
@@ -73,4 +73,9 @@
     public boolean isGranted(@Nonnull String oakPath, @Nonnull String jcrActions) {
         return false;
     }
+
+    @Override
+    public boolean canRead(@Nonnull String oakTreePath, @Nullable String propertyName) {
+        return false;
+    }
 }
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/Context.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/Context.java	(revision 1652391)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/Context.java	(revision )
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.oak.spi.security;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
@@ -75,6 +76,18 @@
     boolean definesLocation(@Nonnull TreeLocation location);
 
     /**
+     * Reveals if the specified {@code path} is defined by the security
+     * module that exposes this {@link Context} instance.
+     *
+     *
+     * @param treePath The tree path to be tested.
+     * @param propertyName An optional property name to be tested.
+     * @return {@code true} if the specified path is related to or
+     * defined by the security module.
+     */
+    boolean definesPath(@Nonnull String treePath, @Nullable String propertyName);
+
+    /**
      * Default implementation of the {@code Context} interface that always returns
      * {@code false}.
      */
@@ -96,6 +109,11 @@
 
         @Override
         public boolean definesLocation(@Nonnull TreeLocation location) {
+            return false;
+        }
+
+        @Override
+        public boolean definesPath(@Nonnull String treePath, String propertyName) {
             return false;
         }
 
\ No newline at end of file
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionProvider.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionProvider.java	(revision 1652391)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionProvider.java	(revision )
@@ -123,4 +123,20 @@
      * {@code false} otherwise.
      */
     boolean isGranted(@Nonnull String oakPath, @Nonnull String jcrActions);
+
+    /**
+     * Test if the item identified by the given {@code oakTreePath} and (optionally)
+     * {@code propertyName} can be accessed by the editing session. Whether or
+     * not the path is resolved to the corresponding item is an implementation
+     * detail and might be omitted for performance reasons. In this case the
+     * permission evaluation might not be able to properly evaluate restrictions
+     * that require access to the item and is required to not expose items
+     * that would not be accessible when evaluated calling
+     * {@code #isGranted(Tree, PropertyState, long)}.
+     *
+     * @param oakTreePath The path of the tree.
+     * @param propertyName Optional name of the property or {@code null}.
+     * @return {@code true} if the item can be read; {@code false} otherwise.
+     */
+    boolean canRead(@Nonnull String oakTreePath, @Nullable String propertyName);
 }
Index: oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugContext.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugContext.java	(revision 1652391)
+++ oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugContext.java	(revision )
@@ -56,7 +56,12 @@
             return (p == null) ? definesTree(tree) : definesProperty(tree, p);
         } else {
             String path = location.getPath();
-            return REP_CUG_POLICY.equals(Text.getName(path)) || path.endsWith(REP_CUG_POLICY + '/' + REP_PRINCIPAL_NAMES);
+            return definesPath(path, Text.getName(path));
         }
+    }
+
+    @Override
+    public boolean definesPath(@Nonnull String treePath, String propertyName) {
+        return treePath.contains('/' + REP_CUG_POLICY) || REP_PRINCIPAL_NAMES.equals(propertyName);
     }
 }
\ No newline at end of file
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeContext.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeContext.java	(revision 1652391)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeContext.java	(revision )
@@ -54,7 +54,11 @@
 
     @Override
     public boolean definesLocation(TreeLocation location) {
-        return location.getPath().startsWith(PRIVILEGES_PATH);
+        return definesPath(location.getPath(), null);
     }
 
+    @Override
+    public boolean definesPath(@Nonnull String treePath, String propertyName) {
+        return treePath.startsWith(PRIVILEGES_PATH);
+    }
 }
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationContext.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationContext.java	(revision 1652391)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationContext.java	(revision )
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.oak.security.authorization;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
@@ -64,9 +65,22 @@
             return (p == null) ? definesTree(tree) : definesProperty(tree, p);
         } else {
             String path = location.getPath();
-            String name = Text.getName(location.getPath());
-            return POLICY_NODE_NAMES.contains(name) || ACE_PROPERTY_NAMES.contains(name) || path.startsWith(PERMISSIONS_STORE_PATH);
+            return definesPath(path, Text.getName(path));
         }
     }
 
+    @Override
+    public boolean definesPath(@Nonnull String treePath, @Nullable String propertyName) {
+        boolean definesProperty = (propertyName != null) && ACE_PROPERTY_NAMES.contains(propertyName);
+        return definesProperty || treePath.startsWith(PERMISSIONS_STORE_PATH) || containsPolicyName(treePath);
+    }
+
+    private static boolean containsPolicyName(@Nonnull String treePath) {
+        for (String pName : POLICY_NODE_NAMES) {
+            if (treePath.contains('/' + pName)) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserContext.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserContext.java	(revision 1652391)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserContext.java	(revision )
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.oak.security.user;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
@@ -75,19 +76,24 @@
             return (p == null) ? definesTree(tree) : definesProperty(tree, p);
         } else {
             String path = location.getPath();
-            String name = Text.getName(path);
-            if (USER_PROPERTY_NAMES.contains(name)
-                    || GROUP_PROPERTY_NAMES.contains(name)
-                    || path.contains(REP_MEMBERS)
-                    || path.contains(REP_MEMBERS_LIST)
-                    || path.contains(REP_PWD)) {
+            return definesPath(path, Text.getName(path));
+        }
+    }
+
+    @Override
+    public boolean definesPath(@Nonnull String treePath, @Nullable String propertyName) {
+        if (USER_PROPERTY_NAMES.contains(propertyName)
+                || GROUP_PROPERTY_NAMES.contains(propertyName)
+                || treePath.contains(REP_MEMBERS)
+                || treePath.contains(REP_MEMBERS_LIST)
+                || treePath.contains(REP_PWD)) {
-                return true;
-            } else {
+            return true;
+        } else {
+            // TODO
-                // undefined: unable to determine if the specified location
-                // defines a user or group node (missing node type information
-                // on non-existing location
-                return false;
+            // undefined: unable to determine if the specified location
+            // defines a user or group node (missing node type information
+            // on non-existing location
+            return false;
-            }
         }
     }
 
\ No newline at end of file
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/composite/CompositePermissionProvider.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/composite/CompositePermissionProvider.java	(revision 1652391)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/composite/CompositePermissionProvider.java	(revision )
@@ -23,6 +23,7 @@
 import java.util.Set;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import javax.jcr.Session;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableMap;
@@ -160,6 +161,18 @@
         }
     }
 
+    @Override
+    public boolean canRead(@Nonnull final String oakTreePath, @Nullable String propertyName) {
+        Iterable<AggregatedPermissionProvider> providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
+            @Override
+            public boolean apply(@Nullable AggregatedPermissionProvider pp) {
+                // TODO separate 'handles' required?
+                return pp != null && pp.handles(oakTreePath, Session.ACTION_READ);
+            }
+        });
+        return grantsRead(oakTreePath, propertyName, providers);
+    }
+
     //--------------------------------------------------------------------------
     private PrivilegeBits getPrivilegeBits(@Nullable final Tree tree) {
         PrivilegeBits sufficient = PrivilegeBits.getInstance();
@@ -209,6 +222,19 @@
         return false;
     }
 
+    private static boolean grantsRead(@Nonnull final String oakTreePath,
+                                      @Nullable String propertyName,
+                                      @Nonnull Iterable<AggregatedPermissionProvider> providers) {
+        Iterator<AggregatedPermissionProvider> it = providers.iterator();
+        while (it.hasNext()) {
+            AggregatedPermissionProvider pp = it.next();
+            boolean isGranted = pp.canRead(oakTreePath, propertyName);
+            if (!it.hasNext() || evalComplete(isGranted, pp.getFlag())) {
+                return isGranted;
+            }
+        }
+        return false;
+    }
     private static boolean grantsAction(@Nonnull final String oakPath,
                                         @Nonnull final String action,
                                         @Nonnull Iterable<AggregatedPermissionProvider> providers) {
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java	(revision 1652391)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java	(revision )
@@ -24,6 +24,7 @@
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
@@ -223,6 +224,16 @@
             public boolean definesLocation(@Nonnull TreeLocation location) {
                 for (SecurityConfiguration sc : configs) {
                     if (sc.getContext().definesLocation(location)) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            @Override
+            public boolean definesPath(@Nonnull String treePath, @Nullable String propertyName) {
+                for (SecurityConfiguration sc : configs) {
+                    if (sc.getContext().definesPath(treePath, propertyName)) {
                         return true;
                     }
                 }
Index: oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProvider.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProvider.java	(revision 1652391)
+++ oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProvider.java	(revision )
@@ -22,6 +22,7 @@
 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;
@@ -205,6 +206,12 @@
         } else {
             return false;
         }
+    }
+
+    @Override
+    public boolean canRead(@Nonnull String oakTreePath, @Nullable String propertyName) {
+        // TODO
+        return false;
     }
 
     //--------------------------------------------------------------------------
\ No newline at end of file
