Author: angela
Date: Fri Oct 23 16:09:01 2015
New Revision: 1710257

URL: http://svn.apache.org/viewvc?rev=1710257&view=rev
Log:
OAK-3548 : Improve permission evaluation for version store items

Added:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/VersionTreePermission.java
   (with props)
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/VersionTreePermissionTest.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java?rev=1710257&r1=1710256&r2=1710257&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java
 Fri Oct 23 16:09:01 2015
@@ -36,13 +36,12 @@ import org.apache.jackrabbit.commons.ite
 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.oak.plugins.identifier.IdentifierManager;
 import org.apache.jackrabbit.oak.plugins.tree.TreeType;
 import org.apache.jackrabbit.oak.plugins.tree.TreeTypeProvider;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.tree.impl.ImmutableTree;
-import org.apache.jackrabbit.oak.plugins.version.VersionConstants;
+import org.apache.jackrabbit.oak.plugins.version.ReadOnlyVersionManager;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
 import org.apache.jackrabbit.oak.spi.security.Context;
 import 
org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
@@ -54,7 +53,7 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
-import org.apache.jackrabbit.oak.util.TreeUtil;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -80,6 +79,7 @@ final class CompiledPermissionImpl imple
     private final TreeTypeProvider typeProvider;
 
     private Root root;
