Author: angela
Date: Fri Oct 11 16:07:11 2019
New Revision: 1868297

URL: http://svn.apache.org/viewvc?rev=1868297&view=rev
Log:
OAK-8671 : respect PARAM_READ_PATHS configuration option

Added:
    
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsAccessControlTest.java
   (with props)
    
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsPermissionTest.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedAccessControlManager.java
    
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedPermissionProvider.java
    
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java

Modified: 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedAccessControlManager.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedAccessControlManager.java?rev=1868297&r1=1868296&r2=1868297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedAccessControlManager.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedAccessControlManager.java
 Fri Oct 11 16:07:11 2019
@@ -36,9 +36,12 @@ import org.apache.jackrabbit.oak.namepat
 import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
 import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
 import org.apache.jackrabbit.oak.spi.query.QueryConstants;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
 import 
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AbstractAccessControlManager;
 import 
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
 import 
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.PolicyOwner;
+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.authorization.permission.Permissions;
 import 
org.apache.jackrabbit.oak.spi.security.authorization.principalbased.Filter;
 import 
org.apache.jackrabbit.oak.spi.security.authorization.principalbased.FilterProvider;
@@ -49,6 +52,7 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.xml.ImportBehavior;
 import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter;
 import org.apache.jackrabbit.util.ISO9075;
+import org.apache.jackrabbit.util.Text;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
@@ -81,6 +85,7 @@ class PrincipalBasedAccessControlManager
 
     private final MgrProvider mgrProvider;
     private final int importBehavior;
+    private final Set<String> readPaths;
 
     private final PrincipalManager principalManager;
     private final PrivilegeBitsProvider privilegeBitsProvider;
@@ -94,7 +99,9 @@ class PrincipalBasedAccessControlManager
 
         this.mgrProvider = mgrProvider;
 
-        importBehavior = 
ImportBehavior.valueFromString(getConfig().getParameters().getConfigValue(ProtectedItemImporter.PARAM_IMPORT_BEHAVIOR,
 ImportBehavior.NAME_ABORT));
+        ConfigurationParameters configParams = getConfig().getParameters();
+        importBehavior = 
ImportBehavior.valueFromString(configParams.getConfigValue(ProtectedItemImporter.PARAM_IMPORT_BEHAVIOR,
 ImportBehavior.NAME_ABORT));
+        readPaths = 
configParams.getConfigValue(PermissionConstants.PARAM_READ_PATHS, 
PermissionConstants.DEFAULT_READ_PATHS);
 
         principalManager = mgrProvider.getPrincipalManager();
         privilegeBitsProvider = mgrProvider.getPrivilegeBitsProvider();
@@ -173,7 +180,6 @@ class PrincipalBasedAccessControlManager
             stmt.append("='").append(QueryUtils.escapeForQuery(effectivePath));
             stmt.append("'");
             cond = " or ";
-
         }
         stmt.append("] order by jcr:path option (traversal ok)");
 
@@ -192,7 +198,13 @@ class PrincipalBasedAccessControlManager
                 }
             }
             Iterable<PrincipalAccessControlList> acls = 
Iterables.transform(m.entrySet(), entry -> new 
ImmutablePrincipalPolicy(entry.getKey(), filter.getOakPath(entry.getKey()), 
entry.getValue(), mgrProvider.getRestrictionProvider(), getNamePathMapper()));
-            return Iterables.toArray(acls, PrincipalAccessControlList.class);
+
+            if (isReadablePath(oakPath)) {
+                Iterable iterable = Iterables.concat(acls, 
Collections.singleton(ReadPolicy.INSTANCE));
+                return Iterables.toArray(iterable, AccessControlPolicy.class);
+            } else {
+                return Iterables.toArray(acls, 
PrincipalAccessControlList.class);
+            }
         } catch (ParseException e) {
             String msg = "Error while collecting effective policies at " 
+absPath;
             log.error(msg, e);
@@ -394,4 +406,19 @@ class PrincipalBasedAccessControlManager
             }
         };
     }
+
+    private boolean isReadablePath(@Nullable String oakPath) {
+        if (oakPath == null) {
+            return false;
+        }
+        if (readPaths.contains(oakPath)) {
+            return true;
+        }
+        for (String rp : readPaths) {
+            if (Text.isDescendant(rp, oakPath)) {
+                return true;
+            }
+        }
+        return false;
+    }
 }

