Author: angela
Date: Thu Mar 15 17:37:45 2018
New Revision: 1826838
URL: http://svn.apache.org/viewvc?rev=1826838&view=rev
Log:
OAK-7341 : PermissionStoreEditor fails to reconnect collision entries if main
entry is removed
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java?rev=1826838&r1=1826837&r2=1826838&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java
Thu Mar 15 17:37:45 2018
@@ -137,12 +137,13 @@ final class PermissionStoreEditor implem
newParent = child;
} else {
newParent.setChildNode(childName,
child.getNodeState());
- child.remove();
}
}
- parent.remove();
if (newParent != null) {
+ // replace the 'parent', which needs to be removed
principalRoot.setChildNode(nodeName,
newParent.getNodeState());
+ } else {
+ parent.remove();
}
} else {
// check if any of the child nodes match
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java?rev=1826838&r1=1826837&r2=1826838&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java
Thu Mar 15 17:37:45 2018
@@ -22,12 +22,14 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.jcr.RepositoryException;
import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.AccessControlManager;
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;
@@ -38,6 +40,7 @@ import org.apache.jackrabbit.oak.api.Pro
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;
@@ -53,6 +56,8 @@ 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;
@@ -79,11 +84,8 @@ public class PermissionHookTest extends
NodeUtil testNode = rootNode.addChild("testPath",
JcrConstants.NT_UNSTRUCTURED);
testNode.addChild("childNode", JcrConstants.NT_UNSTRUCTURED);
- AccessControlManager acMgr = getAccessControlManager(root);
- JackrabbitAccessControlList acl =
AccessControlUtils.getAccessControlList(acMgr, testPath);
- acl.addAccessControlEntry(testPrincipal,
privilegesFromNames(JCR_ADD_CHILD_NODES));
- acl.addAccessControlEntry(EveryonePrincipal.getInstance(),
privilegesFromNames(JCR_READ));
- acMgr.setPolicy(testPath, acl);
+ addACE(testPath, testPrincipal, JCR_ADD_CHILD_NODES);
+ addACE(testPath, EveryonePrincipal.getInstance(), JCR_READ);
root.commit();
bitsProvider = new PrivilegeBitsProvider(root);
@@ -108,6 +110,13 @@ public class PermissionHookTest extends
}
}
+ private void addACE(@Nonnull String path, @Nonnull Principal principal,
@Nonnull 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(@Nonnull Principal principal) {
return
root.getTree(PERMISSIONS_STORE_PATH).getChild(adminSession.getWorkspaceName()).getChild(principal.getName());
}
@@ -407,4 +416,243 @@ public class PermissionHookTest extends
assertFalse(parent.getChild("0").exists());
}
}
+
+ @Test
+ public void testCollisions() throws Exception {
+ Tree testRoot = getPrincipalRoot(testPrincipal);
+
+ 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));
+
+ 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();
+ }
+ }
+ }
+
+ @Test
+ public void testCollisionRemoval() throws Exception {
+ Tree testRoot = getPrincipalRoot(testPrincipal);
+
+ 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));
+ }
+ }
+
+ @Test
+ public void testCollisionRemoval2() throws Exception {
+ Tree testRoot = getPrincipalRoot(testPrincipal);
+
+ 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));
+ }
+ }
+
+ @Test
+ public void testCollisionRemoval3() throws Exception {
+ Tree testRoot = getPrincipalRoot(testPrincipal);
+
+ 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));
+ }
+ }
+
+ @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));
+
+ 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));
+ }
+ }
+
+ @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();
+ }
+ }
+
+ @Nonnull
+ private static Set<String> getAccessControlledPaths(@Nonnull 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;
+ }
+
+ @CheckForNull
+ private static String getAccessControlledPath(@Nonnull Tree t) {
+ PropertyState pathProp = t.getProperty(REP_ACCESS_CONTROLLED_PATH);
+ return (pathProp == null) ? null : pathProp.getValue(Type.STRING);
+
+ }
}
\ No newline at end of file