| /* |
| * 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.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.spi.nodetype.NodeTypeConstants; |
| 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.plugins.tree.TreeUtil; |
| import org.jetbrains.annotations.NotNull; |
| 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(@NotNull TreePermission tp, @NotNull 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)); |
| |
| Tree t = getRootProvider().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, getTreeProvider().asNodeState(t)); |
| } |
| |
| String expectedPath = "/test"; |
| assertVersionPermission(tp, "/test", true); |
| |
| NodeState ns = getTreeProvider().asNodeState(t.getChild("1.0")); |
| 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); |
| } |
| } |