Modified: 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedPermissionProvider.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedPermissionProvider.java?rev=1868297&r1=1868296&r2=1868297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedPermissionProvider.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalBasedPermissionProvider.java
 Fri Oct 11 16:07:11 2019
@@ -28,7 +28,9 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.tree.TreeType;
 import org.apache.jackrabbit.oak.plugins.tree.TreeTypeProvider;
 import org.apache.jackrabbit.oak.plugins.version.ReadOnlyVersionManager;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
 import 
org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
 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;
@@ -65,6 +67,8 @@ class PrincipalBasedPermissionProvider i
     private RepositoryPermissionImpl repositoryPermission;
     private EntryCache entryCache;
 
+    private ReadablePaths readablePaths;
+
     PrincipalBasedPermissionProvider(@NotNull Root root,
                                      @NotNull String workspaceName,
                                      @NotNull Iterable<String> principalPaths,
@@ -79,6 +83,7 @@ class PrincipalBasedPermissionProvider i
         modAcBits = 
mgrProvider.getPrivilegeBitsProvider().getBits(PrivilegeConstants.JCR_MODIFY_ACCESS_CONTROL);
 
         entryCache = new EntryCache(immutableRoot, principalPaths, 
mgrProvider.getRestrictionProvider());
+        readablePaths = new ReadablePaths(mgrProvider);
     }
 
     //-------------------------------------------------< PermissionProvider 
>---
@@ -92,6 +97,7 @@ class PrincipalBasedPermissionProvider i
         if (repositoryPermission != null) {
             repositoryPermission.refresh();
         }
+        readablePaths = new ReadablePaths(mgrProvider);
     }
 
     @NotNull
@@ -252,6 +258,13 @@ class PrincipalBasedPermissionProvider i
     private boolean isGranted(@NotNull String path, @NotNull 
Predicate<PermissionEntry> predicate,
                               @NotNull Predicate<PermissionEntry> 
parentPredicate, long permissions) {
         long allows = Permissions.NO_PERMISSION;
+        if (readablePaths.isReadable(path)) {
+            allows = Permissions.READ;
+            if (isGranted(allows, permissions)) {
+                return true;
+            }
+        }
+
         PrivilegeBits bits = PrivilegeBits.getInstance();
         PrivilegeBits parentBits = PrivilegeBits.getInstance();
 
@@ -266,13 +279,17 @@ class PrincipalBasedPermissionProvider i
                 bits.add(entryBits);
             }
             allows |= PrivilegeBits.calculatePermissions(bits, parentBits, 
true);
-            if ((allows | ~permissions) == -1) {
+            if (isGranted(allows, permissions)) {
                 return true;
             }
         }
         return false;
     }
 
+    private static boolean isGranted(long allows, long permissions) {
+        return ((allows | ~permissions) == -1);
+    }
+
     private boolean isGrantedOnEffective(@NotNull Tree tree, long permission) {
         long toTest = permission & Permissions.MODIFY_ACCESS_CONTROL;
         if (Permissions.NO_PERMISSION == toTest) {
@@ -360,6 +377,9 @@ class PrincipalBasedPermissionProvider i
         while (entries.hasNext()) {
             pb.add(entries.next().getPrivilegeBits());
         }
+        if (!pb.includes(readablePaths.readBits) && 
readablePaths.isReadable(oakPath)) {
+            pb.add(readablePaths.readBits);
+        }
         return pb;
     }
 
@@ -463,4 +483,35 @@ class PrincipalBasedPermissionProvider i
             return new VersionTreePermission(childVersionTree, 
childVersionableTree);
         }
     }
