You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2015/12/17 18:40:03 UTC

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

Author: angela
Date: Thu Dec 17 17:40:03 2015
New Revision: 1720618

URL: http://svn.apache.org/viewvc?rev=1720618&view=rev
Log:
OAK-3704 : Keep track of nested CUGs (WIP)

Added:
    jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/NestedCugHook.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/TopLevelPaths.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/NestedCugHookRootSupportedTest.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/NestedCugHookTest.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/NoCugTest.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/TopLevelPathTest.java
Modified:
    jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugConfiguration.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugConstants.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProvider.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermission.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugUtil.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/AbstractCugTest.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/AccessControlTest.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugAccessControlManagerTest.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugEvaluationTest.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProviderTest.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermissionTest.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugUtilTest.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/EmptyCugTreePermissionTest.java
    jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/VersionTest.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/PropertyBuilder.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/package-info.java

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugConfiguration.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugConfiguration.java?rev=1720618&r1=1720617&r2=1720618&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugConfiguration.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugConfiguration.java Thu Dec 17 17:40:03 2015
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.oak.spi.security.authorization.cug.impl;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.security.Principal;
 import java.security.PrivilegedActionException;
 import java.util.Collections;
@@ -30,6 +31,7 @@ import javax.jcr.security.AccessControlM
 import com.google.common.collect.ImmutableList;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
 import org.apache.felix.scr.annotations.Properties;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
@@ -37,11 +39,16 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Service;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
 import org.apache.jackrabbit.oak.plugins.name.NamespaceEditorProvider;
+import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
 import org.apache.jackrabbit.oak.plugins.nodetype.TypeEditorProvider;
+import org.apache.jackrabbit.oak.plugins.nodetype.write.NodeTypeRegistry;
 import org.apache.jackrabbit.oak.plugins.tree.RootFactory;
+import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.CompositeEditorProvider;
 import org.apache.jackrabbit.oak.spi.commit.EditorHook;
 import org.apache.jackrabbit.oak.spi.commit.MoveTracker;