+    private ReadOnlyVersionManager versionManager;
     private PrivilegeBitsProvider bitsProvider;
 
     private CompiledPermissionImpl(@Nonnull Set<Principal> principals,
@@ -132,6 +132,8 @@ final class CompiledPermissionImpl imple
     public void refresh(@Nonnull Root root, @Nonnull String workspaceName) {
         this.root = root;
         this.bitsProvider = new PrivilegeBitsProvider(root);
+        this.versionManager = null;
+
         store.flush(root);
         userStore.flush();
         groupStore.flush();
@@ -153,22 +155,21 @@ final class CompiledPermissionImpl imple
     @Override
     public TreePermission getTreePermission(@Nonnull Tree tree, @Nonnull 
TreePermission parentPermission) {
         if (tree.isRoot()) {
-            return new TreePermissionImpl(tree, TreeType.DEFAULT, EMPTY);
+            return createRootPermission(tree);
+        }
+        if (parentPermission instanceof VersionTreePermission) {
+            return ((VersionTreePermission) 
parentPermission).createChildPermission(tree);
         }
-        TreeType parentType = getParentType(parentPermission);
-        TreeType type = typeProvider.getType(tree, parentType);
+
+        TreeType type = typeProvider.getType(tree, 
getParentType(parentPermission));
         switch (type) {
             case HIDDEN:
                 return ALL;
             case VERSION:
-                String ntName = TreeUtil.getPrimaryTypeName(tree);
-                if (ntName == null) {
-                    return EMPTY;
-                }
-                if (VersionConstants.VERSION_STORE_NT_NAMES.contains(ntName) 
|| VersionConstants.NT_ACTIVITY.equals(ntName)) {
+                if (ReadOnlyVersionManager.isVersionStoreTree(tree)) {
                     return new TreePermissionImpl(tree, TreeType.VERSION, 
parentPermission);
                 } else {
-                    Tree versionableTree = getVersionableTree(tree);
+                    Tree versionableTree = 
getVersionManager().getVersionable(tree, workspaceName);
                     if (versionableTree == null) {
                         log.warn("Cannot retrieve versionable node for " + 
tree.getPath());
                         return EMPTY;
@@ -182,8 +183,7 @@ final class CompiledPermissionImpl imple
                         while (!versionableTree.exists()) {
                             versionableTree = versionableTree.getParent();
                         }
-                        TreePermission pp = 
getParentPermission(versionableTree, TreeType.VERSION);
-                        return new TreePermissionImpl(versionableTree, 
TreeType.VERSION, pp);
+                        return new VersionTreePermission(tree, 
buildVersionDelegatee(versionableTree));
                     }
                 }
             case INTERNAL:
@@ -194,16 +194,33 @@ final class CompiledPermissionImpl imple
     }
 
     @Nonnull
-    private TreePermission getParentPermission(@Nonnull Tree tree, TreeType 
type) {
+    private TreePermission buildVersionDelegatee(@Nonnull Tree 
versionableTree) {
+        if (!versionableTree.exists()) {
+            return TreePermission.EMPTY;
+        } else if (versionableTree.isRoot()) {
+            return createRootPermission(versionableTree);
+        }
+        TreeType type = typeProvider.getType(versionableTree);
+        switch (type) {
+            case HIDDEN : return ALL;
+            case INTERNAL : return EMPTY;
+            // case VERSION is never expected here
+            default:
+                return new TreePermissionImpl(versionableTree, type, 
buildParentPermission(versionableTree));
+        }
+    }
+
+    @Nonnull
+    private TreePermission buildParentPermission(@Nonnull Tree tree) {
         List<Tree> trees = new ArrayList<Tree>();
         while (!tree.isRoot()) {
             tree = tree.getParent();
-            if (tree.exists()) {
-                trees.add(0, tree);
-            }
+            trees.add(0, tree);
         }
         TreePermission pp = EMPTY;
+        TreeType type = TreeType.DEFAULT;
         for (Tree tr : trees) {
+            type = typeProvider.getType(tr, type);
             pp = new TreePermissionImpl(tr, type, pp);
         }
         return pp;
@@ -216,17 +233,17 @@ final class CompiledPermissionImpl imple
             case HIDDEN:
                 return true;
             case VERSION:
-                Tree versionableTree = getVersionableTree(tree);
-                if (versionableTree == null) {
+                Tree versionTree = getEvaluationTree(tree);
+                if (versionTree == null) {
                     // unable to determine the location of the versionable 
item -> deny access.
                     return false;
                 }
-                if (versionableTree.exists()) {
-                    return internalIsGranted(versionableTree, property, 
permissions);
+                if (versionTree.exists()) {
+                    return internalIsGranted(versionTree, property, 
permissions);
                 } else {
                     // versionable node does not exist (anymore) in this 
workspace;
                     // use best effort calculation based on the item path.
-                    String path = versionableTree.getPath();
+                    String path = versionTree.getPath();
                     if (property != null) {
                         path = PathUtils.concat(path, property.getName());
                     }
@@ -340,12 +357,12 @@ final class CompiledPermissionImpl imple
             case HIDDEN:
                 return PrivilegeBits.EMPTY;
             case VERSION:
-                Tree versionableTree = getVersionableTree(tree);
-                if (versionableTree == null || !versionableTree.exists()) {
+                Tree versionTree = getEvaluationTree(tree);
+                if (versionTree == null || !versionTree.exists()) {
                     // unable to determine the location of the versionable 
item -> deny access.
                     return PrivilegeBits.EMPTY;
                 }  else {
-                    return getPrivilegeBits(versionableTree);
+                    return getPrivilegeBits(versionTree);
                 }
             case INTERNAL:
                 return PrivilegeBits.EMPTY;
@@ -388,38 +405,20 @@ final class CompiledPermissionImpl imple
     }
 
     @CheckForNull
-    private Tree getVersionableTree(@Nonnull Tree versionStoreTree) {
-        String relPath = "";
-        String versionablePath = null;
-        Tree t = versionStoreTree;
-        while (t.exists() && !t.isRoot() && 
!VersionConstants.VERSION_STORE_ROOT_NAMES.contains(t.getName())) {
-            String ntName = TreeUtil.getPrimaryTypeName(t);
-            if (VersionConstants.JCR_FROZENNODE.equals(t.getName()) && t != 
versionStoreTree) {
-                relPath = PathUtils.relativize(t.getPath(), 
versionStoreTree.getPath());
-            } else if (JcrConstants.NT_VERSIONHISTORY.equals(ntName)) {
-                PropertyState prop = t.getProperty(workspaceName);
-                if (prop != null) {
-                    versionablePath = 
PathUtils.concat(prop.getValue(Type.PATH), relPath);
-                }
-                return (versionablePath == null) ? null : 
root.getTree(versionablePath);
-            } else if (VersionConstants.NT_CONFIGURATION.equals(ntName)) {
-                String rootId = TreeUtil.getString(t, 
VersionConstants.JCR_ROOT);
-                if (rootId != null) {
-                    versionablePath = new 
IdentifierManager(root).getPath(rootId);
-                    return (versionablePath == null) ? null : 
root.getTree(versionablePath);
-                } else {
-                    log.error("Missing mandatory property jcr:root with 
configuration node.");
-                    return null;
-                }
-            } else if (VersionConstants.NT_ACTIVITY.equals(ntName)) {
-                return versionStoreTree;
-            }
-            t = t.getParent();
+    private Tree getEvaluationTree(@Nonnull Tree versionStoreTree) {
+        if (ReadOnlyVersionManager.isVersionStoreTree(versionStoreTree)) {
+            return versionStoreTree;
+        } else {
+            return getVersionManager().getVersionable(versionStoreTree, 
workspaceName);
         }
+    }
 
-        // intermediate node in the version, configuration or activity store 
that
-        // matches none of the special conditions checked above -> regular 
permission eval.
-        return versionStoreTree;
+    @Nonnull
+    private ReadOnlyVersionManager getVersionManager() {
+        if (versionManager == null) {
+            versionManager = ReadOnlyVersionManager.getInstance(root, 
NamePathMapper.DEFAULT);
+        }
+        return versionManager;
     }
 
     private static TreeType getParentType(@Nonnull TreePermission 
parentPermission) {
@@ -432,6 +431,10 @@ final class CompiledPermissionImpl imple
         }
     }
 
+    private TreePermissionImpl createRootPermission(@Nonnull Tree rootTree) {
+        return new TreePermissionImpl(rootTree, TreeType.DEFAULT, EMPTY);
+    }
+
     private final class TreePermissionImpl implements TreePermission {
 
         private final Tree tree;

Added: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/VersionTreePermission.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/VersionTreePermission.java?rev=1710257&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/VersionTreePermission.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/VersionTreePermission.java
 Fri Oct 23 16:09:01 2015
@@ -0,0 +1,94 @@
+/*
+ * 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.security.authorization.permission;
+
+import java.util.Set;
+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.plugins.tree.impl.ImmutableTree;
+import org.apache.jackrabbit.oak.plugins.version.VersionConstants;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.util.TreeUtil;
+
+/**
+ * {@link TreePermission} implementations for those items in the version 
storage
+ * that are linked to a versionable node (i.e. the subtree spanned by every 
version
+ * history node. For those items, the effective permissions are defined by
+ * the corresponding versionable node (and it's ancestors).
+ */
+class VersionTreePermission implements TreePermission, VersionConstants {
+
+    private static final Set<String> NT_NAMES = ImmutableSet.of(NT_VERSION, 
NT_VERSIONLABELS);
+
+    private final Tree versionTree;
+    private final TreePermission versionablePermission;
+
+    VersionTreePermission(@Nonnull Tree versionTree, @Nonnull TreePermission 
versionablePermission) {
+        this.versionTree = versionTree;
+        this.versionablePermission = versionablePermission;
+    }
+
+    VersionTreePermission createChildPermission(@Nonnull Tree versionTree) {
+        TreePermission delegatee;
+        if (JCR_FROZENNODE.equals(versionTree.getName()) || 
NT_NAMES.contains(TreeUtil.getPrimaryTypeName(versionTree))) {
+            delegatee = versionablePermission;
+        } else {
+            delegatee = 
versionablePermission.getChildPermission(versionTree.getName(), 
((ImmutableTree) versionTree).getNodeState());
+        }
+        return new VersionTreePermission(versionTree, delegatee);
+    }
+
+    @Nonnull
+    @Override
+    public TreePermission getChildPermission(@Nonnull String childName, 
@Nonnull NodeState childState) {
+        return createChildPermission(new ImmutableTree((ImmutableTree) 
versionTree, childName, childState));
+    }
+
+    @Override
+    public boolean canRead() {
+        return versionablePermission.canRead();
+    }
+
+    @Override
+    public boolean canRead(@Nonnull PropertyState property) {
+        return versionablePermission.canRead(property);
+    }
+
+    @Override
+    public boolean canReadAll() {
+        return versionablePermission.canReadAll();
+    }
+
+    @Override
+    public boolean canReadProperties() {
+        return versionablePermission.canReadProperties();
+    }
+
+    @Override
+    public boolean isGranted(long permissions) {
+        return versionablePermission.isGranted(permissions);
+    }
+
+    @Override
+    public boolean isGranted(long permissions, @Nonnull PropertyState 
property) {
+        return versionablePermission.isGranted(permissions, property);
+    }
+}
\ No newline at end of file

Propchange: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/VersionTreePermission.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/VersionTreePermissionTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/VersionTreePermissionTest.java?rev=1710257&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/VersionTreePermissionTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/VersionTreePermissionTest.java
 Fri Oct 23 16:09:01 2015
@@ -0,0 +1,266 @@
+/*
+ * 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.security.authorization.permission;
+
+import java.lang.reflect.Field;
+import java.security.Principal;
+
+import javax.annotation.Nonnull;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+
+import com.google.common.collect.ImmutableSet;
+import 
org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.plugins.tree.RootFactory;
+import org.apache.jackrabbit.oak.plugins.tree.impl.ImmutableTree;
+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.PermissionProvider;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission;
+import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.apache.jackrabbit.oak.util.TreeUtil;
+import org.junit.Test;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class VersionTreePermissionTest extends AbstractSecurityTest implements 
NodeTypeConstants {
+
+    private ReadOnlyVersionManager vMgr;
+    private PermissionProvider pp;
+
+    private Tree testTree;
+
+    private Field vpField;
+    private Field tpImplTree;
+
+    @Override
+    public void before() throws Exception {
+        super.before();
+
+        NodeUtil testNode = new NodeUtil(root.getTree("/")).addChild("test", 
NT_OAK_UNSTRUCTURED);
+        testNode.addChild("a", NT_OAK_UNSTRUCTURED).addChild("b", 
NT_OAK_UNSTRUCTURED).addChild("c", NT_OAK_UNSTRUCTURED);
+        TreeUtil.addMixin(testNode.getTree(), MIX_VERSIONABLE, 
root.getTree(NODE_TYPES_PATH), null);
+
+        AccessControlManager acMgr = getAccessControlManager(root);
+        AccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, 
"/test");
+        acl.addAccessControlEntry(EveryonePrincipal.getInstance(), 
AccessControlUtils.privilegesFromNames(acMgr, PrivilegeConstants.JCR_READ));
+        acMgr.setPolicy("/test", acl);
+        root.commit();
+
+        // create a structure in the version storage
+        testNode.setBoolean(JCR_ISCHECKEDOUT, false);
+        root.commit();
+        testNode.setBoolean(JCR_ISCHECKEDOUT, true);
+        root.commit();
+
+        testTree = testNode.getTree();
+        vMgr = ReadOnlyVersionManager.getInstance(root, 
NamePathMapper.DEFAULT);
+        pp = 
getConfig(AuthorizationConfiguration.class).getPermissionProvider(root, 
root.getContentSession().getWorkspaceName(), 
ImmutableSet.<Principal>of(EveryonePrincipal.getInstance()));
+
+        assertTrue(pp instanceof PermissionProviderImpl);
+
+        vpField = 
VersionTreePermission.class.getDeclaredField("versionablePermission");
+        vpField.setAccessible(true);
+        Class cls = Class.forName(CompiledPermissionImpl.class.getName() + 
"$TreePermissionImpl");
+        tpImplTree = cls.getDeclaredField("tree");
+        tpImplTree.setAccessible(true);
+    }
+
+    @Override
+    public void after() throws Exception {
+        try {
+            root.refresh();
+            Tree t = root.getTree("/test");
+            if (t.exists()) {
+                t.remove();
+                root.commit();
+            }
+        } finally {
+            super.after();
+        }
+    }
+
+    private static TreePermission getVersionPermission(Root root, 
PermissionProvider pp, String path) {
+        Tree t = root.getTree("/");
+        TreePermission tp = pp.getTreePermission(t, TreePermission.EMPTY);
+        for (String name : PathUtils.elements(path)) {
+            t = t.getChild(name);
+            tp = pp.getTreePermission(t, tp);
+        }
+        return tp;
+    }
+
+    private void assertVersionPermission(@Nonnull TreePermission tp, @Nonnull 
String expectedPath, boolean canRead) throws Exception {
+        assertTrue(tp instanceof VersionTreePermission);
+        assertEquals(canRead, tp.canRead());
+        assertEquals(canRead, tp.canRead(PropertyStates.createProperty("any", 
"Value")));
+        assertEquals(canRead, tp.isGranted(Permissions.READ));
+        assertEquals(canRead, tp.isGranted(Permissions.READ, 
PropertyStates.createProperty("any", "Value")));
+        assertEquals(canRead, tp.canReadProperties());
+        assertFalse(tp.canReadAll());
+
+        VersionTreePermission vtp = (VersionTreePermission) tp;
+        TreePermission delegatee = (TreePermission) vpField.get(vtp);
+        Tree delegateeTree = (Tree) tpImplTree.get(delegatee);
+
+        assertEquals(expectedPath, delegateeTree.getPath());
+    }
+
+    @Test
+    public void testGetTreePermission() throws Exception {
+        Tree versionHistory = checkNotNull(vMgr.getVersionHistory(testTree));
+
+        String expectedPath = "/test";
+
+        TreePermission tp = getVersionPermission(root, pp, 
versionHistory.getPath());
+        assertVersionPermission(tp, expectedPath, true);
+
+        Tree vTree = versionHistory.getChild("1.0");
+        assertTrue(vTree.exists());
+        tp = pp.getTreePermission(vTree, tp);
+        assertVersionPermission(tp, expectedPath, true);
+
+        Tree frozen = vTree.getChild(JCR_FROZENNODE);
+        assertTrue(frozen.exists());
+        tp = pp.getTreePermission(frozen, tp);
+        assertVersionPermission(tp, expectedPath, true);
+
+        Tree t = frozen;
+        for (String name : new String[] {"a", "b", "c"}) {
+            t = t.getChild(name);
+            expectedPath = PathUtils.concat(expectedPath, name);
+            tp = pp.getTreePermission(t, tp);
+            assertVersionPermission(tp, expectedPath, true);
+        }
+    }
+
+    @Test
+    public void testGetChild() throws Exception {
+        Tree versionHistory = checkNotNull(vMgr.getVersionHistory(testTree));
+
+        ImmutableTree t = (ImmutableTree) 
RootFactory.createReadOnlyRoot(root).getTree("/");
+        TreePermission tp = pp.getTreePermission(t, TreePermission.EMPTY);
+        for (String name : PathUtils.elements(versionHistory.getPath())) {
+            t = t.getChild(name);
+            tp = tp.getChildPermission(name, t.getNodeState());
+        }
+
+        String expectedPath = "/test";
+        assertVersionPermission(tp, "/test", true);
+
+        NodeState ns = t.getChild("1.0").getNodeState();
+        tp = tp.getChildPermission("1.0", ns);
+        assertVersionPermission(tp, "/test", true);
+
+        ns = ns.getChildNode(JCR_FROZENNODE);
+        tp = tp.getChildPermission(JCR_FROZENNODE, ns);
+        assertVersionPermission(tp, "/test", true);
+
+        for (String name : new String[] {"a", "b", "c"}) {
+            ns = ns.getChildNode(name);
+            expectedPath = PathUtils.concat(expectedPath, name);
+
+            tp = tp.getChildPermission(name, ns);
+            assertVersionPermission(tp, expectedPath, true);
+        }
+    }
+
+    @Test
+    public void testVersionableRemoved() throws Exception {
+        Tree versionHistory = checkNotNull(vMgr.getVersionHistory(testTree));
+
+        testTree.remove();
+        root.commit();
+        pp.refresh();
+
+        TreePermission tp = getVersionPermission(root, pp, 
versionHistory.getPath());
+        assertVersionPermission(tp, "/", false);
+
+        Tree vTree = versionHistory.getChild("1.0");
+        tp = pp.getTreePermission(vTree, tp);
+        assertVersionPermission(tp, "/", false);
+
+        Tree frozen = vTree.getChild(JCR_FROZENNODE);
+        assertTrue(frozen.exists());
+        tp = pp.getTreePermission(frozen, tp);
+        assertVersionPermission(tp, "/", false);
+
+        Tree t = frozen;
+        String expectedPath = "/";
+        for (String name : new String[] {"a", "b", "c"}) {
+            t = t.getChild(name);
+            expectedPath = PathUtils.concat(expectedPath, name);
+            tp = pp.getTreePermission(t, tp);
+            assertVersionPermission(tp, expectedPath, false);
+        }
+    }
+
+    @Test
+    public void testVersionableChildRemoved() throws Exception {
+        root.getTree("/test/a/b/c").remove();
+        root.commit();
+        pp.refresh();
+
+        Tree versionHistory = checkNotNull(vMgr.getVersionHistory(testTree));
+        String frozenCPath = PathUtils.concat(versionHistory.getPath(), "1.0", 
JCR_FROZENNODE, "a/b/c");
+
+        TreePermission tp = getVersionPermission(root, pp, frozenCPath);
+        assertVersionPermission(tp, "/test/a/b/c", true);
+
+        root.getTree("/test/a").remove();
+        root.commit();
+        pp.refresh();
+
+        tp = getVersionPermission(root, pp, frozenCPath);
+        assertVersionPermission(tp, "/test/a/b/c", true);
+    }
+
+    @Test
+    public void testVersionableChildRemoved2() throws Exception {
+        root.getTree("/test/a/b").remove();
+        root.commit();
+        pp.refresh();
+
+        Tree versionHistory = checkNotNull(vMgr.getVersionHistory(testTree));
+
+        String frozenAPath = PathUtils.concat(versionHistory.getPath(), "1.0", 
JCR_FROZENNODE, "a");
+        TreePermission tp = getVersionPermission(root, pp, frozenAPath);
+        assertVersionPermission(tp, "/test/a", true);
+
+        Tree frozenB = root.getTree(frozenAPath).getChild("b");
+        tp = pp.getTreePermission(frozenB, tp);
+        assertVersionPermission(tp, "/test/a/b", true);
+
+        Tree frozenC = frozenB.getChild("c");
+        tp = pp.getTreePermission(frozenC, tp);
+        assertVersionPermission(tp, "/test/a/b/c", true);
+    }
+}
\ No newline at end of file

Propchange: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/VersionTreePermissionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to