+
+    private static final class ReadablePaths {
+
+        private final String[] paths;
+        private final String[] substrPaths;
+        private final PrivilegeBits readBits;
+
+        private ReadablePaths(@NotNull MgrProvider mgrProvider) {
+            paths = 
mgrProvider.getSecurityProvider().getParameters(AuthorizationConfiguration.NAME).getConfigValue(PermissionConstants.PARAM_READ_PATHS,
 PermissionConstants.DEFAULT_READ_PATHS).toArray(new String[0]);
+            substrPaths = new String[paths.length];
+            int i = 0;
+            for (String p : this.paths) {
+                substrPaths[i++] = p + '/';
+            }
+            this.readBits = 
mgrProvider.getPrivilegeBitsProvider().getBits(PrivilegeConstants.JCR_READ);
+        }
+
+        public boolean isReadable(@NotNull String treePath) {
+            for (String path : paths) {
+                if (treePath.equals(path)) {
+                    return true;
+                }
+            }
+            for (String path : substrPaths) {
+                if (treePath.startsWith(path)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
 }

Modified: 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java?rev=1868297&r1=1868296&r2=1868297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java
 Fri Oct 11 16:07:11 2019
@@ -71,7 +71,6 @@ public class AbstractPrincipalBasedTest
     );
 
     private User testSystemUser;
-    private MgrProvider mgrProvider;
     private PrincipalBasedAuthorizationConfiguration 
principalBasedAuthorizationConfiguration;
 
     String testJcrPath;
@@ -213,11 +212,8 @@ public class AbstractPrincipalBasedTest
     }
 
     @NotNull
-    MgrProvider getMgrProvider(Root root) {
-        if (mgrProvider == null) {
-            mgrProvider = new 
MgrProviderImpl(principalBasedAuthorizationConfiguration, root, 
getNamePathMapper());
-        }
-        return mgrProvider;
+    MgrProvider getMgrProvider(Root r) {
+        return new MgrProviderImpl(principalBasedAuthorizationConfiguration, 
r, getNamePathMapper());
     }
 
     @NotNull

Added: 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsAccessControlTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsAccessControlTest.java?rev=1868297&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsAccessControlTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsAccessControlTest.java
 Fri Oct 11 16:07:11 2019
@@ -0,0 +1,238 @@
+/*
+ * 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.principalbased.impl;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Sets;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+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.privilege.PrivilegeConstants;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.Privilege;
+import javax.security.auth.Subject;
+import java.security.Principal;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+
+import static org.apache.jackrabbit.oak.commons.PathUtils.ROOT_PATH;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_READ;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_READ_NODES;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_READ_PROPERTIES;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ReadablePathsAccessControlTest extends AbstractPrincipalBasedTest 
{
+
+    private Principal testPrincipal;
+    private Iterator<String> readablePaths;
+    private Iterator<String> readableChildPaths;
+
+    private JackrabbitAccessControlManager acMgr;
+
+    @Before
+    public void before() throws Exception {
+        super.before();
+
+        acMgr = new PrincipalBasedAccessControlManager(getMgrProvider(root), 
getFilterProvider());
+
+        testPrincipal = getTestSystemUser().getPrincipal();
+        Set<String> paths = 
getConfig(AuthorizationConfiguration.class).getParameters().getConfigValue(PermissionConstants.PARAM_READ_PATHS,
 PermissionConstants.DEFAULT_READ_PATHS);
+        assertFalse(paths.isEmpty());
+
+        readablePaths = Iterators.cycle(Iterables.transform(paths, 
(Function<String, String>) f -> getNamePathMapper().getJcrPath(f)));
+        Set<String> childPaths = Sets.newHashSet();
+        for (String path : paths) {
+            Iterables.addAll(childPaths, 
Iterables.transform(root.getTree(path).getChildren(), tree -> 
getNamePathMapper().getJcrPath(tree.getPath())));
+        }
+        readableChildPaths = Iterators.cycle(childPaths);
+    }
+
+    private Subject getTestSubject() {
+        return new Subject(true, Collections.singleton(testPrincipal), 
ImmutableSet.of(), ImmutableSet.of());
+    }
+
+    @Test
+    public void testHasPrivilege() throws Exception {
+        try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), 
(PrivilegedExceptionAction<ContentSession>) () -> 
getContentRepository().login(null, null), null)) {
+            PrincipalBasedAccessControlManager testAcMgr = new 
PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), 
getFilterProvider());
+
+            Set<Principal> principals = Collections.singleton(testPrincipal);
+
+            assertTrue(testAcMgr.hasPrivileges(readablePaths.next(), 
principals, privilegesFromNames(JCR_READ)));
+            assertTrue(testAcMgr.hasPrivileges(readablePaths.next(), 
principals, privilegesFromNames(REP_READ_PROPERTIES)));
+
+            assertTrue(testAcMgr.hasPrivileges(readableChildPaths.next(), 
principals, privilegesFromNames(REP_READ_NODES)));
+            assertTrue(testAcMgr.hasPrivileges(readableChildPaths.next(), 
principals, privilegesFromNames(REP_READ_NODES, REP_READ_PROPERTIES)));
+        }
+    }
+
+    @Test
+    public void testNotHasPrivilege() throws Exception {
+        try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), 
(PrivilegedExceptionAction<ContentSession>) () -> 
getContentRepository().login(null, null), null)) {
+            PrincipalBasedAccessControlManager testAcMgr = new 
PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), 
getFilterProvider());
+
+            Set<Principal> principals = Collections.singleton(testPrincipal);
+
+            assertFalse(testAcMgr.hasPrivileges(readablePaths.next(), 
principals, privilegesFromNames(JCR_READ, 
PrivilegeConstants.JCR_READ_ACCESS_CONTROL)));
+            assertFalse(testAcMgr.hasPrivileges(readablePaths.next(), 
principals, privilegesFromNames(PrivilegeConstants.JCR_ALL)));
+
+            assertFalse(testAcMgr.hasPrivileges(readableChildPaths.next(), 
principals, privilegesFromNames(REP_READ_NODES, 
PrivilegeConstants.JCR_MODIFY_PROPERTIES)));
+            assertFalse(testAcMgr.hasPrivileges(readableChildPaths.next(), 
principals, privilegesFromNames(REP_READ_NODES, REP_READ_PROPERTIES, 
PrivilegeConstants.JCR_NAMESPACE_MANAGEMENT)));
+        }
+    }
+
+    @Test
+    public void testHasPrivilegePrincipal() throws Exception {
+        Set<Principal> principals = Collections.singleton(testPrincipal);
+
+        assertTrue(acMgr.hasPrivileges(readablePaths.next(), principals, 
privilegesFromNames(JCR_READ)));
+        assertTrue(acMgr.hasPrivileges(readablePaths.next(), principals, 
privilegesFromNames(REP_READ_PROPERTIES)));
+
+        assertTrue(acMgr.hasPrivileges(readableChildPaths.next(), principals, 
privilegesFromNames(REP_READ_NODES)));
+        assertTrue(acMgr.hasPrivileges(readableChildPaths.next(), principals, 
privilegesFromNames(REP_READ_NODES, REP_READ_PROPERTIES)));
+    }
+
+    @Test
+    public void testNotHasPrivilegePrincipal() throws Exception {
+        Set<Principal> principals = Collections.singleton(testPrincipal);
+
+        assertFalse(acMgr.hasPrivileges(readablePaths.next(), principals, 
privilegesFromNames(JCR_READ, PrivilegeConstants.JCR_MODIFY_PROPERTIES)));
+        assertFalse(acMgr.hasPrivileges(readablePaths.next(), principals, 
privilegesFromNames(PrivilegeConstants.JCR_ALL)));
+
+        assertFalse(acMgr.hasPrivileges(readableChildPaths.next(), principals, 
privilegesFromNames(REP_READ_NODES, 
PrivilegeConstants.JCR_READ_ACCESS_CONTROL)));
+        assertFalse(acMgr.hasPrivileges(readableChildPaths.next(), principals, 
privilegesFromNames(PrivilegeConstants.JCR_VERSION_MANAGEMENT, 
REP_READ_PROPERTIES)));
+
+        assertFalse(acMgr.hasPrivileges(ROOT_PATH, principals, 
privilegesFromNames(JCR_READ)));
+        String systemPath = 
getNamePathMapper().getJcrPath(PathUtils.concat(ROOT_PATH, 
JcrConstants.JCR_SYSTEM));
+        assertFalse(acMgr.hasPrivileges(systemPath, principals, 
privilegesFromNames(REP_READ_PROPERTIES)));
+    }
+
+    @Test
+    public void testGetPrivileges() throws Exception {
+        try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), 
(PrivilegedExceptionAction<ContentSession>) () -> 
getContentRepository().login(null, null), null)) {
+            PrincipalBasedAccessControlManager testAcMgr = new 
PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), 
getFilterProvider());
+
+            Privilege[] expected = privilegesFromNames(JCR_READ);
+
+            assertArrayEquals(expected, 
testAcMgr.getPrivileges(readablePaths.next()));
+            assertArrayEquals(expected, 
testAcMgr.getPrivileges(readableChildPaths.next()));
+        }
+    }
+
+    @Test(expected = PathNotFoundException.class)
+    public void testGetPrivilegesAtRoot() throws Exception {
+        try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), 
(PrivilegedExceptionAction<ContentSession>) () -> 
getContentRepository().login(null, null), null)) {
+            PrincipalBasedAccessControlManager testAcMgr = new 
PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), 
getFilterProvider());
+            testAcMgr.getPrivileges(ROOT_PATH);
+        }
+    }
+
+    @Test
+    public void testGetPrivilegesByPrincipal() throws Exception {
+        Privilege[] expected = privilegesFromNames(JCR_READ);
+        Set<Principal> principals = Collections.singleton(testPrincipal);
+
+        assertArrayEquals(expected, acMgr.getPrivileges(readablePaths.next(), 
principals));
+        assertArrayEquals(expected, 
acMgr.getPrivileges(readableChildPaths.next(), principals));
+
+        assertEquals(0, acMgr.getPrivileges(ROOT_PATH, principals).length);
+        assertEquals(0, acMgr.getPrivileges(PathUtils.concat(ROOT_PATH, 
getNamePathMapper().getJcrName(JcrConstants.JCR_SYSTEM)), principals).length);
+
+    }
+
+    @Test
+    public void testGetEffectivePolicies() throws Exception {
+        AccessControlPolicy[] expected = new AccessControlPolicy[] 
{ReadPolicy.INSTANCE};
+
+        assertArrayEquals(expected, 
acMgr.getEffectivePolicies(readablePaths.next()));
+        assertArrayEquals(expected, 
acMgr.getEffectivePolicies(readableChildPaths.next()));
+    }
+
+    @Test
+    public void testGetEffectivePoliciesNullPath() throws Exception {
+        assertEquals(0, acMgr.getEffectivePolicies((String) null).length);
+    }
+
+    @Test(expected = AccessDeniedException.class)
+    public void testGetEffectivePoliciesLimitedAccess() throws Exception {
+        try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), 
(PrivilegedExceptionAction<ContentSession>) () -> 
getContentRepository().login(null, null), null)) {
+            PrincipalBasedAccessControlManager testAcMgr = new 
PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), 
getFilterProvider());
+            testAcMgr.getEffectivePolicies(readablePaths.next());
+        }
+    }
+
+    @Test
+    public void testGetEffectivePoliciesLimitedAccess2() throws Exception {
+        String path = readablePaths.next();
+        setupPrincipalBasedAccessControl(testPrincipal, path, 
PrivilegeConstants.JCR_READ_ACCESS_CONTROL);
+        // default: grant read-ac at root node as nodetype/namespace roots 
cannot have their mixin changed
+        addDefaultEntry(PathUtils.ROOT_PATH, testPrincipal, 
PrivilegeConstants.JCR_READ_ACCESS_CONTROL);
+        root.commit();
+
+        // test-session can read-ac at readable path but cannot access 
principal-based policy
+        try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), 
(PrivilegedExceptionAction<ContentSession>) () -> 
getContentRepository().login(null, null), null)) {
+            PrincipalBasedAccessControlManager testAcMgr = new 
PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), 
getFilterProvider());
+            Set<AccessControlPolicy> effective = 
ImmutableSet.copyOf(testAcMgr.getEffectivePolicies(path));
+
+            assertEquals(1, effective.size());
+            assertTrue(effective.contains(ReadPolicy.INSTANCE));
+        }
+    }
+
+    @Test
+    public void testGetEffectivePoliciesLimitedAccess3() throws Exception {
+        String path = readablePaths.next();
+        setupPrincipalBasedAccessControl(testPrincipal, path, 
PrivilegeConstants.JCR_READ_ACCESS_CONTROL);
+        setupPrincipalBasedAccessControl(testPrincipal, 
getTestSystemUser().getPath(), PrivilegeConstants.JCR_READ, 
PrivilegeConstants.JCR_READ_ACCESS_CONTROL);
+        // default: grant read and read-ac at root node to make sure both 
policies are accessible
+        addDefaultEntry(PathUtils.ROOT_PATH, testPrincipal, 
PrivilegeConstants.JCR_READ_ACCESS_CONTROL, PrivilegeConstants.JCR_READ);
+        root.commit();
+
+        // test-session can read-ac at readable path and at principal-based 
policy
+        try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), 
(PrivilegedExceptionAction<ContentSession>) () -> 
getContentRepository().login(null, null), null)) {
+            PrincipalBasedAccessControlManager testAcMgr = new 
PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), 
getFilterProvider());
+            Set<AccessControlPolicy> effective = 
Sets.newHashSet(testAcMgr.getEffectivePolicies(path));
+
+            assertEquals(2, effective.size());
+            assertTrue(effective.remove(ReadPolicy.INSTANCE));
+            assertTrue(effective.iterator().next() instanceof 
ImmutablePrincipalPolicy);
+        }
+    }
+
+    @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);
+    }
+}
\ No newline at end of file

Propchange: 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsAccessControlTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsPermissionTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsPermissionTest.java?rev=1868297&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsPermissionTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsPermissionTest.java
 Fri Oct 11 16:07:11 2019
@@ -0,0 +1,221 @@
+/*
+ * 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.principalbased.impl;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Sets;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.tree.TreeLocation;
+import org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants;
+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.permission.PermissionConstants;
+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.security.privilege.PrivilegeConstants;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.oak.commons.PathUtils.ROOT_PATH;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_READ;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_READ_NODES;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_READ_PROPERTIES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ReadablePathsPermissionTest extends AbstractPrincipalBasedTest {
+
+    private Iterator<String> readablePaths;
+    private Iterator<String> readableChildPaths;
+
+    private PrincipalBasedPermissionProvider permissionProvider;
+
+    @Before
+    public void before() throws Exception {
+        super.before();
+
+        Set<String> paths = 
getConfig(AuthorizationConfiguration.class).getParameters().getConfigValue(PermissionConstants.PARAM_READ_PATHS,
 PermissionConstants.DEFAULT_READ_PATHS);
+        assertFalse(paths.isEmpty());
+
+        readablePaths = Iterators.cycle(paths);
+        Set<String> childPaths = Sets.newHashSet();
+        for (String path : paths) {
+            Iterables.addAll(childPaths, 
Iterables.transform(root.getTree(path).getChildren(), tree -> tree.getPath()));
+        }
+        readableChildPaths = Iterators.cycle(childPaths);
+
+        permissionProvider = new PrincipalBasedPermissionProvider(root, 
root.getContentSession().getWorkspaceName(), 
Collections.singleton(getTestSystemUser().getPath()), 
getPrincipalBasedAuthorizationConfiguration());
+    }
+
+    @Override
+    protected ConfigurationParameters getSecurityConfigParameters() {
+        return ConfigurationParameters.of(AuthorizationConfiguration.NAME,
+                
ConfigurationParameters.of(PermissionConstants.PARAM_READ_PATHS, new String[]{
+                        NamespaceConstants.NAMESPACES_PATH,
+                        PrivilegeConstants.PRIVILEGES_PATH
+                }));
+    }
+
+    @NotNull
+    private Tree getTree(@NotNull String path) {
+        return root.getTree(path);
+    }
+
+    @Test
+    public void testHasPrivileges() throws Exception {
+        
assertTrue(permissionProvider.hasPrivileges(getTree(readablePaths.next()), 
JCR_READ));
+        
assertTrue(permissionProvider.hasPrivileges(getTree(readablePaths.next()), 
REP_READ_PROPERTIES));
+        
assertTrue(permissionProvider.hasPrivileges(getTree(readableChildPaths.next()), 
REP_READ_NODES));
+        
assertTrue(permissionProvider.hasPrivileges(getTree(readableChildPaths.next()), 
REP_READ_NODES, REP_READ_PROPERTIES));
+    }
+
+    @Test
+    public void testNotHasPrivileges() throws Exception {
+        
assertFalse(permissionProvider.hasPrivileges(getTree(readablePaths.next()), 
JCR_READ, PrivilegeConstants.JCR_READ_ACCESS_CONTROL));
+        
assertFalse(permissionProvider.hasPrivileges(getTree(readablePaths.next()), 
PrivilegeConstants.JCR_WRITE));
+        
assertFalse(permissionProvider.hasPrivileges(getTree(readableChildPaths.next()),
 PrivilegeConstants.JCR_MODIFY_ACCESS_CONTROL, REP_READ_PROPERTIES));
+        
assertFalse(permissionProvider.hasPrivileges(getTree(readableChildPaths.next()),
 REP_READ_NODES, PrivilegeConstants.JCR_REMOVE_NODE));
+
+        assertFalse(permissionProvider.hasPrivileges(getTree(ROOT_PATH), 
JCR_READ));
+        String systemPath = PathUtils.concat(ROOT_PATH, JCR_SYSTEM);
+        assertFalse(permissionProvider.hasPrivileges(getTree(systemPath), 
REP_READ_NODES));
+    }
+
+    @Test
+    public void testGetPrivileges() throws Exception {
+        Set<String> expected = Collections.singleton(JCR_READ);
+
+        assertEquals(expected, 
permissionProvider.getPrivileges(getTree(readablePaths.next())));
+        assertEquals(expected, 
permissionProvider.getPrivileges(getTree(readableChildPaths.next())));
+
+        
assertTrue(permissionProvider.getPrivileges(getTree(ROOT_PATH)).isEmpty());
+        String systemPath = PathUtils.concat(ROOT_PATH, JCR_SYSTEM);
+        
assertTrue(permissionProvider.getPrivileges(getTree(systemPath)).isEmpty());
+    }
+
+    @Test
+    public void testIsGrantedPath() throws Exception {
+        assertTrue(permissionProvider.isGranted(readablePaths.next(), 
Permissions.getString(Permissions.READ)));
+        assertTrue(permissionProvider.isGranted(readablePaths.next(), 
Permissions.getString(Permissions.READ_NODE|Permissions.READ_PROPERTY)));
+        assertTrue(permissionProvider.isGranted(readableChildPaths.next(), 
Permissions.getString(Permissions.READ_NODE)));
+        
assertTrue(permissionProvider.isGranted(PathUtils.concat(readableChildPaths.next(),
 JCR_PRIMARYTYPE), Permissions.getString(Permissions.READ_PROPERTY)));
+        
assertTrue(permissionProvider.isGranted(PathUtils.concat(readableChildPaths.next(),
 "nonExisting"), Permissions.getString(Permissions.READ)));
+    }
+
+    @Test
+    public void testNotIsGrantedPath() throws Exception {
+        assertFalse(permissionProvider.isGranted(readablePaths.next(), 
Permissions.getString(Permissions.READ|Permissions.VERSION_MANAGEMENT)));
+        assertFalse(permissionProvider.isGranted(readablePaths.next(), 
Permissions.getString(Permissions.READ_ACCESS_CONTROL|Permissions.READ_NODE)));
+        assertFalse(permissionProvider.isGranted(readableChildPaths.next(), 
Permissions.getString(Permissions.READ_PROPERTY|Permissions.ALL)));
+
+        assertFalse(permissionProvider.isGranted(ROOT_PATH, 
Permissions.getString(Permissions.READ)));
+        assertFalse(permissionProvider.isGranted(PathUtils.concat(ROOT_PATH, 
JCR_SYSTEM), Permissions.getString(Permissions.READ_NODE)));
+        assertFalse(permissionProvider.isGranted("/nonExistingContent", 
Permissions.getString(Permissions.READ_PROPERTY)));
+    }
+
+    @Test
+    public void testIsGrantedTree() throws Exception {
+        assertTrue(permissionProvider.isGranted(getTree(readablePaths.next()), 
null, Permissions.READ));
+        assertTrue(permissionProvider.isGranted(getTree(readablePaths.next()), 
null, Permissions.READ_NODE));
+        Tree t = getTree(readablePaths.next());
+        assertTrue(permissionProvider.isGranted(t, 
t.getProperty(JCR_PRIMARYTYPE), Permissions.READ_PROPERTY));
+
+        
assertTrue(permissionProvider.isGranted(getTree(readableChildPaths.next()), 
null, Permissions.READ));
+        
assertTrue(permissionProvider.isGranted(getTree(readableChildPaths.next()), 
null, Permissions.READ_NODE));
+        t = getTree(readableChildPaths.next());
+        assertTrue(permissionProvider.isGranted(t, 
t.getProperty(JCR_PRIMARYTYPE), Permissions.READ_PROPERTY));
+    }
+
+    @Test
+    public void testNotIsGrantedTree() throws Exception {
+        
assertFalse(permissionProvider.isGranted(getTree(readablePaths.next()), null, 
Permissions.READ_ACCESS_CONTROL|Permissions.READ));
+        
assertFalse(permissionProvider.isGranted(getTree(readablePaths.next()), null, 
Permissions.ADD_NODE));
+        Tree t = getTree(readableChildPaths.next());
+        assertFalse(permissionProvider.isGranted(t, 
t.getProperty(JCR_PRIMARYTYPE), 
Permissions.MODIFY_PROPERTY|Permissions.READ_PROPERTY));
+
+        t = getTree(PathUtils.ROOT_PATH);
+        assertFalse(permissionProvider.isGranted(t, null, Permissions.READ));
+        assertFalse(permissionProvider.isGranted(t, 
t.getProperty(JCR_PRIMARYTYPE), Permissions.READ_PROPERTY));
+        
assertFalse(permissionProvider.isGranted(t.getChildren().iterator().next(), 
null, Permissions.READ_NODE));
+    }
+
+    @Test
+    public void testIsGrantedLocation() throws Exception {
+        assertTrue(permissionProvider.isGranted(TreeLocation.create(root, 
readablePaths.next()), Permissions.READ));
+        assertTrue(permissionProvider.isGranted(TreeLocation.create(root, 
readableChildPaths.next()), Permissions.READ_NODE));
+        assertTrue(permissionProvider.isGranted(TreeLocation.create(root, 
readableChildPaths.next()).getChild(JCR_PRIMARYTYPE), 
Permissions.READ_PROPERTY));
+    }
+
+    @Test
+    public void testNotIsGrantedLocation() throws Exception {
+        assertFalse(permissionProvider.isGranted(TreeLocation.create(root, 
readablePaths.next()), Permissions.READ|Permissions.WRITE));
+        assertFalse(permissionProvider.isGranted(TreeLocation.create(root, 
readableChildPaths.next()), Permissions.ALL));
+        assertFalse(permissionProvider.isGranted(TreeLocation.create(root, 
readableChildPaths.next()).getChild(JCR_PRIMARYTYPE), 
Permissions.READ_PROPERTY|Permissions.MODIFY_PROPERTY));
+
+        TreeLocation location = TreeLocation.create(root);
+        assertFalse(permissionProvider.isGranted(location, Permissions.READ));
+        
assertFalse(permissionProvider.isGranted(location.getChild(JCR_SYSTEM), 
Permissions.READ_NODE));
+        
assertFalse(permissionProvider.isGranted(location.getChild(JCR_PRIMARYTYPE), 
Permissions.READ_PROPERTY));
+    }
+
+    @Test
+    public void testTreePermission() throws Exception {
+        Tree t = getTree(ROOT_PATH);
+        TreePermission tp = permissionProvider.getTreePermission(t, 
TreePermission.EMPTY);
+        assertFalse(tp.isGranted(Permissions.READ));
+        assertFalse(tp.canRead());
+        assertFalse(tp.canRead(t.getProperty(JCR_PRIMARYTYPE)));
+
+        tp = permissionProvider.getTreePermission(t.getChild(JCR_SYSTEM), tp);
+        assertFalse(tp.isGranted(Permissions.READ_NODE));
+        assertFalse(tp.canReadProperties());
+        assertFalse(tp.canReadAll());
+
+        // readable paths
+        t = root.getTree(readablePaths.next());
+        tp = permissionProvider.getTreePermission(t, tp);
+        assertTrue(tp.isGranted(Permissions.READ));
+        assertFalse(tp.isGranted(Permissions.READ_ACCESS_CONTROL));
+
+        assertTrue(tp.canRead());
+        assertTrue(tp.canRead(t.getProperty(JCR_PRIMARYTYPE)));
+        assertFalse(tp.canReadProperties());
+
+        t = t.getChildren().iterator().next();
+        tp = permissionProvider.getTreePermission(t, tp);
+        assertTrue(tp.isGranted(Permissions.READ_NODE));
+        assertTrue(tp.isGranted(Permissions.READ_PROPERTY, 
t.getProperty(JCR_PRIMARYTYPE)));
+        
assertFalse(tp.isGranted(Permissions.READ_PROPERTY|Permissions.MODIFY_PROPERTY, 
t.getProperty(JCR_PRIMARYTYPE)));
+        assertTrue(tp.canRead());
+        assertFalse(tp.canReadAll());
+    }
+
+    @Test
+    public void testRepositoryPermission() throws Exception {
+        
assertFalse(permissionProvider.getRepositoryPermission().isGranted(Permissions.READ));
+    }
+}
\ No newline at end of file

Propchange: 
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/ReadablePathsPermissionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to