@@ -66,7 +73,8 @@ import org.apache.jackrabbit.oak.spi.xml
 
 @Component(metatype = true,
         label = "Apache Jackrabbit Oak CUG Configuration",
-        description = "Authorization configuration dedicated to setup and evaluate 'Closed User Group' permissions.")
+        description = "Authorization configuration dedicated to setup and evaluate 'Closed User Group' permissions.",
+        policy = ConfigurationPolicy.REQUIRE)
 @Service({AuthorizationConfiguration.class, SecurityConfiguration.class})
 @Properties({
         @Property(name = CugConstants.PARAM_CUG_SUPPORTED_PATHS,
@@ -143,7 +151,7 @@ public class CugConfiguration extends Co
                 Root root = RootFactory.createSystemRoot(store,
                         new EditorHook(new CompositeEditorProvider(new NamespaceEditorProvider(), new TypeEditorProvider())),
                         null, null, null, null);
-                if (CugUtil.registerCugNodeTypes(root)) {
+                if (registerCugNodeTypes(root)) {
                     NodeState target = store.getRoot();
                     target.compareAgainstBaseState(base, new ApplyDiff(builder));
                 }
@@ -153,6 +161,12 @@ public class CugConfiguration extends Co
 
     @Nonnull
     @Override
+    public List<? extends CommitHook> getCommitHooks(@Nonnull String workspaceName) {
+        return Collections.singletonList(new NestedCugHook());
+    }
+
+    @Nonnull
+    @Override
     public List<? extends ValidatorProvider> getValidators(@Nonnull String workspaceName, @Nonnull Set<Principal> principals, @Nonnull MoveTracker moveTracker) {
         return ImmutableList.of(new CugValidatorProvider());
     }
@@ -181,4 +195,29 @@ public class CugConfiguration extends Co
     private CugExclude getExclude() {
         return (exclude == null) ? new CugExclude.Default() : exclude;
     }
+
+    static boolean registerCugNodeTypes(@Nonnull final Root root) {
+        try {
+            ReadOnlyNodeTypeManager ntMgr = new ReadOnlyNodeTypeManager() {
+                @Override
+                protected Tree getTypes() {
+                    return root.getTree(NodeTypeConstants.NODE_TYPES_PATH);
+                }
+            };
+            if (!ntMgr.hasNodeType(NT_REP_CUG_POLICY)) {
+                InputStream stream = CugConfiguration.class.getResourceAsStream("cug_nodetypes.cnd");
+                try {
+                    NodeTypeRegistry.register(root, stream, "cug node types");
+                    return true;
+                } finally {
+                    stream.close();
+                }
+            }
+        } catch (IOException e) {
+            throw new IllegalStateException("Unable to read cug node types", e);
+        } catch (RepositoryException e) {
+            throw new IllegalStateException("Unable to read cug node types", e);
+        }
+        return false;
+    }
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugConstants.java?rev=1720618&r1=1720617&r2=1720618&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugConstants.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugConstants.java Thu Dec 17 17:40:03 2015
@@ -37,6 +37,18 @@ interface CugConstants {
     String REP_CUG_POLICY = "rep:cugPolicy";
 
     /**
+     * The name of the hidden property that stores information about nested
+     * CUG policy nodes.
+     */
+    String HIDDEN_NESTED_CUGS = ":nestedCugs";
+
+    /**
+     * The name of the hidden property that stores information about the number
+     * of CUG roots located close to the root node.
+     */
+    String HIDDEN_TOP_CUG_CNT = ":topCugCnt";
+
+    /**
      * The name of the property that stores the principal names that are allowed
      * to access the restricted area defined by the CUG (closed user group).
      */

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProvider.java?rev=1720618&r1=1720617&r2=1720618&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProvider.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProvider.java Thu Dec 17 17:40:03 2015
@@ -67,6 +67,7 @@ class CugPermissionProvider implements A
 
     private Root immutableRoot;
     private ReadOnlyVersionManager versionManager;
+    private TopLevelPaths topPaths;
 
     CugPermissionProvider(@Nonnull Root root,
                           @Nonnull String workspaceName,
@@ -86,6 +87,8 @@ class CugPermissionProvider implements A
         this.supportedPaths = new SupportedPaths(supportedPaths);
         this.typeProvider = new TreeTypeProvider(ctx);
         this.ctx = ctx;
+
+        topPaths = new TopLevelPaths(immutableRoot);
     }
 
     @Nonnull
@@ -114,6 +117,7 @@ class CugPermissionProvider implements A
     public void refresh() {
         immutableRoot = RootFactory.createReadOnlyRoot(root);
         versionManager = null;
+        topPaths = new TopLevelPaths(immutableRoot);
     }
 
     @Nonnull
@@ -149,7 +153,7 @@ class CugPermissionProvider implements A
     @Override
     public TreePermission getTreePermission(@Nonnull Tree tree, @Nonnull TreePermission parentPermission) {
         if (TreePermission.NO_RECOURSE == parentPermission) {
-            throw new IllegalStateException("Attempt to create tree permission for unsupported path.");
+            throw new IllegalStateException("Attempt to create tree permission for path '"+ tree.getPath() +"', which is either not supported or doesn't contain any CUGs.");
         }
         Tree immutableTree = getImmutableTree(tree);
         TreeType type = typeProvider.getType(immutableTree);
@@ -247,7 +251,7 @@ class CugPermissionProvider implements A
 
     @Nonnull
     public TreePermission getTreePermission(@Nonnull Tree immutableTree, @Nonnull TreeType type, @Nonnull TreePermission parentPermission) {
-        if (!isSupportedType(type)) {
+        if (!isSupportedType(type) || !topPaths.hasAny()) {
             return TreePermission.NO_RECOURSE;
         }
 
@@ -260,9 +264,13 @@ class CugPermissionProvider implements A
                 tp = new CugTreePermission(immutableTree, type, parentPermission, this);
             } else {
                 String path = immutableTree.getPath();
-                if (supportedPaths.includes(path)) {
-                    tp =  new CugTreePermission(immutableTree, type, parentPermission, this);
-                } else if (supportedPaths.mayContainCug(path) || isJcrSystemPath(immutableTree)) {
+                if (includes(path)) {
+                    if (topPaths.contains(path)) {
+                        tp = new CugTreePermission(immutableTree, type, parentPermission, this);
+                    } else {
+                        tp = TreePermission.NO_RECOURSE;
+                    }
+                } else if (mayContain(path) || isJcrSystemPath(immutableTree)) {
                     tp =  new EmptyCugTreePermission(immutableTree, type, this);
                 } else {
                     tp = TreePermission.NO_RECOURSE;
@@ -273,6 +281,7 @@ class CugPermissionProvider implements A
     }
 
     //--------------------------------------------------------------------------
+
     private static boolean isJcrSystemPath(@Nonnull Tree tree) {
         return JcrConstants.JCR_SYSTEM.equals(tree.getName());
     }
@@ -289,13 +298,21 @@ class CugPermissionProvider implements A
         if (tree != null) {
             Tree immutableTree = getImmutableTree(tree);
             TreeType type = typeProvider.getType(immutableTree);
-            if (isSupportedType(type)) {
+            if (isSupportedType(type) && topPaths.hasAny()) {
                 return getCugRoot(immutableTree, type) != null;
             }
         }
         return false;
     }
 
+    private boolean includes(@Nonnull String path) {
+        return supportedPaths.includes(path);
+    }
+
+    private boolean mayContain(@Nonnull String path) {
+        return supportedPaths.mayContainCug(path) && topPaths.contains(path);
+    }
+
     /**
      * Returns the {@code tree} that holds a CUG policy in the ancestry of the
      * given {@code tree} with the specified {@code path} or {@code null} if no
@@ -317,7 +334,7 @@ class CugPermissionProvider implements A
             }
             p = tree.getPath();
         }
-        if (!supportedPaths.includes(p)) {
+        if (!includes(p)) {
             return null;
         }
         if (CugUtil.hasCug(tree)) {
@@ -326,7 +343,7 @@ class CugPermissionProvider implements A
         String parentPath;
         while (!tree.isRoot()) {
             parentPath = PathUtils.getParentPath(p);
-            if (!supportedPaths.includes(parentPath)) {
+            if (!includes(parentPath)) {
                 break;
             }
             tree = tree.getParent();
@@ -340,7 +357,7 @@ class CugPermissionProvider implements A
     private boolean canRead(@Nonnull Tree tree) {
         Tree immutableTree = getImmutableTree(tree);
         TreeType type = typeProvider.getType(immutableTree);
-        if (!isSupportedType(type)) {
+        if (!isSupportedType(type) || !topPaths.hasAny()) {
             return false;
         }
         Tree cugRoot = getCugRoot(immutableTree, type);
@@ -393,7 +410,7 @@ class CugPermissionProvider implements A
             Tree cug = null;
             if (parentIsCugPermission) {
                 cug = CugUtil.getCug(versionableTree);
-            } else if (supportedPaths.includes(path)) {
+            } else if (includes(path)) {
                 isSupportedPath = true;
                 // the versionable tree might be included in a cug defined by
                 // a parent node -> need to search for inherited cugs as well.
@@ -406,13 +423,13 @@ class CugPermissionProvider implements A
             TreePermission tp;
             if (cug != null) {
                 // backing versionable tree holds a cug
-                tp = new CugTreePermission(tree, type, parent, this, true, isAllow(cug));
+                tp = new CugTreePermission(tree, type, parent, this, true, isAllow(cug), CugUtil.hasNestedCug(cug));
             } else if (parentIsCugPermission) {
                 CugTreePermission ctp = (CugTreePermission) parent;
-                tp = new CugTreePermission(tree, type, parent, this, ctp.isInCug(), ctp.isAllow());
+                tp = new CugTreePermission(tree, type, parent, this, ctp.isInCug(), ctp.isAllow(), ctp.hasNestedCug());
             } else if (isSupportedPath) {
-                tp = new CugTreePermission(tree, type, parent, this, false, false);
-            } else  if (supportedPaths.mayContainCug(path)) {
+                tp = new CugTreePermission(tree, type, parent, this, false, false, false);
+            } else  if (mayContain(path)) {
                 tp = new EmptyCugTreePermission(tree, type, this);
             } else {
                 tp = TreePermission.NO_RECOURSE;

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermission.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermission.java?rev=1720618&r1=1720617&r2=1720618&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermission.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermission.java Thu Dec 17 17:40:03 2015
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.oak.spi.security.authorization.cug.impl;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
@@ -40,10 +41,10 @@ final class CugTreePermission extends Ab
     }
 
     CugTreePermission(@Nonnull Tree tree, @Nonnull TreeType type, @Nonnull TreePermission parent,
-                      @Nonnull CugPermissionProvider permissionProvider, boolean inCug, boolean canRead) {
+                      @Nonnull CugPermissionProvider permissionProvider, boolean inCug, boolean canRead, boolean hasNestedCug) {
         super(tree, type, permissionProvider);
         this.parent = parent;
-        status = new Status(inCug, canRead);
+        status = new Status(inCug, canRead, hasNestedCug);
     }
 
     boolean isInCug() {
@@ -59,26 +60,46 @@ final class CugTreePermission extends Ab
         }
         return status.allow;
     }
-
+    
+    boolean hasNestedCug() {
+        if (status == null) {
+            loadStatus();
+        }
+        return status.hasNested;
+    }
+    
     private Status getStatus() {
         if (status == null) {
             loadStatus();
         }
         return status;
     }
-
+    
     private void loadStatus() {
-        Tree cugTree = CugUtil.getCug(tree);
-        if (cugTree != null) {
-            status = new Status(true, permissionProvider.isAllow(cugTree));
-        } else if (parent instanceof CugTreePermission) {
-            status = ((CugTreePermission) parent).getStatus();
-            ;
+        CugTreePermission parentCugPerm = (parent instanceof CugTreePermission) ? (CugTreePermission) parent : null;
+        if (neverNested(parentCugPerm)) {
+            status = parentCugPerm.getStatus();
         } else {
-            status = Status.FALSE;
+            // need to load information
+            Tree cugTree = CugUtil.getCug(tree);
+            if (cugTree != null) {
+                status = new Status(true, permissionProvider.isAllow(cugTree), CugUtil.hasNestedCug(cugTree));
+            } else if (parentCugPerm != null) {
+                status = parentCugPerm.getStatus();
+            } else {
+                status = Status.FALSE;
+            }
         }
     }
 
+    private static boolean neverNested(@CheckForNull CugTreePermission parentCugPerm) {
+        if (parentCugPerm != null) {
+            Status st = parentCugPerm.status;
+            return st != null && st.inCug && !st.hasNested;
+        }
+        return false;
+    }
+
     //-----------------------------------------------------< TreePermission >---
 
     @Override
@@ -114,14 +135,16 @@ final class CugTreePermission extends Ab
     //--------------------------------------------------------------------------
     private final static class Status {
 
-        private static final Status FALSE = new Status(false, false);
+        private static final Status FALSE = new Status(false, false, false);
 
         private final boolean inCug;
         private final boolean allow;
+        private final boolean hasNested;
 
-        private Status(boolean inCug, boolean allow) {
+        private Status(boolean inCug, boolean allow, boolean hasNested) {
             this.inCug = inCug;
             this.allow = allow;
+            this.hasNested = hasNested;
         }
     }
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugUtil.java?rev=1720618&r1=1720617&r2=1720618&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugUtil.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugUtil.java Thu Dec 17 17:40:03 2015
@@ -16,20 +16,16 @@
  */
 package org.apache.jackrabbit.oak.spi.security.authorization.cug.impl;
 
-import java.io.IOException;
-import java.io.InputStream;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
-import javax.jcr.RepositoryException;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
-import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
-import org.apache.jackrabbit.oak.plugins.nodetype.write.NodeTypeRegistry;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
 import org.apache.jackrabbit.oak.spi.xml.ImportBehavior;
 import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter;
 import org.apache.jackrabbit.oak.util.TreeUtil;
@@ -46,6 +42,14 @@ final class CugUtil implements CugConsta
         return tree.exists() && tree.hasChild(REP_CUG_POLICY);
     }
 
+    public static boolean hasCug(@CheckForNull NodeState state) {
+        return state != null && state.hasChildNode(REP_CUG_POLICY);
+    }
+
+    public static boolean hasCug(@CheckForNull NodeBuilder builder) {
+        return builder != null && builder.hasChildNode(REP_CUG_POLICY);
+    }
+
     @CheckForNull
     public static Tree getCug(@Nonnull Tree tree) {
         Tree cugTree = (CugUtil.hasCug(tree)) ? tree.getChild(REP_CUG_POLICY) : null;
@@ -60,10 +64,18 @@ final class CugUtil implements CugConsta
         return tree.exists() && REP_CUG_POLICY.equals(tree.getName()) && NT_REP_CUG_POLICY.equals(TreeUtil.getPrimaryTypeName(tree));
     }
 
+    public static boolean definesCug(@Nonnull String name, @Nonnull NodeState state) {
+        return REP_CUG_POLICY.equals(name) && NT_REP_CUG_POLICY.equals(NodeStateUtils.getPrimaryTypeName(state));
+    }
+
     public static boolean definesCug(@Nonnull Tree tree, @Nonnull PropertyState property) {
         return REP_PRINCIPAL_NAMES.equals(property.getName()) && definesCug(tree);
     }
 
+    public static boolean hasNestedCug(@Nonnull Tree cugTree) {
+        return cugTree.hasProperty(CugConstants.HIDDEN_NESTED_CUGS);
+    }
+
     public static boolean isSupportedPath(@Nullable String oakPath, @Nonnull ConfigurationParameters config) {
         if (oakPath == null) {
             return false;
@@ -81,29 +93,4 @@ final class CugUtil implements CugConsta
         String importBehaviorStr = config.getConfigValue(ProtectedItemImporter.PARAM_IMPORT_BEHAVIOR, ImportBehavior.NAME_ABORT);
         return ImportBehavior.valueFromString(importBehaviorStr);
     }
-
-    public static boolean registerCugNodeTypes(@Nonnull final Root root) {
-        try {
-            ReadOnlyNodeTypeManager ntMgr = new ReadOnlyNodeTypeManager() {
-                @Override
-                protected Tree getTypes() {
-                    return root.getTree(NodeTypeConstants.NODE_TYPES_PATH);
-                }
-            };
-            if (!ntMgr.hasNodeType(NT_REP_CUG_POLICY)) {
-                InputStream stream = CugConfiguration.class.getResourceAsStream("cug_nodetypes.cnd");
-                try {
-                    NodeTypeRegistry.register(root, stream, "cug node types");
-                    return true;
-                } finally {
-                    stream.close();
-                }
-            }
-        } catch (IOException e) {
-            throw new IllegalStateException("Unable to read cug node types", e);
-        } catch (RepositoryException e) {
-            throw new IllegalStateException("Unable to read cug node types", e);
-        }
-        return false;
-    }
 }
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/NestedCugHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/NestedCugHook.java?rev=1720618&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/NestedCugHook.java (added)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/NestedCugHook.java Thu Dec 17 17:40:03 2015
@@ -0,0 +1,273 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.spi.security.authorization.cug.impl;
+
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyBuilder;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.PostValidationHook;
+import org.apache.jackrabbit.oak.spi.state.DefaultNodeStateDiff;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+
+/**
+ * {@code PostValidationHook} implementation responsible for keeping track of
+ * nested CUGs to simplify evaluation. The information about the nested CUGs is
+ * stored in a hidden property associated with the policy node.
+ *
+ * Note, that this hook does _not_ respect the configured supported paths
+ * and keeps track of all CUG policies irrespective of their validity.
+ * Consequently all optimization considering the nested CUG information must
+ * also verify the supported paths.
+ */
+class NestedCugHook implements PostValidationHook, CugConstants {
+
+    /**
+     * logger instance
+     */
+    private static final Logger log = LoggerFactory.getLogger(NestedCugHook.class);
+
+    private Set<String> deletedCUGs = Sets.newHashSet();
+
+    //-------------------------------------------------< PostValidationHook >---
+    @Nonnull
+    @Override
+    public NodeState processCommit(NodeState before, NodeState after, CommitInfo info) throws CommitFailedException {
+        NodeBuilder builder = after.builder();
+        after.compareAgainstBaseState(before, new Diff(before, builder));
+        deletedCUGs.clear();
+        return builder.getNodeState();
+    }
+
+    //-------------------------------------------------------------< Object >---
+    @Override
+    public String toString() {
+        return "NestedCugHook";
+    }
+
+    //------------------------------------------------------------< private >---
+
+    private static long addNestedCugPath(@Nonnull NodeBuilder parentBuilder, @Nonnull NodeBuilder builder, @Nonnull String pathWithNewCug) {
+        PropertyState ps = parentBuilder.getProperty(HIDDEN_NESTED_CUGS);
+        PropertyBuilder pb = getHiddenPropertyBuilder(ps);
+        if (ps != null) {
+            List<String> moveToNestedCug = Lists.newArrayList();
+            for (String p : ps.getValue(Type.STRINGS)) {
+                if (Text.isDescendant(pathWithNewCug, p)) {
+                    pb.removeValue(p);
+                    moveToNestedCug.add(p);
+                } else if (p.equals(pathWithNewCug)) {
+                    // already present with parent -> remove to avoid duplicate entries
+                    log.debug("Path of node holding a new nested CUG is already listed with the parent CUG.");
+                    pb.removeValue(p);
+                }
+            }
+            if (!moveToNestedCug.isEmpty()) {
+                PropertyBuilder pb2 = getHiddenPropertyBuilder(builder.getProperty(HIDDEN_NESTED_CUGS));
+                pb2.addValues(moveToNestedCug);
+                builder.setProperty(pb2.getPropertyState());
+            }
+        }
+
+        // update the nested-cug property of the parent
+        pb.addValue(pathWithNewCug);
+        parentBuilder.setProperty(pb.getPropertyState());
+        return pb.count();
+    }
+
+    private static int removeNestedCugPath(@Nonnull NodeBuilder parentBuilder, @Nonnull String toRemove, @Nonnull Iterable<String> toReconnect) {
+        PropertyState ps = parentBuilder.getProperty(HIDDEN_NESTED_CUGS);
+        PropertyBuilder pb = getHiddenPropertyBuilder(ps);
+        if (pb.hasValue(toRemove)) {
+            pb.removeValue(toRemove);
+            pb.addValues(toReconnect);
+            if (pb.isEmpty()) {
+                parentBuilder.removeProperty(HIDDEN_NESTED_CUGS);
+                return 0;
+            } else {
+                parentBuilder.setProperty(pb.getPropertyState());
+                return pb.count();
+            }
+        } else {
+            log.debug("Parent CUG doesn't contain expected entry for removed nested CUG");
+            return -1;
+        }
+    }
+
+    private static PropertyBuilder getHiddenPropertyBuilder(@Nullable PropertyState ps) {
+        return PropertyBuilder.copy(Type.STRING, ps).setName(HIDDEN_NESTED_CUGS).setArray();
+    }
+
+    private final class Diff extends DefaultNodeStateDiff {
+
+        private final Diff parentDiff;
+        private final boolean isRoot;
+
+        private String path;
+        private NodeState beforeState = null;
+
+        private NodeBuilder afterBuilder;
+        private boolean afterHoldsCug;
+
+        private Diff(@Nonnull NodeState rootBefore, @Nonnull NodeBuilder rootAfter) {
+            parentDiff = null;
+            isRoot = true;
+            path = PathUtils.ROOT_PATH;
+
+            beforeState = rootBefore;
+
+            afterBuilder = rootAfter;
+            afterHoldsCug = CugUtil.hasCug(rootAfter);
+        }
+
+        private Diff(@Nonnull Diff parentDiff, @Nonnull String name, @Nullable NodeState before, @Nullable NodeBuilder after) {
+            this.parentDiff = parentDiff;
+            isRoot = false;
+            path = PathUtils.concat(parentDiff.path, name);
+
+            this.beforeState = before;
+
+            afterBuilder = after;
+            afterHoldsCug = CugUtil.hasCug(after);
+        }
+
+        @Override
+        public boolean childNodeAdded(String name, NodeState after) {
+            if (!NodeStateUtils.isHidden(name)) {
+                if (CugUtil.definesCug(name, after)) {
+                    if (isRoot) {
+                        PropertyState alt = afterBuilder.getProperty(HIDDEN_NESTED_CUGS);
+                        if (alt != null) {
+                            NodeBuilder cugNode = afterBuilder.getChildNode(REP_CUG_POLICY);
+                            cugNode.setProperty(alt);
+                            afterBuilder.removeProperty(HIDDEN_NESTED_CUGS);
+                            afterBuilder.removeProperty(HIDDEN_TOP_CUG_CNT);
+                        }
+                    } else {
+                        Diff diff = parentDiff;
+                        while (diff != null) {
+                            if (diff.afterHoldsCug) {
+                                NodeBuilder cugNode = diff.afterBuilder.getChildNode(REP_CUG_POLICY);
+                                addNestedCugPath(cugNode, afterBuilder.getChildNode(REP_CUG_POLICY), path);
+                                break;
+                            } else if (diff.isRoot) {
+                                long cnt = addNestedCugPath(diff.afterBuilder, afterBuilder.getChildNode(name), path);
+                                diff.afterBuilder.setProperty(HIDDEN_TOP_CUG_CNT, cnt, Type.LONG);
+
+                            }
+                            diff = diff.parentDiff;
+                        }
+                    }
+                    // no need to traverse down the CUG policy node.
+                } else {
+                    after.compareAgainstBaseState(EMPTY_NODE, new Diff(this, name, null, afterBuilder.getChildNode(name)));
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public boolean childNodeChanged(String name, NodeState before, NodeState after) {
+            if (!NodeStateUtils.isHidden(name)) {
+                after.compareAgainstBaseState(before, new Diff(this, name, before, afterBuilder.getChildNode(name)));
+            }
+            return true;
+        }
+
+        @Override
+        public boolean childNodeDeleted(String name, NodeState before) {
+            if (!NodeStateUtils.isHidden(name)) {
+                if (CugUtil.definesCug(name, before)) {
+                    deletedCUGs.add(path);
+                    // reconnect information about nested cugs at a parent if
+                    // only the CUG got removed but the whole subtree including CUGs
+                    // are still present.
+                    Set<String> reconnect = Sets.newHashSet();
+                    if (afterBuilder != null) {
+                        for (String nestedCug : before.getStrings(HIDDEN_NESTED_CUGS)) {
+                            if (!deletedCUGs.contains(nestedCug)) {
+                                String relPath = PathUtils.relativize(path, nestedCug);
+                                NodeState ns = NodeStateUtils.getNode(afterBuilder.getNodeState(), relPath);
+                                if (CugUtil.hasCug(ns)) {
+                                    reconnect.add(nestedCug);
+                                }
+                            }
+                        }
+                    }
+                    if (isRoot) {
+                        if (!Iterables.isEmpty(reconnect)) {
+                            afterBuilder.setProperty(HIDDEN_NESTED_CUGS, reconnect, Type.STRINGS);
+                            afterBuilder.setProperty(HIDDEN_TOP_CUG_CNT, reconnect.size());
+                        }
+                    } else {
+                        Diff diff = parentDiff;
+                        while (diff != null) {
+                            if (diff.afterHoldsCug) {
+                                // found an existing parent CUG
+                                NodeBuilder cugNode = diff.afterBuilder.getChildNode(REP_CUG_POLICY);
+                                if (removeNestedCugPath(cugNode, path, reconnect) > -1) {
+                                    break;
+                                }
+                            }
+                            if (CugUtil.hasCug(diff.beforeState)) {
+                                // parent CUG got removed -> no removal/reconnect required if current path is listed.
+                                NodeState cugNode = diff.beforeState.getChildNode(REP_CUG_POLICY);
+                                PropertyState ps = cugNode.getProperty(HIDDEN_NESTED_CUGS);
+                                if (ps != null && Iterables.contains(ps.getValue(Type.STRINGS), path)) {
+                                    log.debug("Nested cug property containing " + path + " has also been removed; no reconnect required.");
+                                    break;
+                                }
+                            }
+                            if (diff.isRoot) {
+                                long cnt = removeNestedCugPath(diff.afterBuilder, path, reconnect);
+                                if (cnt < 0) {
+                                    log.warn("Failed to updated nested CUG info for path '" + path + "'.");
+                                } else if (cnt == 0) {
+                                    diff.afterBuilder.removeProperty(HIDDEN_TOP_CUG_CNT);
+                                } else {
+                                    diff.afterBuilder.setProperty(HIDDEN_TOP_CUG_CNT, cnt, Type.LONG);
+                                }
+                            }
+                            diff = diff.parentDiff;
+                        }
+                    }
+                    // no need to traverse down the CUG policy node
+                } else {
+                    EMPTY_NODE.compareAgainstBaseState(before, new Diff(this, name, before, null));
+                }
+            }
+            return true;
+        }
+    }
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/TopLevelPaths.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/TopLevelPaths.java?rev=1720618&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/TopLevelPaths.java (added)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/TopLevelPaths.java Thu Dec 17 17:40:03 2015
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.spi.security.authorization.cug.impl;
+
+import javax.annotation.Nonnull;
+
+import com.google.common.collect.Iterables;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.util.Text;
+
+/**
+ * Utility class to determine the top-level CUG paths as recorded on the root
+ * node.
+ */
+class TopLevelPaths implements CugConstants {
+
+    static final long NONE = -1;
+    static final long MAX_CNT = 10;
+
+    private final Root root;
+
+    private Boolean hasAny;
+    private Long cnt;
+    private String[] paths;
+
+    TopLevelPaths(Root root) {
+        this.root = root;
+    }
+
+    boolean hasAny() {
+        if (hasAny == null) {
+            Tree rootTree = root.getTree(PathUtils.ROOT_PATH);
+            hasAny = rootTree.hasProperty(HIDDEN_TOP_CUG_CNT) || CugUtil.hasCug(rootTree);
+        }
+        return hasAny;
+    }
+
+    boolean contains(@Nonnull String path) {
+        if (!hasAny()) {
+            return false;
+        }
+        if (PathUtils.denotesRoot(path)) {
+            return true;
+        }
+
+        if (cnt == null) {
+            Tree rootTree = root.getTree(PathUtils.ROOT_PATH);
+            PropertyState hiddenTopCnt = rootTree.getProperty(HIDDEN_TOP_CUG_CNT);
+            if (hiddenTopCnt != null) {
+                cnt = hiddenTopCnt.getValue(Type.LONG);
+                if (cnt <= MAX_CNT) {
+                    PropertyState hidden = root.getTree(PathUtils.ROOT_PATH).getProperty(HIDDEN_NESTED_CUGS);
+                    paths = (hidden == null) ? new String[0] : Iterables.toArray(hidden.getValue(Type.STRINGS), String.class);
+                } else {
+                    paths = null;
+                }
+            } else {
+                cnt = NONE;
+            }
+        }
+
+        if (cnt == NONE) {
+            return false;
+        } if (cnt > MAX_CNT) {
+            return true;
+        } else if (paths != null) {
+            for (String p : paths) {
+                if (Text.isDescendantOrEqual(path, p)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/AbstractCugTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/AbstractCugTest.java?rev=1720618&r1=1720617&r2=1720618&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/AbstractCugTest.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/AbstractCugTest.java Thu Dec 17 17:40:03 2015
@@ -27,6 +27,7 @@ import javax.jcr.security.AccessControlM
 import javax.jcr.security.AccessControlPolicy;
 import javax.jcr.security.AccessControlPolicyIterator;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.Group;
@@ -48,6 +49,8 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
 import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.apache.jackrabbit.oak.util.TreeUtil;
+import org.apache.jackrabbit.util.Text;
 
 import static org.junit.Assert.assertTrue;
 
@@ -60,11 +63,14 @@ public class AbstractCugTest extends Abs
 
     static final String SUPPORTED_PATH = "/content";
     static final String SUPPORTED_PATH2 = "/content2";
+    static final String SUPPORTED_PATH3 = "/some/content/tree";
     static final String UNSUPPORTED_PATH = "/testNode";
     static final String INVALID_PATH = "/path/to/non/existing/tree";
 
+    static final String[] SUPPORTED_PATHS = {SUPPORTED_PATH, SUPPORTED_PATH2, SUPPORTED_PATH3};
+
     static final ConfigurationParameters CUG_CONFIG = ConfigurationParameters.of(
-            CugConstants.PARAM_CUG_SUPPORTED_PATHS, new String[] {SUPPORTED_PATH, SUPPORTED_PATH2},
+            CugConstants.PARAM_CUG_SUPPORTED_PATHS, SUPPORTED_PATHS,
             CugConstants.PARAM_CUG_ENABLED, true);
 
     private static final String TEST_GROUP_ID = "testGroup" + UUID.randomUUID();
@@ -74,10 +80,28 @@ public class AbstractCugTest extends Abs
     public void before() throws Exception {
         super.before();
 
+        /**
+         * Create tree structure:
+         *
+         * + root
+         *   + content
+         *     + subtree
+         *   + content2
+         *   + some
+         *     + content
+         *       + tree
+         *   + testNode
+         *     + child
+         */
         NodeUtil rootNode = new NodeUtil(root.getTree("/"));
+
         NodeUtil content = rootNode.addChild("content", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
         content.addChild("subtree", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+
         rootNode.addChild("content2", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+
+        rootNode.addChild("some", NodeTypeConstants.NT_OAK_UNSTRUCTURED).addChild("content", NodeTypeConstants.NT_OAK_UNSTRUCTURED).addChild("tree", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+
         NodeUtil testNode = rootNode.addChild("testNode", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
         testNode.addChild("child", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
         root.commit();
@@ -98,9 +122,12 @@ public class AbstractCugTest extends Abs
             if (testUser2 != null) {
                 testUser2.remove();
             }
-            root.getTree(SUPPORTED_PATH).remove();
-            root.getTree(SUPPORTED_PATH2).remove();
-            root.getTree(UNSUPPORTED_PATH).remove();
+            for (String p : new String[] {SUPPORTED_PATH, SUPPORTED_PATH2, Text.getAbsoluteParent(SUPPORTED_PATH3, 0), UNSUPPORTED_PATH}) {
+                Tree t = root.getTree(p);
+                if (t.exists()) {
+                    t.remove();
+                }
+            }
             root.commit();
         } finally {
             super.after();
@@ -132,6 +159,8 @@ public class AbstractCugTest extends Abs
         ((Group) uMgr.getAuthorizable(testGroupPrincipal)).addMember(testUser2);
         root.commit();
 
+        User testUser = getTestUser();
+
         // add more child nodes
         NodeUtil n = new NodeUtil(root.getTree(SUPPORTED_PATH));
         n.addChild("a", NT_OAK_UNSTRUCTURED).addChild("b", NT_OAK_UNSTRUCTURED).addChild("c", NT_OAK_UNSTRUCTURED);
@@ -152,7 +181,7 @@ public class AbstractCugTest extends Abs
         // - testGroup ; allow ; jcr:read, jcr:write, jcr:readAccessControl
         AccessControlManager acMgr = getAccessControlManager(root);
         AccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, "/content");
-        acl.addAccessControlEntry(getTestUser().getPrincipal(), privilegesFromNames(
+        acl.addAccessControlEntry(testUser.getPrincipal(), privilegesFromNames(
                 PrivilegeConstants.JCR_READ));
         acl.addAccessControlEntry(testGroupPrincipal, privilegesFromNames(
                         PrivilegeConstants.JCR_READ, PrivilegeConstants.REP_WRITE, PrivilegeConstants.JCR_READ_ACCESS_CONTROL)
@@ -175,6 +204,14 @@ public class AbstractCugTest extends Abs
         throw new IllegalStateException("Unable to create CUG at " + absPath);
     }
 
+    static void createCug(@Nonnull Root root, @Nonnull String path, @Nonnull String principalName) throws RepositoryException {
+        Tree tree = root.getTree(path);
+        Preconditions.checkState(tree.exists());
+
+        TreeUtil.addMixin(tree, MIX_REP_CUG_MIXIN, root.getTree(NODE_TYPES_PATH), null);
+        new NodeUtil(tree).addChild(REP_CUG_POLICY, NT_REP_CUG_POLICY).setStrings(REP_PRINCIPAL_NAMES, principalName);
+    }
+
     Principal getTestGroupPrincipal() throws Exception {
         UserManager uMgr = getUserManager(root);
         Group g = uMgr.getAuthorizable(TEST_GROUP_ID, Group.class);

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/AccessControlTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/AccessControlTest.java?rev=1720618&r1=1720617&r2=1720618&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/AccessControlTest.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/AccessControlTest.java Thu Dec 17 17:40:03 2015
@@ -82,7 +82,7 @@ public class AccessControlTest extends A
                 "/content2/rep:cugPolicy"
         );
 
-        pp = createCugPermissionProvider(ImmutableSet.of("/"), EveryonePrincipal.getInstance(), getTestGroupPrincipal(), getTestUser().getPrincipal());
+        pp = createCugPermissionProvider(ImmutableSet.of(PathUtils.ROOT_PATH), EveryonePrincipal.getInstance(), getTestGroupPrincipal(), getTestUser().getPrincipal());
     }
 
     @Test

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugAccessControlManagerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugAccessControlManagerTest.java?rev=1720618&r1=1720617&r2=1720618&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugAccessControlManagerTest.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugAccessControlManagerTest.java Thu Dec 17 17:40:03 2015
@@ -221,7 +221,7 @@ public class CugAccessControlManagerTest
         root.commit();
 
         ConfigurationParameters config = ConfigurationParameters.of(AuthorizationConfiguration.NAME, ConfigurationParameters.of(
-                    CugConstants.PARAM_CUG_SUPPORTED_PATHS, new String[] {SUPPORTED_PATH, SUPPORTED_PATH2},
+                    CugConstants.PARAM_CUG_SUPPORTED_PATHS, SUPPORTED_PATHS,
                     CugConstants.PARAM_CUG_ENABLED, false));
         CugAccessControlManager acMgr = new CugAccessControlManager(root, NamePathMapper.DEFAULT, new CugSecurityProvider(config));
         AccessControlPolicy[] policies = acMgr.getEffectivePolicies(SUPPORTED_PATH);

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugEvaluationTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugEvaluationTest.java?rev=1720618&r1=1720617&r2=1720618&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugEvaluationTest.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugEvaluationTest.java Thu Dec 17 17:40:03 2015
@@ -62,6 +62,15 @@ public class CugEvaluationTest extends A
     public void before() throws Exception {
         super.before();
 
+        // create cugs
+        // - /content/a     : allow testGroup, deny everyone
+        // - /content/aa/bb : allow testGroup, deny everyone
+        // - /content/a/b/c : allow everyone,  deny testGroup (isolated)
+        // - /content2      : allow everyone,  deny testGroup (isolated)
+
+        // regular acl:
+        // - /content       : allow testUser, jcr:read
+        // - /content       : allow testGroup, jcr:read, jcr:write, jcr:readAccessControl
         setupCugsAndAcls();
 
         testGroupPrincipal = getTestGroupPrincipal();

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProviderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProviderTest.java?rev=1720618&r1=1720617&r2=1720618&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProviderTest.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugPermissionProviderTest.java Thu Dec 17 17:40:03 2015
@@ -64,6 +64,13 @@ public class CugPermissionProviderTest e
         PATH_INCUG_MAP.put("/content/a/b/c/jcr:primaryType", true);
         PATH_INCUG_MAP.put("/content/aa", false);
         PATH_INCUG_MAP.put("/content/aa/bb/cc", true);
+
+        // path below supported-path but which never contains a cug
+        PATH_INCUG_MAP.put("/content/no", false);
+        PATH_INCUG_MAP.put("/content/no/cug", false);
+        PATH_INCUG_MAP.put("/content/no/cug/in", false);
+        PATH_INCUG_MAP.put("/content/no/cug/in/subtree", false);
+
         // paths that may not contain cugs anyway
         PATH_INCUG_MAP.put(NODE_TYPES_PATH, false);
         PATH_INCUG_MAP.put("/", false);
@@ -86,7 +93,8 @@ public class CugPermissionProviderTest e
             "/content/aa", "/content/aa/jcr:primaryType",
             "/content/bb", "/content/bb/jcr:primaryType",
             "/content/aa/bb/rep:cugPolicy", "/content/aa/bb/rep:cugPolicy/jcr:primaryType", "/content/aa/bb/rep:cugPolicy/rep:principalNames",
-            "/content/nonExisting", "/content/nonExisting/jcr:primaryType");
+            "/content/nonExisting", "/content/nonExisting/jcr:primaryType",
+            "/content/no","/content/no/cug","/content/no/cug/in","/content/no/cug/in/subtree");
 
     private Principal testGroupPrincipal;
     private CugPermissionProvider cugPermProvider;
@@ -102,6 +110,7 @@ public class CugPermissionProviderTest e
         NodeUtil n = new NodeUtil(root.getTree(SUPPORTED_PATH));
         n.addChild("a", NT_OAK_UNSTRUCTURED).addChild("b", NT_OAK_UNSTRUCTURED).addChild("c", NT_OAK_UNSTRUCTURED);
         n.addChild("aa", NT_OAK_UNSTRUCTURED).addChild("bb", NT_OAK_UNSTRUCTURED).addChild("cc", NT_OAK_UNSTRUCTURED);
+        n.addChild("no", NT_OAK_UNSTRUCTURED).addChild("cug", NT_OAK_UNSTRUCTURED).addChild("in", NT_OAK_UNSTRUCTURED).addChild("subtree", NT_OAK_UNSTRUCTURED);
 
         createCug("/content/a", testGroupPrincipal);
         createCug("/content/a/b/c", EveryonePrincipal.getInstance());

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermissionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermissionTest.java?rev=1720618&r1=1720617&r2=1720618&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermissionTest.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugTreePermissionTest.java Thu Dec 17 17:40:03 2015
@@ -21,12 +21,15 @@ import javax.annotation.Nonnull;
 
 import com.google.common.collect.ImmutableSet;
 import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
 import org.apache.jackrabbit.oak.plugins.tree.impl.AbstractTree;
 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.principal.EveryonePrincipal;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.util.NodeUtil;
 import org.junit.Test;
 
 import static org.junit.Assert.assertFalse;
@@ -54,7 +57,7 @@ public class CugTreePermissionTest exten
     }
 
     private CugTreePermission getCugTreePermission(@Nonnull String path, @Nonnull Principal... principals) {
-        CugPermissionProvider pp = createCugPermissionProvider(ImmutableSet.of(SUPPORTED_PATH, SUPPORTED_PATH2), principals);
+        CugPermissionProvider pp = createCugPermissionProvider(ImmutableSet.copyOf(SUPPORTED_PATHS), principals);
         TreePermission targetTp = getTreePermission(root, path, pp);
         assertTrue(targetTp instanceof CugTreePermission);
         return (CugTreePermission) targetTp;
@@ -69,7 +72,7 @@ public class CugTreePermissionTest exten
         child = deniedTp.getChildPermission("subtree", ns);
         assertTrue(child instanceof CugTreePermission);
 
-        NodeState cugNs = ((AbstractTree) root.getTree(SUPPORTED_PATH + "/" + REP_CUG_POLICY)).getNodeState();
+        NodeState cugNs = ((AbstractTree) root.getTree(PathUtils.concat(SUPPORTED_PATH, REP_CUG_POLICY))).getNodeState();
         TreePermission cugChild = allowedTp.getChildPermission(REP_CUG_POLICY, cugNs);
         assertSame(TreePermission.NO_RECOURSE, cugChild);
     }
@@ -78,20 +81,97 @@ public class CugTreePermissionTest exten
     public void testIsAllow() throws Exception {
         assertTrue(allowedTp.isAllow());
         assertFalse(deniedTp.isAllow());
+    }
+
+    @Test
+    public void testIsAllowNestedCug() throws Exception {
+        String childPath = SUPPORTED_PATH + "/subtree";
 
-        CugTreePermission tp = getCugTreePermission(SUPPORTED_PATH2);
+        // before creating nested CUG
+        CugTreePermission tp = getCugTreePermission(childPath);
         assertFalse(tp.isAllow());
-        tp = getCugTreePermission(SUPPORTED_PATH2, getTestUser().getPrincipal(), EveryonePrincipal.getInstance());
+        tp = getCugTreePermission(childPath, getTestUser().getPrincipal(), EveryonePrincipal.getInstance());
+        assertTrue(tp.isAllow());
+
+        // create nested CUG for same principal
+        createCug(childPath, EveryonePrincipal.getInstance());
+        root.commit();
+
+        tp = getCugTreePermission(childPath);
         assertFalse(tp.isAllow());
+
+        tp = getCugTreePermission(childPath, getTestUser().getPrincipal(), EveryonePrincipal.getInstance());
+        assertTrue(tp.isAllow());
     }
 
     @Test
     public void testIsInCug() {
         assertTrue(allowedTp.isInCug());
         assertTrue(deniedTp.isInCug());
+    }
+
+    @Test
+    public void testIsInCugChild() throws Exception {
+        String childPath = SUPPORTED_PATH + "/subtree";
+
+        CugTreePermission tp = getCugTreePermission(childPath);
+        assertTrue(tp.isInCug());
+
+        tp = getCugTreePermission(childPath, getTestUser().getPrincipal(), EveryonePrincipal.getInstance());
+        assertTrue(tp.isInCug());
+    }
+
+    @Test
+    public void testIsInCugNestedCug() throws Exception {
+        String childPath = SUPPORTED_PATH + "/subtree";
+
+        // create nested CUG for same principal
+        createCug(childPath, EveryonePrincipal.getInstance());
+        root.commit();
+
+        CugTreePermission tp = getCugTreePermission(childPath);
+        assertTrue(tp.isInCug());
+
+        tp = getCugTreePermission(childPath, getTestUser().getPrincipal(), EveryonePrincipal.getInstance());
+        assertTrue(tp.isInCug());
+    }
+
+    @Test
+    public void testIsInCugSupportedPathWithoutCug() throws Exception {
+        NodeUtil node = new NodeUtil(root.getTree(SUPPORTED_PATH2));
+        Tree c1 = node.addChild("c1", NT_OAK_UNSTRUCTURED).getTree();
+        Tree c2 = node.addChild("c2", NT_OAK_UNSTRUCTURED).getTree();
+
+        String cugPath = c2.getPath();
+        createCug(cugPath, getTestGroupPrincipal());
+        root.commit();
+
+        assertTrue(getCugTreePermission(cugPath).isInCug());
+        assertFalse(getCugTreePermission(c1.getPath()).isInCug());
+    }
+
+    @Test
+    public void testHasNested() {
+        CugTreePermission tp = getCugTreePermission(SUPPORTED_PATH);
+        assertFalse(tp.hasNestedCug());
+
+        String childPath = SUPPORTED_PATH + "/subtree";
+        tp = getCugTreePermission(childPath);
+        assertFalse(tp.hasNestedCug());
+    }
+
+    @Test
+    public void testHasNestedWithNestedCug() throws Exception {
+        // create nested CUG for same principal
+        String childPath = SUPPORTED_PATH + "/subtree";
+        createCug(childPath, EveryonePrincipal.getInstance());
+        root.commit();
+
+        CugTreePermission tp = getCugTreePermission(SUPPORTED_PATH);
+        assertTrue(tp.hasNestedCug());
 
-        CugTreePermission tp = getCugTreePermission(SUPPORTED_PATH2);
-        assertFalse(tp.isInCug());
+        tp = getCugTreePermission(childPath);
+        assertFalse(tp.hasNestedCug());
     }
 
     @Test

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugUtilTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugUtilTest.java?rev=1720618&r1=1720617&r2=1720618&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugUtilTest.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugUtilTest.java Thu Dec 17 17:40:03 2015
@@ -16,11 +16,16 @@
  */
 package org.apache.jackrabbit.oak.spi.security.authorization.cug.impl;
 
+import javax.annotation.Nonnull;
+
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.plugins.tree.impl.AbstractTree;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
 import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.xml.ImportBehavior;
 import org.apache.jackrabbit.oak.util.NodeUtil;
 import org.junit.Test;
@@ -49,32 +54,60 @@ public class CugUtilTest extends Abstrac
         }
     }
 
+    @Nonnull
+    private static NodeState getNodeState(@Nonnull Tree tree) {
+        return ((AbstractTree) tree).getNodeState();
+    }
+
     @Test
     public void testHasCug() throws Exception {
-        assertFalse(CugUtil.hasCug(root.getTree("/")));
-        assertFalse(CugUtil.hasCug(root.getTree(INVALID_PATH)));
-        assertFalse(CugUtil.hasCug(root.getTree(UNSUPPORTED_PATH)));
-        assertFalse(CugUtil.hasCug(root.getTree(SUPPORTED_PATH + "/subtree")));
-        assertFalse(CugUtil.hasCug(root.getTree(SUPPORTED_PATH2)));
-
         assertTrue(CugUtil.hasCug(root.getTree(SUPPORTED_PATH)));
 
+        for (String path : new String[] {PathUtils.ROOT_PATH, INVALID_PATH, UNSUPPORTED_PATH, SUPPORTED_PATH + "/subtree", SUPPORTED_PATH2, SUPPORTED_PATH3}) {
+            assertFalse(CugUtil.hasCug(root.getTree(path)));
+        }
+
         new NodeUtil(root.getTree(SUPPORTED_PATH2)).addChild(REP_CUG_POLICY, NodeTypeConstants.NT_OAK_UNSTRUCTURED).getTree();
         assertTrue(CugUtil.hasCug(root.getTree(SUPPORTED_PATH2)));
     }
 
     @Test
-    public void testGetCug() throws Exception {
-        assertNull(CugUtil.getCug(root.getTree("/")));
-        assertNull(CugUtil.getCug(root.getTree(INVALID_PATH)));
-        assertNull(CugUtil.getCug(root.getTree(UNSUPPORTED_PATH)));
-        assertNull(CugUtil.getCug(root.getTree(SUPPORTED_PATH + "/subtree")));
-        assertNull(CugUtil.getCug(root.getTree(SUPPORTED_PATH2)));
+    public void testHasCugNodeState() throws Exception {
+        assertTrue(CugUtil.hasCug(getNodeState(root.getTree(SUPPORTED_PATH))));
+
+        assertFalse(CugUtil.hasCug((NodeState) null));
+
+        for (String path : new String[] {PathUtils.ROOT_PATH, INVALID_PATH, UNSUPPORTED_PATH, SUPPORTED_PATH + "/subtree", SUPPORTED_PATH2, SUPPORTED_PATH3}) {
+            assertFalse(CugUtil.hasCug(getNodeState(root.getTree(path))));
+        }
+
+        new NodeUtil(root.getTree(SUPPORTED_PATH2)).addChild(REP_CUG_POLICY, NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+        assertTrue(CugUtil.hasCug(getNodeState(root.getTree(SUPPORTED_PATH2))));
+    }
+
+    @Test
+    public void testHasCugNodeBuilder() throws Exception {
+        assertTrue(CugUtil.hasCug(getNodeState(root.getTree(SUPPORTED_PATH)).builder()));
+
+        assertFalse(CugUtil.hasCug((NodeBuilder) null));
+        for (String path : new String[] {PathUtils.ROOT_PATH, INVALID_PATH, UNSUPPORTED_PATH, SUPPORTED_PATH + "/subtree", SUPPORTED_PATH2, SUPPORTED_PATH3}) {
+            assertFalse(CugUtil.hasCug(getNodeState(root.getTree(path)).builder()));
+        }
+
+        new NodeUtil(root.getTree(SUPPORTED_PATH2)).addChild(REP_CUG_POLICY, NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+        assertTrue(CugUtil.hasCug(getNodeState(root.getTree(SUPPORTED_PATH2)).builder()));
+    }
 
+    @Test
+    public void testGetCug() throws Exception {
         assertNotNull(CugUtil.getCug(root.getTree(SUPPORTED_PATH)));
 
-        Tree invalid = new NodeUtil(root.getTree(SUPPORTED_PATH2)).addChild(REP_CUG_POLICY, NodeTypeConstants.NT_OAK_UNSTRUCTURED).getTree();
-        assertNull(CugUtil.getCug(invalid));
+        for (String path : new String[] {PathUtils.ROOT_PATH, INVALID_PATH, UNSUPPORTED_PATH, SUPPORTED_PATH + "/subtree", SUPPORTED_PATH2, SUPPORTED_PATH3}) {
+            assertNull(CugUtil.getCug(root.getTree(path)));
+        }
+
+        new NodeUtil(root.getTree(SUPPORTED_PATH2)).addChild(REP_CUG_POLICY, NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+        assertNull(CugUtil.getCug(root.getTree(SUPPORTED_PATH2)));
     }
 
     @Test

Modified: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/EmptyCugTreePermissionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/EmptyCugTreePermissionTest.java?rev=1720618&r1=1720617&r2=1720618&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/EmptyCugTreePermissionTest.java (original)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/EmptyCugTreePermissionTest.java Thu Dec 17 17:40:03 2015
@@ -90,8 +90,7 @@ public class EmptyCugTreePermissionTest
         String name = Text.getName(SUPPORTED_PATH2);
         NodeState ns = rootState.getChildNode(name);
         TreePermission child = tp.getChildPermission(name, ns);
-        assertCugPermission(child, true);
-        assertFalse(((CugTreePermission) child).isInCug());
+        assertSame(TreePermission.NO_RECOURSE, child);
 
         name = Text.getName(SUPPORTED_PATH);
         ns = rootState.getChildNode(name);

Added: jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/NestedCugHookRootSupportedTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/NestedCugHookRootSupportedTest.java?rev=1720618&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/NestedCugHookRootSupportedTest.java (added)
+++ jackrabbit/oak/trunk/oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/NestedCugHookRootSupportedTest.java Thu Dec 17 17:40:03 2015
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.spi.security.authorization.cug.impl;
+
+import org.apache.jackrabbit.oak.commons.PathUtils;
+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.junit.Test;
+
+import static org.apache.jackrabbit.oak.commons.PathUtils.ROOT_PATH;
+import static org.junit.Assert.assertTrue;
+
+public class NestedCugHookRootSupportedTest extends NestedCugHookTest {
+
+    @Override
+    protected ConfigurationParameters getSecurityConfigParameters() {
+        return ConfigurationParameters.of(AuthorizationConfiguration.NAME, ConfigurationParameters.of(
+                CugConstants.PARAM_CUG_SUPPORTED_PATHS, new String[] {PathUtils.ROOT_PATH},
+                CugConstants.PARAM_CUG_ENABLED, true));
+    }
+
+    @Test
+    public void testAddAtRoot() throws Exception {
+        createCug(ROOT_PATH, EveryonePrincipal.getInstance());
+        root.commit();
+        assertTrue(root.getTree("/").hasChild(REP_CUG_POLICY));
+
+        createCug("/content", getTestGroupPrincipal());
+        createCug("/content2", EveryonePrincipal.getInstance());
+        root.commit();
+
+        assertNestedCugs(root, ROOT_PATH, true, "/content", "/content2");
+    }
+
+    @Test
+    public void testAddAtRoot2() throws Exception {
+        createCug("/content", getTestGroupPrincipal());
+        createCug("/content2", EveryonePrincipal.getInstance());
+        root.commit();
+
+        assertNestedCugs(root, ROOT_PATH, false, "/content", "/content2");
+
+        createCug(ROOT_PATH, EveryonePrincipal.getInstance());
+        root.commit();
+
+        assertNestedCugs(root, ROOT_PATH, false);
+        assertNestedCugs(root, ROOT_PATH, true, "/content", "/content2");
+    }
+
+    @Test
+    public void testAddAtRoot3() throws Exception {
+        createCug(ROOT_PATH, EveryonePrincipal.getInstance());
+        createCug("/content", getTestGroupPrincipal());
+        createCug("/content2", EveryonePrincipal.getInstance());
+        root.commit();
+
+        assertNestedCugs(root, ROOT_PATH, true, "/content", "/content2");
+    }
+
+    @Test
+    public void testRemoveRootCug() throws Exception {
+        // add cug at /
+        createCug(ROOT_PATH, EveryonePrincipal.getInstance());
+        createCug("/content", getTestGroupPrincipal());
+        createCug("/content2", EveryonePrincipal.getInstance());
+        root.commit();
+
+        assertTrue(removeCug(ROOT_PATH, true));
+        assertNestedCugs(root, ROOT_PATH, false, "/content", "/content2");
+
+        assertTrue(removeCug("/content", true));
+        assertNestedCugs(root, ROOT_PATH, false, "/content2");
+
+        assertTrue(removeCug("/content2", true));
+        assertNestedCugs(root, ROOT_PATH, false);
+    }
+
+    @Test
+    public void testRemoveRootCug2() throws Exception {
+        // add cug at /
+        createCug(ROOT_PATH, EveryonePrincipal.getInstance());
+        createCug("/content", getTestGroupPrincipal());
+        createCug("/content2", EveryonePrincipal.getInstance());
+        root.commit();
+
+        removeCug("/content", true);
+        assertNestedCugs(root, ROOT_PATH, true, "/content2");
+
+        removeCug("/", true);
+        assertNestedCugs(root, ROOT_PATH, false, "/content2");
+
+        removeCug("/content2", true);
+        assertNestedCugs(root, ROOT_PATH, false);
+    }
+
+    @Test
+    public void testRemoveRootCug3() throws Exception {
+        // add cug at /
+        createCug(ROOT_PATH, EveryonePrincipal.getInstance());
+        createCug("/content", getTestGroupPrincipal());
+        createCug("/content2", EveryonePrincipal.getInstance());
+        root.commit();
+
+        assertTrue(removeCug("/content", true));
+        assertNestedCugs(root, ROOT_PATH, true, "/content2");
+
+        assertTrue(removeCug("/content2", true));
+        assertNestedCugs(root, ROOT_PATH, true);
+
+        assertTrue(removeCug(ROOT_PATH, true));
+        assertNestedCugs(root, ROOT_PATH, false);
+    }
+
+    @Test
+    public void testRemoveRootCug4() throws Exception {
+        // add cug at /
+        createCug("/", EveryonePrincipal.getInstance());
+        createCug("/content", getTestGroupPrincipal());
+        createCug("/content2", EveryonePrincipal.getInstance());
+        root.commit();
+
+        assertTrue(removeCug("/content", false));
+        assertTrue(removeCug("/content2", false));
+        assertTrue(removeCug("/", false));
+        root.commit();
+
+        assertNestedCugs(root, "/", false);
+    }
+}
\ No newline at end of file