| /* |
| * 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.security.Principal; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| import javax.jcr.RepositoryException; |
| import javax.jcr.security.AccessControlEntry; |
| import javax.jcr.security.AccessControlManager; |
| |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Sets; |
| import org.apache.jackrabbit.JcrConstants; |
| import org.apache.jackrabbit.api.security.JackrabbitAccessControlList; |
| import org.apache.jackrabbit.api.security.user.Group; |
| import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils; |
| import org.apache.jackrabbit.oak.AbstractSecurityTest; |
| import org.apache.jackrabbit.oak.api.ContentSession; |
| 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.plugins.tree.TreeUtil; |
| import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration; |
| import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants; |
| import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants; |
| 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.principal.EveryonePrincipal; |
| import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider; |
| import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants; |
| import org.apache.jackrabbit.oak.util.NodeUtil; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| /** |
| * Testing the {@code PermissionHook} |
| */ |
| public class PermissionHookTest extends AbstractSecurityTest implements AccessControlConstants, PermissionConstants, PrivilegeConstants { |
| |
| protected String testPath = "/testPath"; |
| protected String childPath = "/testPath/childNode"; |
| |
| protected Principal testPrincipal; |
| protected PrivilegeBitsProvider bitsProvider; |
| protected List<Principal> principals = new ArrayList<>(); |
| |
| @Override |
| @Before |
| public void before() throws Exception { |
| super.before(); |
| |
| testPrincipal = getTestUser().getPrincipal(); |
| NodeUtil rootNode = new NodeUtil(root.getTree("/"), namePathMapper); |
| NodeUtil testNode = rootNode.addChild("testPath", JcrConstants.NT_UNSTRUCTURED); |
| testNode.addChild("childNode", JcrConstants.NT_UNSTRUCTURED); |
| |
| addACE(testPath, testPrincipal, JCR_ADD_CHILD_NODES); |
| addACE(testPath, EveryonePrincipal.getInstance(), JCR_READ); |
| root.commit(); |
| |
| bitsProvider = new PrivilegeBitsProvider(root); |
| } |
| |
| @Override |
| @After |
| public void after() throws Exception { |
| try { |
| root.refresh(); |
| Tree test = root.getTree(testPath); |
| if (test.exists()) { |
| test.remove(); |
| } |
| |
| for (Principal principal : principals) { |
| getUserManager(root).getAuthorizable(principal).remove(); |
| } |
| root.commit(); |
| } finally { |
| super.after(); |
| } |
| } |
| |
| private void addACE(@NotNull String path, @NotNull Principal principal, @NotNull String... privilegeNames) throws RepositoryException { |
| AccessControlManager acMgr = getAccessControlManager(root); |
| JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, path); |
| acl.addAccessControlEntry(principal, privilegesFromNames(privilegeNames)); |
| acMgr.setPolicy(path, acl); |
| } |
| |
| protected Tree getPrincipalRoot(@NotNull Principal principal) { |
| return root.getTree(PERMISSIONS_STORE_PATH).getChild(adminSession.getWorkspaceName()).getChild(principal.getName()); |
| } |
| |
| protected Tree getEntry(@NotNull Principal principal, String accessControlledPath, long index) throws Exception { |
| Tree principalRoot = getPrincipalRoot(principal); |
| Tree parent = principalRoot.getChild(PermissionUtil.getEntryName(accessControlledPath)); |
| Tree entry = parent.getChild(String.valueOf(index)); |
| if (!entry.exists()) { |
| throw new RepositoryException("no such entry"); |
| } |
| return entry; |
| } |
| |
| protected long cntEntries(Tree parent) { |
| long cnt = parent.getChildrenCount(Long.MAX_VALUE); |
| for (Tree child : parent.getChildren()) { |
| cnt += cntEntries(child); |
| } |
| return cnt; |
| } |
| |
| protected void createPrincipals() throws Exception { |
| if (principals.isEmpty()) { |
| for (int i = 0; i < 10; i++) { |
| Group gr = getUserManager(root).createGroup("testGroup" + i); |
| principals.add(gr.getPrincipal()); |
| } |
| root.commit(); |
| } |
| } |
| |
| static protected void assertIndex(int expected, Tree entry) { |
| assertEquals(expected, Integer.parseInt(entry.getName())); |
| } |
| |
| @Test |
| public void testModifyRestrictions() throws Exception { |
| Tree testAce = root.getTree(testPath + "/rep:policy").getChildren().iterator().next(); |
| assertEquals(testPrincipal.getName(), testAce.getProperty(REP_PRINCIPAL_NAME).getValue(Type.STRING)); |
| |
| // add a new restriction node through the OAK API instead of access control manager |
| NodeUtil node = new NodeUtil(testAce); |
| NodeUtil restrictions = node.addChild(REP_RESTRICTIONS, NT_REP_RESTRICTIONS); |
| restrictions.setString(REP_GLOB, "*"); |
| String restrictionsPath = restrictions.getTree().getPath(); |
| root.commit(); |
| |
| Tree principalRoot = getPrincipalRoot(testPrincipal); |
| assertEquals(2, cntEntries(principalRoot)); |
| Tree parent = principalRoot.getChildren().iterator().next(); |
| assertEquals("*", parent.getChildren().iterator().next().getProperty(REP_GLOB).getValue(Type.STRING)); |
| |
| // modify the restrictions node |
| Tree restrictionsNode = root.getTree(restrictionsPath); |
| restrictionsNode.setProperty(REP_GLOB, "/*/jcr:content/*"); |
| root.commit(); |
| |
| principalRoot = getPrincipalRoot(testPrincipal); |
| assertEquals(2, cntEntries(principalRoot)); |
| parent = principalRoot.getChildren().iterator().next(); |
| assertEquals("/*/jcr:content/*", parent.getChildren().iterator().next().getProperty(REP_GLOB).getValue(Type.STRING)); |
| |
| // remove the restriction again |
| root.getTree(restrictionsPath).remove(); |
| root.commit(); |
| |
| principalRoot = getPrincipalRoot(testPrincipal); |
| assertEquals(2, cntEntries(principalRoot)); |
| parent = principalRoot.getChildren().iterator().next(); |
| assertNull(parent.getChildren().iterator().next().getProperty(REP_GLOB)); |
| } |
| |
| @Test |
| public void testReorderAce() throws Exception { |
| Tree entry = getEntry(testPrincipal, testPath, 0); |
| assertIndex(0, entry); |
| |
| Tree aclTree = root.getTree(testPath + "/rep:policy"); |
| aclTree.getChildren().iterator().next().orderBefore(null); |
| |
| root.commit(); |
| |
| entry = getEntry(testPrincipal, testPath, 1); |
| assertIndex(1, entry); |
| } |
| |
| @Test |
| public void testReorderAndAddAce() throws Exception { |
| Tree entry = getEntry(testPrincipal, testPath, 0); |
| assertIndex(0, entry); |
| |
| Tree aclTree = root.getTree(testPath + "/rep:policy"); |
| // reorder |
| aclTree.getChildren().iterator().next().orderBefore(null); |
| |
| // add a new entry |
| NodeUtil ace = new NodeUtil(aclTree).addChild("denyEveryoneLockMgt", NT_REP_DENY_ACE); |
| ace.setString(REP_PRINCIPAL_NAME, EveryonePrincipal.NAME); |
| ace.setNames(AccessControlConstants.REP_PRIVILEGES, JCR_LOCK_MANAGEMENT); |
| root.commit(); |
| |
| entry = getEntry(testPrincipal, testPath, 1); |
| assertIndex(1, entry); |
| } |
| |
| @Test |
| public void testReorderAddAndRemoveAces() throws Exception { |
| Tree entry = getEntry(testPrincipal, testPath, 0); |
| assertIndex(0, entry); |
| |
| Tree aclTree = root.getTree(testPath + "/rep:policy"); |
| |
| // reorder testPrincipal entry to the end |
| aclTree.getChildren().iterator().next().orderBefore(null); |
| |
| Iterator<Tree> aceIt = aclTree.getChildren().iterator(); |
| // remove the everyone entry |
| aceIt.next().remove(); |
| // remember the name of the testPrincipal entry. |
| String name = aceIt.next().getName(); |
| |
| // add a new entry |
| NodeUtil ace = new NodeUtil(aclTree).addChild("denyEveryoneLockMgt", NT_REP_DENY_ACE); |
| ace.setString(REP_PRINCIPAL_NAME, EveryonePrincipal.NAME); |
| ace.setNames(AccessControlConstants.REP_PRIVILEGES, JCR_LOCK_MANAGEMENT); |
| |
| // reorder the new entry before the remaining existing entry |
| ace.getTree().orderBefore(name); |
| |
| root.commit(); |
| |
| entry = getEntry(testPrincipal, testPath, 1); |
| assertIndex(1, entry); |
| } |
| |
| /** |
| * ACE : 0 1 2 3 4 5 6 7 |
| * Before : tp ev p0 p1 p2 p3 |
| * After : ev p2 p1 p3 p4 p5 |
| */ |
| @Test |
| public void testReorderAddAndRemoveAces2() throws Exception { |
| createPrincipals(); |
| |
| AccessControlManager acMgr = getAccessControlManager(root); |
| JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, testPath); |
| for (int i = 0; i < 4; i++) { |
| acl.addAccessControlEntry(principals.get(i), privilegesFromNames(JCR_READ)); |
| } |
| acMgr.setPolicy(testPath, acl); |
| root.commit(); |
| |
| AccessControlEntry[] aces = acl.getAccessControlEntries(); |
| acl.removeAccessControlEntry(aces[0]); |
| acl.removeAccessControlEntry(aces[2]); |
| acl.orderBefore(aces[4], aces[3]); |
| acl.addAccessControlEntry(principals.get(4), privilegesFromNames(JCR_READ)); |
| acl.addAccessControlEntry(principals.get(5), privilegesFromNames(JCR_READ)); |
| acMgr.setPolicy(testPath, acl); |
| root.commit(); |
| |
| Tree entry = getEntry(principals.get(2), testPath, 1); |
| assertIndex(1, entry); |
| |
| entry = getEntry(principals.get(1), testPath, 2); |
| assertIndex(2, entry); |
| } |
| |
| /** |
| * ACE : 0 1 2 3 4 5 6 7 |
| * Before : tp ev p0 p1 p2 p3 |
| * After : p1 ev p3 p2 |
| */ |
| @Test |
| public void testReorderAndRemoveAces() throws Exception { |
| createPrincipals(); |
| |
| AccessControlManager acMgr = getAccessControlManager(root); |
| JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, testPath); |
| for (int i = 0; i < 4; i++) { |
| acl.addAccessControlEntry(principals.get(i), privilegesFromNames(JCR_READ)); |
| } |
| acMgr.setPolicy(testPath, acl); |
| root.commit(); |
| |
| AccessControlEntry[] aces = acl.getAccessControlEntries(); |
| acl.removeAccessControlEntry(aces[0]); |
| acl.removeAccessControlEntry(aces[2]); |
| acl.orderBefore(aces[4], null); |
| acl.orderBefore(aces[3], aces[1]); |
| acMgr.setPolicy(testPath, acl); |
| root.commit(); |
| |
| Tree entry = getEntry(EveryonePrincipal.getInstance(), testPath, 1); |
| assertIndex(1, entry); |
| |
| entry = getEntry(principals.get(2), testPath, 3); |
| assertIndex(3, entry); |
| |
| for (Principal p : new Principal[]{testPrincipal, principals.get(0)}) { |
| try { |
| getEntry(p, testPath, 0); |
| fail(); |
| } catch (RepositoryException e) { |
| // success |
| } |
| } |
| } |
| |
| @Test |
| public void testImplicitAceRemoval() throws Exception { |
| AccessControlManager acMgr = getAccessControlManager(root); |
| JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, testPath); |
| acl.addAccessControlEntry(testPrincipal, privilegesFromNames(JCR_READ, REP_WRITE)); |
| acMgr.setPolicy(testPath, acl); |
| |
| acl = AccessControlUtils.getAccessControlList(acMgr, childPath); |
| acl.addAccessControlEntry(EveryonePrincipal.getInstance(), privilegesFromNames(JCR_READ)); |
| acMgr.setPolicy(childPath, acl); |
| root.commit(); |
| |
| assertTrue(root.getTree(childPath + "/rep:policy").exists()); |
| |
| Tree principalRoot = getPrincipalRoot(EveryonePrincipal.getInstance()); |
| assertEquals(4, cntEntries(principalRoot)); |
| |
| ContentSession testSession = createTestSession(); |
| Root testRoot = testSession.getLatestRoot(); |
| |
| assertTrue(testRoot.getTree(childPath).exists()); |
| assertFalse(testRoot.getTree(childPath + "/rep:policy").exists()); |
| |
| testRoot.getTree(childPath).remove(); |
| testRoot.commit(); |
| testSession.close(); |
| |
| root.refresh(); |
| assertFalse(root.getTree(testPath).hasChild("childNode")); |
| assertFalse(root.getTree(childPath + "/rep:policy").exists()); |
| // aces must be removed in the permission store even if the editing |
| // session wasn't able to access them. |
| principalRoot = getPrincipalRoot(EveryonePrincipal.getInstance()); |
| assertEquals(2, cntEntries(principalRoot)); |
| } |
| |
| /** |
| * @see <a href="https://issues.apache.org/jira/browse/OAK-2015">OAK-2015</a> |
| */ |
| @Test |
| public void testDynamicJcrAll() throws Exception { |
| AccessControlManager acMgr = getAccessControlManager(root); |
| |
| // grant 'everyone' jcr:all at the child path. |
| JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, childPath); |
| acl.addAccessControlEntry(EveryonePrincipal.getInstance(), privilegesFromNames(JCR_ALL)); |
| acMgr.setPolicy(childPath, acl); |
| root.commit(); |
| |
| // verify that the permission store contains an entry for everyone at childPath |
| // and the privilegeBits for jcr:all are reflect with a placeholder value. |
| Tree allEntry = getEntry(EveryonePrincipal.getInstance(), childPath, 0); |
| assertTrue(allEntry.exists()); |
| PropertyState ps = allEntry.getProperty(PermissionConstants.REP_PRIVILEGE_BITS); |
| assertEquals(1, ps.count()); |
| assertEquals(PermissionStore.DYNAMIC_ALL_BITS, ps.getValue(Type.LONG, 0).longValue()); |
| |
| // verify that the permission provider still exposes the correct privilege |
| // (jcr:all) for the given childPath irrespective of the dynamic nature of |
| // the privilege bits in the persisted permission entry. |
| Set<Principal> principalSet = ImmutableSet.<Principal>of(EveryonePrincipal.getInstance()); |
| PermissionProvider permissionProvider = getConfig(AuthorizationConfiguration.class).getPermissionProvider(root, root.getContentSession().getWorkspaceName(), principalSet); |
| Tree childTree = root.getTree(childPath); |
| assertTrue(permissionProvider.hasPrivileges(childTree, PrivilegeConstants.JCR_ALL)); |
| assertTrue(permissionProvider.getPrivileges(childTree).contains(PrivilegeConstants.JCR_ALL)); |
| |
| // also verify the permission evaluation |
| long diff = Permissions.diff(Permissions.ALL, Permissions.REMOVE_NODE|Permissions.ADD_NODE); |
| assertFalse(permissionProvider.isGranted(childTree, null, Permissions.REMOVE_NODE)); |
| assertFalse(permissionProvider.isGranted(childTree, null, Permissions.ADD_NODE)); |
| assertTrue(permissionProvider.isGranted(childTree, null, diff)); |
| |
| // remove the ACE again |
| acl = AccessControlUtils.getAccessControlList(acMgr, childPath); |
| for (AccessControlEntry ace : acl.getAccessControlEntries()) { |
| if (EveryonePrincipal.NAME.equals(ace.getPrincipal().getName())) { |
| acl.removeAccessControlEntry(ace); |
| } |
| } |
| acMgr.setPolicy(childPath, acl); |
| root.commit(); |
| |
| // verify that the corresponding permission entry has been removed. |
| Tree everyoneRoot = getPrincipalRoot(EveryonePrincipal.getInstance()); |
| Tree parent = everyoneRoot.getChild(PermissionUtil.getEntryName(childPath)); |
| if (parent.exists()) { |
| assertFalse(parent.getChild("0").exists()); |
| } |
| } |
| |
| @Test |
| public void testNumPermissionsProperty() throws Exception { |
| Tree everyoneRoot = getPrincipalRoot(EveryonePrincipal.getInstance()); |
| Tree testRoot = getPrincipalRoot(testPrincipal); |
| |
| // initial state after setup |
| assertNumPermissionsProperty(1, everyoneRoot); |
| assertNumPermissionsProperty(1, testRoot); |
| |
| // add another acl with an entry for everyone |
| addACE(childPath, EveryonePrincipal.getInstance(), JCR_READ); |
| root.commit(); |
| |
| assertNumPermissionsProperty(2, everyoneRoot); |
| assertNumPermissionsProperty(1, testRoot); |
| |
| // adding another ACE at an existing ACL must not change num-permissions |
| AccessControlManager acMgr = getAccessControlManager(root); |
| JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, childPath); |
| acl = AccessControlUtils.getAccessControlList(acMgr, childPath); |
| acl.addEntry(EveryonePrincipal.getInstance(), privilegesFromNames(JCR_READ), false, ImmutableMap.of(REP_GLOB, getValueFactory(root).createValue("/*/jcr:content"))); |
| acMgr.setPolicy(childPath, acl); |
| root.commit(); |
| |
| assertNumPermissionsProperty(2, everyoneRoot); |
| assertNumPermissionsProperty(1, testRoot); |
| |
| // remove policy at 'testPath' |
| acMgr.removePolicy(testPath, AccessControlUtils.getAccessControlList(acMgr, testPath)); |
| root.commit(); |
| |
| assertNumPermissionsProperty(1, everyoneRoot); |
| assertNumPermissionsProperty(0, testRoot); |
| |
| // remove all ACEs on the childPath policy -> same effect as policy removal on permission store |
| acl = AccessControlUtils.getAccessControlList(acMgr, childPath); |
| for (AccessControlEntry entry : acl.getAccessControlEntries()) { |
| acl.removeAccessControlEntry(entry); |
| } |
| acMgr.setPolicy(childPath, acl); |
| root.commit(); |
| |
| assertNumPermissionsProperty(0, everyoneRoot); |
| assertNumPermissionsProperty(0, testRoot); |
| } |
| |
| @Test |
| public void testCollisions() throws Exception { |
| Tree testRoot = getPrincipalRoot(testPrincipal); |
| assertNumPermissionsProperty(1, testRoot); |
| |
| String aaPath = testPath + "/Aa"; |
| String bbPath = testPath + "/BB"; |
| |
| if (aaPath.hashCode() == bbPath.hashCode()) { |
| try { |
| Tree parent = root.getTree(testPath); |
| Tree aa = TreeUtil.addChild(parent, "Aa", JcrConstants.NT_UNSTRUCTURED); |
| addACE(aa.getPath(), testPrincipal, JCR_READ); |
| |
| Tree bb = TreeUtil.addChild(parent, "BB", JcrConstants.NT_UNSTRUCTURED); |
| addACE(bb.getPath(), testPrincipal, JCR_READ); |
| root.commit(); |
| |
| assertEquals(2, testRoot.getChildrenCount(Long.MAX_VALUE)); |
| assertNumPermissionsProperty(3, testRoot); |
| |
| Set<String> accessControlledPaths = Sets.newHashSet(testPath, aa.getPath(), bb.getPath()); |
| assertEquals(accessControlledPaths, getAccessControlledPaths(testRoot)); |
| } finally { |
| root.getTree(aaPath).remove(); |
| root.getTree(bbPath).remove(); |
| root.commit(); |
| } |
| } else { |
| fail(); |
| } |
| |
| } |
| |
| @Test |
| public void testCollisionRemoval() throws Exception { |
| Tree testRoot = getPrincipalRoot(testPrincipal); |
| assertNumPermissionsProperty(1, testRoot); |
| |
| String aaPath = testPath + "/Aa"; |
| String bbPath = testPath + "/BB"; |
| |
| if (aaPath.hashCode() == bbPath.hashCode()) { |
| Tree parent = root.getTree(testPath); |
| Tree aa = TreeUtil.addChild(parent, "Aa", JcrConstants.NT_UNSTRUCTURED); |
| addACE(aa.getPath(), testPrincipal, JCR_READ); |
| |
| Tree bb = TreeUtil.addChild(parent, "BB", JcrConstants.NT_UNSTRUCTURED); |
| addACE(bb.getPath(), testPrincipal, JCR_READ); |
| root.commit(); |
| |
| root.getTree(aaPath).remove(); |
| root.commit(); |
| |
| assertEquals(2, testRoot.getChildrenCount(Long.MAX_VALUE)); |
| assertTrue(testRoot.hasChild(bbPath.hashCode() + "")); |
| |
| assertEquals(Sets.newHashSet(testPath, bb.getPath()), getAccessControlledPaths(testRoot)); |
| assertNumPermissionsProperty(2, testRoot); |
| } |
| } |
| |
| @Test |
| public void testCollisionRemoval2() throws Exception { |
| Tree testRoot = getPrincipalRoot(testPrincipal); |
| assertNumPermissionsProperty(1, testRoot); |
| |
| String aaPath = testPath + "/Aa"; |
| String bbPath = testPath + "/BB"; |
| |
| if (aaPath.hashCode() == bbPath.hashCode()) { |
| Tree parent = root.getTree(testPath); |
| Tree aa = TreeUtil.addChild(parent, "Aa", JcrConstants.NT_UNSTRUCTURED); |
| addACE(aa.getPath(), testPrincipal, JCR_READ); |
| |
| Tree bb = TreeUtil.addChild(parent, "BB", JcrConstants.NT_UNSTRUCTURED); |
| addACE(bb.getPath(), testPrincipal, JCR_READ); |
| root.commit(); |
| |
| root.getTree(bbPath).remove(); |
| root.commit(); |
| |
| assertEquals(2, testRoot.getChildrenCount(Long.MAX_VALUE)); |
| assertTrue(testRoot.hasChild(aaPath.hashCode() + "")); |
| |
| assertEquals(Sets.newHashSet(testPath, aa.getPath()), getAccessControlledPaths(testRoot)); |
| assertNumPermissionsProperty(2, testRoot); |
| } |
| } |
| |
| @Test |
| public void testCollisionRemoval3() throws Exception { |
| Tree testRoot = getPrincipalRoot(testPrincipal); |
| assertNumPermissionsProperty(1, testRoot); |
| |
| String aaPath = testPath + "/Aa"; |
| String bbPath = testPath + "/BB"; |
| |
| if (aaPath.hashCode() == bbPath.hashCode()) { |
| Tree parent = root.getTree(testPath); |
| Tree aa = TreeUtil.addChild(parent, "Aa", JcrConstants.NT_UNSTRUCTURED); |
| addACE(aa.getPath(), testPrincipal, JCR_READ); |
| |
| Tree bb = TreeUtil.addChild(parent, "BB", JcrConstants.NT_UNSTRUCTURED); |
| addACE(bb.getPath(), testPrincipal, JCR_READ); |
| root.commit(); |
| |
| root.getTree(aaPath).remove(); |
| root.getTree(bbPath).remove(); |
| root.commit(); |
| |
| assertEquals(1, testRoot.getChildrenCount(Long.MAX_VALUE)); |
| assertFalse(testRoot.hasChild(aaPath.hashCode() + "")); |
| assertFalse(testRoot.hasChild(bbPath.hashCode() + "")); |
| |
| assertEquals(Sets.newHashSet(testPath), getAccessControlledPaths(testRoot)); |
| assertNumPermissionsProperty(1, testRoot); |
| } |
| } |
| |
| @Test |
| public void testCollisionRemoval4() throws Exception { |
| Tree testRoot = getPrincipalRoot(testPrincipal); |
| |
| String aPath = testPath + "/AaAa"; |
| String bPath = testPath + "/BBBB"; |
| String cPath = testPath + "/AaBB"; |
| |
| if (aPath.hashCode() == bPath.hashCode() && bPath.hashCode() == cPath.hashCode()) { |
| String name = aPath.hashCode() + ""; |
| |
| Tree parent = root.getTree(testPath); |
| Tree aa = TreeUtil.addChild(parent, "AaAa", JcrConstants.NT_UNSTRUCTURED); |
| addACE(aa.getPath(), testPrincipal, JCR_READ); |
| |
| Tree bb = TreeUtil.addChild(parent, "BBBB", JcrConstants.NT_UNSTRUCTURED); |
| addACE(bb.getPath(), testPrincipal, JCR_READ); |
| |
| Tree cc = TreeUtil.addChild(parent, "AaBB", JcrConstants.NT_UNSTRUCTURED); |
| addACE(cc.getPath(), testPrincipal, JCR_READ); |
| root.commit(); |
| |
| Set<String> paths = Sets.newHashSet(aPath, bPath, cPath); |
| paths.add(testPath); |
| |
| assertEquals(2, testRoot.getChildrenCount(Long.MAX_VALUE)); |
| assertEquals(paths, getAccessControlledPaths(testRoot)); |
| assertNumPermissionsProperty(paths.size(), testRoot); |
| |
| String toRemove = null; |
| for (String path : paths) { |
| if (testRoot.hasChild(name) && path.equals(getAccessControlledPath(testRoot.getChild(name)))) { |
| toRemove = path; |
| break; |
| } |
| } |
| |
| assertNotNull(toRemove); |
| paths.remove(toRemove); |
| |
| root.getTree(toRemove).remove(); |
| root.commit(); |
| |
| assertEquals(2, testRoot.getChildrenCount(Long.MAX_VALUE)); |
| assertTrue(testRoot.hasChild(toRemove.hashCode() + "")); |
| assertNotEquals(toRemove, getAccessControlledPath(testRoot.getChild(name))); |
| |
| assertEquals(paths, getAccessControlledPaths(testRoot)); |
| assertNumPermissionsProperty(paths.size(), testRoot); |
| } |
| } |
| |
| @Test |
| public void testCollisionRemovalSubsequentAdd() throws Exception { |
| Tree testRoot = getPrincipalRoot(testPrincipal); |
| |
| String aPath = testPath + "/AaAa"; |
| String bPath = testPath + "/BBBB"; |
| String cPath = testPath + "/AaBB"; |
| String dPath = testPath + "/BBAa"; |
| |
| if (aPath.hashCode() == bPath.hashCode() && bPath.hashCode() == cPath.hashCode() && cPath.hashCode() == dPath.hashCode()) { |
| String name = aPath.hashCode() + ""; |
| |
| Tree parent = root.getTree(testPath); |
| Tree aa = TreeUtil.addChild(parent, "AaAa", JcrConstants.NT_UNSTRUCTURED); |
| addACE(aa.getPath(), testPrincipal, JCR_READ); |
| |
| Tree bb = TreeUtil.addChild(parent, "BBBB", JcrConstants.NT_UNSTRUCTURED); |
| addACE(bb.getPath(), testPrincipal, JCR_READ); |
| |
| Tree cc = TreeUtil.addChild(parent, "AaBB", JcrConstants.NT_UNSTRUCTURED); |
| addACE(cc.getPath(), testPrincipal, JCR_READ); |
| root.commit(); |
| |
| Set<String> paths = Sets.newHashSet(aPath, bPath, cPath); |
| paths.add(testPath); |
| |
| assertEquals(2, testRoot.getChildrenCount(Long.MAX_VALUE)); |
| assertEquals(paths, getAccessControlledPaths(testRoot)); |
| |
| String toRemove = null; |
| for (String path : paths) { |
| if (testRoot.hasChild(name) && path.equals(getAccessControlledPath(testRoot.getChild(name)))) { |
| toRemove = path; |
| break; |
| } |
| } |
| |
| paths.remove(toRemove); |
| root.getTree(toRemove).remove(); |
| root.commit(); |
| |
| Tree dd = TreeUtil.addChild(parent, "BBAa", JcrConstants.NT_UNSTRUCTURED); |
| addACE(dd.getPath(), testPrincipal, JCR_READ); |
| root.commit(); |
| |
| assertEquals(2, testRoot.getChildrenCount(Long.MAX_VALUE)); |
| paths.add(dPath); |
| assertEquals(paths, getAccessControlledPaths(testRoot)); |
| } else { |
| fail(); |
| } |
| } |
| |
| @NotNull |
| private static Set<String> getAccessControlledPaths(@NotNull Tree principalTree) { |
| Set<String> s = Sets.newHashSet(); |
| for (Tree tree : principalTree.getChildren()) { |
| String path = getAccessControlledPath(tree); |
| if (path != null) { |
| s.add(path); |
| } |
| for (Tree child : tree.getChildren()) { |
| if (child.getName().startsWith("c")) { |
| String childPath = getAccessControlledPath(child); |
| if (childPath != null) { |
| s.add(childPath); |
| } |
| } |
| } |
| } |
| return s; |
| } |
| |
| @Nullable |
| private static String getAccessControlledPath(@NotNull Tree t) { |
| PropertyState pathProp = t.getProperty(REP_ACCESS_CONTROLLED_PATH); |
| return (pathProp == null) ? null : pathProp.getValue(Type.STRING); |
| |
| } |
| |
| private static void assertNumPermissionsProperty(long expectedValue, @NotNull Tree parent) { |
| PropertyState p = parent.getProperty(REP_NUM_PERMISSIONS); |
| assertNotNull(p); |
| assertEquals(expectedValue, p.getValue(Type.LONG).longValue()); |
| } |
| } |