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 2013/03/22 09:45:53 UTC
svn commit: r1459665 - in /jackrabbit/oak/trunk/oak-core/src:
main/java/org/apache/jackrabbit/oak/security/authorization/permission/
main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/
test/java/org/apache/jackrabbit/oak/security/authoriza...
Author: angela
Date: Fri Mar 22 08:45:53 2013
New Revision: 1459665
URL: http://svn.apache.org/r1459665
Log:
OAK-527: permissions (wip)
Added:
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/PermissionHook.java
jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java?rev=1459665&r1=1459664&r2=1459665&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java Fri Mar 22 08:45:53 2013
@@ -20,6 +20,7 @@ import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
+import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import org.apache.jackrabbit.JcrConstants;
@@ -82,7 +83,7 @@ public class PermissionHook implements P
ntMgr = ReadOnlyNodeTypeManager.getInstance(before);
bitsProvider = new PrivilegeBitsProvider(new ImmutableRoot(before, workspaceName));
- after.compareAgainstBaseState(before, new Diff(new BeforeNode(before), new Node(rootAfter)));
+ after.compareAgainstBaseState(before, new Diff(new BeforeNode(before), new AfterNode(rootAfter)));
return rootAfter.getNodeState();
}
@@ -102,11 +103,20 @@ public class PermissionHook implements P
return permissionRoot;
}
+ @CheckForNull
+ private NodeBuilder getPrincipalRoot(String principalName) {
+ if (permissionRoot.hasChildNode(principalName)) {
+ return permissionRoot.child(principalName);
+ } else {
+ return null;
+ }
+ }
+
private static Tree getTree(String name, NodeState nodeState) {
return new ImmutableTree(ImmutableTree.ParentProvider.UNSUPPORTED, name, nodeState, ImmutableTree.TypeProvider.EMPTY);
}
- private static String getAccessControlledPath(BaseNode aclNode) {
+ private static String getAccessControlledPath(Node aclNode) {
if (REP_REPO_POLICY.equals(aclNode.getName())) {
return "";
} else {
@@ -114,27 +124,21 @@ public class PermissionHook implements P
}
}
- private static int getAceIndex(BaseNode aclNode, String aceName) {
+ private static int getAceIndex(Node aclNode, String aceName) {
PropertyState ordering = checkNotNull(aclNode.getNodeState().getProperty(TreeImpl.OAK_CHILD_ORDER));
return Lists.newArrayList(ordering.getValue(Type.STRINGS)).indexOf(aceName);
}
- private static String generateName(NodeBuilder principalRoot, PermissionEntry entry) {
- StringBuilder name = new StringBuilder();
- name.append((entry.isAllow) ? PREFIX_ALLOW : PREFIX_DENY).append('-').append(principalRoot.getChildNodeCount());
- return name.toString();
- }
-
private Set<Restriction> getRestrictions(String accessControlledPath, Tree aceTree) {
return restrictionProvider.readRestrictions(Strings.emptyToNull(accessControlledPath), aceTree);
}
private class Diff implements NodeStateDiff {
- private final BeforeNode parentBefore;
- private final Node parentAfter;
+ private final Node parentBefore;
+ private final AfterNode parentAfter;
- private Diff(@Nonnull BeforeNode parentBefore, @Nonnull Node parentAfter) {
+ private Diff(@Nonnull Node parentBefore, @Nonnull AfterNode parentAfter) {
this.parentBefore = parentBefore;
this.parentAfter = parentAfter;
}
@@ -162,9 +166,11 @@ public class PermissionHook implements P
// ignore hidden nodes
} else if (isACE(name, after)) {
addEntry(name, after);
+ } else if (REP_RESTRICTIONS.equals(name)) {
+ updateEntry(parentAfter.getName(), parentBefore.getNodeState(), parentAfter.getNodeState());
} else {
- BeforeNode before = new BeforeNode(parentBefore.getPath(), name, EMPTY_NODE);
- Node node = new Node(parentAfter, name);
+ Node before = new BeforeNode(parentBefore.getPath(), name, EMPTY_NODE);
+ AfterNode node = new AfterNode(parentAfter, name);
after.compareAgainstBaseState(before.getNodeState(), new Diff(before, node));
}
}
@@ -179,7 +185,7 @@ public class PermissionHook implements P
updateEntry(parentAfter.getName(), parentBefore.getNodeState(), parentAfter.getNodeState());
} else {
BeforeNode nodeBefore = new BeforeNode(parentBefore.getPath(), name, before);
- Node nodeAfter = new Node(parentAfter, name);
+ AfterNode nodeAfter = new AfterNode(parentAfter, name);
after.compareAgainstBaseState(before, new Diff(nodeBefore, nodeAfter));
}
}
@@ -190,9 +196,11 @@ public class PermissionHook implements P
// ignore hidden nodes
} else if (isACE(name, before)) {
removeEntry(name, before);
+ } else if (REP_RESTRICTIONS.equals(name)) {
+ updateEntry(parentAfter.getName(), parentBefore.getNodeState(), parentAfter.getNodeState());
} else {
BeforeNode nodeBefore = new BeforeNode(parentBefore.getPath(), name, before);
- Node after = new Node(parentAfter.getPath(), name, EMPTY_NODE);
+ AfterNode after = new AfterNode(parentAfter.getPath(), name, EMPTY_NODE);
after.getNodeState().compareAgainstBaseState(before, new Diff(nodeBefore, after));
}
}
@@ -208,16 +216,14 @@ public class PermissionHook implements P
private void addEntry(String name, NodeState ace) {
PermissionEntry entry = createPermissionEntry(name, ace, parentAfter);
- if (getExistingPermissionNodeName(entry) == null) {
- entry.writeTo(permissionRoot);
- }
+ entry.writeTo(permissionRoot);
}
private void removeEntry(String name, NodeState ace) {
PermissionEntry entry = createPermissionEntry(name, ace, parentBefore);
- String permissionName = getExistingPermissionNodeName(entry);
- if (permissionName != null) {
- permissionRoot.child(entry.principalName).removeNode(permissionName);
+ NodeBuilder principalRoot = getPrincipalRoot(entry.principalName);
+ if (principalRoot != null) {
+ principalRoot.removeNode(entry.nodeName);
}
}
@@ -226,28 +232,8 @@ public class PermissionHook implements P
addEntry(name, after);
}
- @CheckForNull
- private String getExistingPermissionNodeName(PermissionEntry permissionEntry) {
- if (permissionRoot.hasChildNode(permissionEntry.principalName)) {
- NodeBuilder principalRoot = permissionRoot.child(permissionEntry.principalName);
- for (String childName : principalRoot.getChildNodeNames()) {
- NodeState state = principalRoot.child(childName).getNodeState();
- if (permissionEntry.isSame(childName, state)) {
- log.debug("Found existing permission entry for " + permissionEntry);
- return childName;
- }
- }
- log.warn("No permission entry for " + permissionEntry);
- } else {
- // inconsistency: removing an ACE that doesn't have a corresponding
- // entry in the permission store.
- log.warn("Missing permission node for principal " + permissionEntry.principalName);
- }
- return null;
- }
-
@Nonnull
- private PermissionEntry createPermissionEntry(String name, NodeState ace, BaseNode acl) {
+ private PermissionEntry createPermissionEntry(String name, NodeState ace, Node acl) {
Tree aceTree = getTree(name, ace);
String accessControlledPath = getAccessControlledPath(acl);
String principalName = checkNotNull(TreeUtil.getString(aceTree, REP_PRINCIPAL_NAME));
@@ -259,15 +245,15 @@ public class PermissionHook implements P
}
}
- private static abstract class BaseNode {
+ private static abstract class Node {
private final String path;
- private BaseNode(String path) {
+ private Node(String path) {
this.path = path;
}
- private BaseNode(String parentPath, String name) {
+ private Node(String parentPath, String name) {
this.path = PathUtils.concat(parentPath, new String[]{name});
}
@@ -282,7 +268,7 @@ public class PermissionHook implements P
abstract NodeState getNodeState();
}
- private static final class BeforeNode extends BaseNode {
+ private static final class BeforeNode extends Node {
private final NodeState nodeState;
@@ -303,21 +289,21 @@ public class PermissionHook implements P
}
}
- private static final class Node extends BaseNode {
+ private static final class AfterNode extends Node {
private final NodeBuilder builder;
- private Node(NodeBuilder rootBuilder) {
+ private AfterNode(NodeBuilder rootBuilder) {
super("/");
this.builder = rootBuilder;
}
- private Node(String parentPath, String name, NodeState state) {
+ private AfterNode(String parentPath, String name, NodeState state) {
super(parentPath, name);
this.builder = state.builder();
}
- private Node(Node parent, String name) {
+ private AfterNode(AfterNode parent, String name) {
super(parent.getPath(), name);
this.builder = parent.builder.child(name);
}
@@ -331,12 +317,13 @@ public class PermissionHook implements P
private final String accessControlledPath;
private final int index;
-
private final String principalName;
private final PrivilegeBits privilegeBits;
private final boolean isAllow;
private final Set<Restriction> restrictions;
+ private final String nodeName;
+
private PermissionEntry(@Nonnull String accessControlledPath,
int index,
@Nonnull String principalName,
@@ -349,6 +336,12 @@ public class PermissionHook implements P
this.privilegeBits = privilegeBits;
this.isAllow = isAllow;
this.restrictions = restrictions;
+
+ // create node name from ace definition (excluding the index)
+ StringBuilder name = new StringBuilder();
+ name.append((isAllow) ? PREFIX_ALLOW : PREFIX_DENY).append('-');
+ name.append(Objects.hashCode(accessControlledPath, principalName, privilegeBits, isAllow, restrictions));
+ nodeName = name.toString();
}
private void writeTo(NodeBuilder permissionRoot) {
@@ -356,8 +349,7 @@ public class PermissionHook implements P
if (principalRoot.getProperty(JCR_PRIMARYTYPE) == null) {
principalRoot.setProperty(JCR_PRIMARYTYPE, NT_REP_PERMISSION_STORE, Type.NAME);
}
- String entryName = generateName(principalRoot, this);
- NodeBuilder entry = principalRoot.child(entryName)
+ NodeBuilder entry = principalRoot.child(nodeName)
.setProperty(JCR_PRIMARYTYPE, NT_REP_PERMISSIONS, Type.NAME)
.setProperty(REP_ACCESS_CONTROLLED_PATH, accessControlledPath)
.setProperty(REP_INDEX, index)
@@ -367,27 +359,10 @@ public class PermissionHook implements P
}
}
- private boolean isSame(String name, NodeState node) {
- Tree entry = getTree(name, node);
-
- if (isAllow != (name.charAt(0) == PREFIX_ALLOW)) {
- return false;
- }
- if (!privilegeBits.equals(PrivilegeBits.getInstance(node.getProperty(REP_PRIVILEGES)))) {
- return false;
- }
- if (index != entry.getProperty(REP_INDEX).getValue(Type.LONG)) {
- return false;
- }
- if (!accessControlledPath.equals(TreeUtil.getString(entry, REP_ACCESS_CONTROLLED_PATH))) {
- return false;
- }
- return restrictions.equals(getRestrictions(accessControlledPath, entry));
- }
-
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("permission entry: ").append(accessControlledPath);
+ sb.append(';').append(index);
sb.append(';').append(principalName);
sb.append(';').append(isAllow ? "allow" : "deny");
sb.append(';').append(privilegeBits);
Modified: jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd?rev=1459665&r1=1459664&r2=1459665&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd Fri Mar 22 08:45:53 2013
@@ -637,10 +637,8 @@
* @since oak 1.0
*/
[rep:Permissions]
- - rep:accessControlledPath (PATH) protected mandatory
- - rep:privileges (LONG) protected multiple mandatory
- - rep:index (LONG) protected mandatory
- * (UNDEFINED) protected
+ - * (UNDEFINED) protected multiple
// -----------------------------------------------------------------------------
// Principal based AC
Added: 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=1459665&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java Fri Mar 22 08:45:53 2013
@@ -0,0 +1,121 @@
+/*
+ * 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 javax.jcr.RepositoryException;
+import javax.jcr.security.AccessControlManager;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.oak.security.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.oak.spi.security.authorization.AbstractAccessControlTest;
+import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * PermissionHookTest... TODO
+ */
+public class PermissionHookTest extends AbstractAccessControlTest implements PermissionConstants {
+
+ private AccessControlManager acMgr;
+ @Override
+ @Before
+ public void before() throws Exception {
+ super.before();
+
+ NodeUtil rootNode = new NodeUtil(root.getTree("/"), namePathMapper);
+ rootNode.addChild("testName", JcrConstants.NT_UNSTRUCTURED);
+ root.commit();
+
+ acMgr = getAccessControlManager(root);
+ }
+
+ @After
+ public void after() throws Exception {
+ root.refresh();
+ root.getTree("/testName").remove();
+ root.commit();
+ }
+
+ private Tree getEntry(String principalName, String accessControlledPath) throws Exception {
+ Tree permissionTree = root.getTree(PERMISSIONS_STORE_PATH).getChild(adminSession.getWorkspaceName()).getChild(principalName);
+ for (Tree entry : permissionTree.getChildren()) {
+ if (accessControlledPath.equals(entry.getProperty(REP_ACCESS_CONTROLLED_PATH).getValue(Type.STRING))) {
+ return entry;
+ }
+ }
+ throw new RepositoryException("no such entry");
+ }
+
+ @Test
+ public void testAddDuplicateAce() {
+ // TODO
+ }
+
+ @Test
+ public void testRemoveDuplicateAce() {
+ // TODO
+ }
+
+ @Test
+ public void testAddRestrictionNode() {
+ // TODO add restriction node on oak-api
+ }
+
+ @Test
+ public void testRemoveRestrictionNode() {
+ // TODO
+ }
+
+ @Test
+ public void testModifyRestrictions() {
+ // TODO
+ }
+
+ @Ignore("PermissionHook#propertyChanged without corresponding child node modifications")
+ @Test
+ public void testReorderAce() throws Exception {
+ Principal testPrincipal = new PrincipalImpl("admin");
+ JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, "/testName");
+ acl.addAccessControlEntry(testPrincipal, privilegesFromNames(PrivilegeConstants.JCR_ADD_CHILD_NODES));
+ acl.addAccessControlEntry(EveryonePrincipal.getInstance(), privilegesFromNames(PrivilegeConstants.JCR_READ));
+ acMgr.setPolicy("/testName", acl);
+ root.commit();
+
+ Tree entry = getEntry("admin", "/testName");
+ assertEquals(0, entry.getProperty(REP_INDEX).getValue(Type.LONG).longValue());
+
+ Tree aclTree = root.getTree("/testName/rep:policy");
+ aclTree.getChildren().iterator().next().orderBefore(null);
+
+ root.commit();
+
+ entry = getEntry("admin", "/testName");
+ assertEquals(1, entry.getProperty(REP_INDEX).getValue(Type.LONG).longValue());
+ }
+}
\ No newline at end of file