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/02/18 12:19:01 UTC
svn commit: r1447202 - in
/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization:
PermissionHook.java PermissionProviderImpl.java
permission/CompiledPermissionImpl.java
Author: angela
Date: Mon Feb 18 11:19:00 2013
New Revision: 1447202
URL: http://svn.apache.org/r1447202
Log:
OAK-527: permissions (wip)
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/PermissionHook.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/PermissionProviderImpl.java
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/PermissionHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/PermissionHook.java?rev=1447202&r1=1447201&r2=1447202&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/PermissionHook.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/PermissionHook.java Mon Feb 18 11:19:00 2013
@@ -16,27 +16,39 @@
*/
package org.apache.jackrabbit.oak.security.authorization;
+import java.util.Collections;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.jcr.RepositoryException;
+import com.google.common.collect.Lists;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
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.core.ReadOnlyRoot;
import org.apache.jackrabbit.oak.core.ReadOnlyTree;
import org.apache.jackrabbit.oak.core.TreeImpl;
import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeState;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryPropertyBuilder;
import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
+import org.apache.jackrabbit.oak.security.privilege.PrivilegeBits;
+import org.apache.jackrabbit.oak.security.privilege.PrivilegeDefinitionStore;
import org.apache.jackrabbit.oak.spi.commit.CommitHook;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
+import org.apache.jackrabbit.oak.spi.state.PropertyBuilder;
+import org.apache.jackrabbit.oak.util.TreeUtil;
import org.apache.jackrabbit.util.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static com.google.common.base.Preconditions.checkNotNull;
+
/**
* {@code CommitHook} implementation that processes any modification made to
* access control content and updates persisted permission caches associated
@@ -55,15 +67,17 @@ public class PermissionHook implements C
@Nonnull
@Override
public NodeState processCommit(final NodeState before, NodeState after) throws CommitFailedException {
- NodeBuilder rootBuilder = after.builder();
+ NodeBuilder rootAfter = after.builder();
- NodeBuilder permissionRoot = getPermissionRoot(rootBuilder, workspaceName);
+ NodeBuilder permissionRoot = getPermissionRoot(rootAfter, workspaceName);
ReadOnlyNodeTypeManager ntMgr = ReadOnlyNodeTypeManager.getInstance(before);
+ PrivilegeDefinitionStore privilegeStore = new PrivilegeDefinitionStore(new ReadOnlyRoot(before));
- after.compareAgainstBaseState(before, new Diff(new Node(rootBuilder), permissionRoot, ntMgr));
- return rootBuilder.getNodeState();
+ after.compareAgainstBaseState(before, new Diff(new BeforeNode(before), new Node(rootAfter), permissionRoot, privilegeStore, ntMgr));
+ return rootAfter.getNodeState();
}
+ @Nonnull
private NodeBuilder getPermissionRoot(NodeBuilder rootBuilder, String workspaceName) {
NodeBuilder store = rootBuilder.child(NodeTypeConstants.JCR_SYSTEM).child(REP_PERMISSION_STORE);
NodeBuilder permissionRoot;
@@ -76,16 +90,39 @@ public class PermissionHook implements C
return permissionRoot;
}
+ private static Tree getTree(String name, NodeState nodeState) {
+ // FIXME: this readonlytree is not properly connect to it's parent
+ return new ReadOnlyTree(null, name, nodeState);
+ }
+
+ private static int getAceIndex(BaseNode 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, Entry entry) {
+ StringBuilder name = new StringBuilder();
+ name.append((entry.isAllow) ? 'a' : 'd').append('-').append(principalRoot.getChildNodeCount());
+ return name.toString();
+ }
+
private static class Diff implements NodeStateDiff {
- private final ReadOnlyNodeTypeManager ntMgr;
- private final NodeBuilder permissionRoot;
+ private final BeforeNode parentBefore;
private final Node parentAfter;
+ private final NodeBuilder permissionRoot;
+ private final PrivilegeDefinitionStore privilegeStore;
+ private final ReadOnlyNodeTypeManager ntMgr;
- private Diff(@Nonnull Node node, NodeBuilder permissionRoot, ReadOnlyNodeTypeManager ntMgr) {
- this.ntMgr = ntMgr;
+ private Diff(@Nonnull BeforeNode parentBefore, @Nonnull Node parentAfter,
+ @Nonnull NodeBuilder permissionRoot,
+ @Nonnull PrivilegeDefinitionStore privilegeStore,
+ @Nonnull ReadOnlyNodeTypeManager ntMgr) {
+ this.parentBefore = parentBefore;
+ this.parentAfter = parentAfter;
this.permissionRoot = permissionRoot;
- this.parentAfter = node;
+ this.privilegeStore = privilegeStore;
+ this.ntMgr = ntMgr;
}
@Override
@@ -96,7 +133,7 @@ public class PermissionHook implements C
@Override
public void propertyChanged(PropertyState before, PropertyState after) {
if (isACL(parentAfter) && TreeImpl.OAK_CHILD_ORDER.equals(before.getName())) {
- updateEntries();
+ // TODO: update if order has changed without child-node modifications
}
}
@@ -110,19 +147,22 @@ public class PermissionHook implements C
if (isACE(name, after)) {
addEntry(name, after);
} else {
- NodeState before = MemoryNodeState.EMPTY_NODE;
+ BeforeNode before = new BeforeNode(parentBefore.getPath(), name, MemoryNodeState.EMPTY_NODE);
Node node = new Node(parentAfter, name);
- after.compareAgainstBaseState(before, new Diff(node, permissionRoot, ntMgr));
+ after.compareAgainstBaseState(before.getNodeState(), new Diff(before, node, permissionRoot, privilegeStore, ntMgr));
}
}
@Override
- public void childNodeChanged(String name, NodeState before, NodeState after) {
+ public void childNodeChanged(String name, final NodeState before, NodeState after) {
if (isACE(name, before) || isACE(name, after)) {
updateEntry(name, before, after);
+ } else if (REP_RESTRICTIONS.equals(name)) {
+ updateEntry(parentAfter.getName(), parentBefore.getNodeState(), parentAfter.getNodeState());
} else {
- Node node = new Node(parentAfter, name);
- after.compareAgainstBaseState(before, new Diff(node, permissionRoot, ntMgr));
+ BeforeNode nodeBefore = new BeforeNode(parentBefore.getPath(), name, before);
+ Node nodeAfter = new Node(parentAfter, name);
+ after.compareAgainstBaseState(before, new Diff(nodeBefore, nodeAfter, permissionRoot, privilegeStore, ntMgr));
}
}
@@ -131,8 +171,9 @@ public class PermissionHook implements C
if (isACE(name, before)) {
removeEntry(name, before);
} else {
- Node after = new Node(parentAfter.path, name);
- after.builder.getNodeState().compareAgainstBaseState(before, new Diff(after, permissionRoot, ntMgr));
+ BeforeNode nodeBefore = new BeforeNode(parentBefore.getPath(), name, before);
+ Node after = new Node(parentAfter.getPath(), name, MemoryNodeState.EMPTY_NODE);
+ after.getNodeState().compareAgainstBaseState(before, new Diff(nodeBefore, after, permissionRoot, privilegeStore, ntMgr));
}
}
@@ -153,67 +194,206 @@ public class PermissionHook implements C
}
}
- private static String getAccessControlledPath(Node aclNode) {
- return Text.getRelativeParent(aclNode.path, 1);
+ private static String getAccessControlledPath(BaseNode aclNode) {
+ if (REP_REPO_POLICY.equals(aclNode.getName())) {
+ return "";
+ } else {
+ return Text.getRelativeParent(aclNode.getPath(), 1);
+ }
}
- private static Tree getTree(String name, NodeState nodeState) {
- // FIXME: this readonlytree is not properly connect to it's parent
- return new ReadOnlyTree(null, name, nodeState);
+ private void addEntry(String name, NodeState ace) {
+ Entry entry = createEntry(name, ace, parentAfter);
+ entry.writeTo(permissionRoot.child(entry.principalName));
}
- private void addEntry(String name, NodeState after) {
- String accessControlledPath = getAccessControlledPath(parentAfter);
- // TODO
- //log.info("add entry:" + name);
+ private void removeEntry(String name, NodeState ace) {
+ Entry entry = createEntry(name, ace, parentBefore);
+ String permissionName = getPermissionNodeName(entry);
+ if (permissionName != null) {
+ permissionRoot.child(entry.principalName).removeNode(permissionName);
+ }
}
- private void removeEntry(String name, NodeState after) {
- String accessControlledPath = getAccessControlledPath(parentAfter);
- // TODO
- //log.info("remove entry" + name);
+ private void updateEntry(String name, NodeState before, NodeState after) {
+ removeEntry(name, before);
+ addEntry(name, after);
+ }
+
+ @CheckForNull
+ private String getPermissionNodeName(Entry aceEntry) {
+ if (permissionRoot.hasChildNode(aceEntry.principalName)) {
+ NodeBuilder principalRoot = permissionRoot.child(aceEntry.principalName);
+ for (String childName : principalRoot.getChildNodeNames()) {
+ NodeState state = principalRoot.child(childName).getNodeState();
+ if (aceEntry.isSame(childName, state)) {
+ return childName;
+ }
+ }
+ log.warn("No entry node for " + aceEntry);
+ } else {
+ // inconsistency: removing an ACE that doesn't have a corresponding
+ // entry in the permission store.
+ log.warn("Missing permission node for principal " + aceEntry.principalName);
+ }
+ return null;
}
- private void updateEntry(String name, NodeState after, NodeState before) {
- String accessControlledPath = getAccessControlledPath(parentAfter);
- // TODO
- //log.info("update"+ name);
- }
+ @Nonnull
+ private Entry createEntry(String name, NodeState ace, BaseNode acl) {
+ Tree aceTree = getTree(name, ace);
+ String principalName = checkNotNull(TreeUtil.getString(aceTree, REP_PRINCIPAL_NAME));
+ PrivilegeBits privilegeBits = privilegeStore.getBits(TreeUtil.getString(aceTree, REP_PRIVILEGES));
+ boolean isAllow = NT_REP_GRANT_ACE.equals(TreeUtil.getPrimaryTypeName(aceTree));
+ // TODO: respect restrictions
- private void updateEntries() {
- String accessControlledPath = getAccessControlledPath(parentAfter);
- NodeState aclState = parentAfter.getNodeState();
+ String accessControlledPath = getAccessControlledPath(acl);
+ int index = getAceIndex(acl, name);
- // TODO
+ return new Entry(accessControlledPath, index, principalName, privilegeBits, isAllow);
}
}
- private static final class Node {
+ private static abstract class BaseNode {
private final String path;
+
+ private BaseNode(String path) {
+ this.path = path;
+ }
+
+ private BaseNode(String parentPath, String name) {
+ this.path = PathUtils.concat(parentPath, new String[]{name});
+ }
+
+ String getName() {
+ return Text.getName(path);
+ }
+
+ String getPath() {
+ return path;
+ }
+
+ abstract NodeState getNodeState();
+ }
+
+ private static class BeforeNode extends BaseNode {
+
+ private final NodeState nodeState;
+
+ BeforeNode(NodeState root) {
+ super("/");
+ this.nodeState = root;
+ }
+
+
+ BeforeNode(String parentPath, String name, NodeState nodeState) {
+ super(parentPath, name);
+ this.nodeState = nodeState;
+ }
+
+ @Override
+ NodeState getNodeState() {
+ return nodeState;
+ }
+ }
+
+ private static class Node extends BaseNode {
+
private final NodeBuilder builder;
private Node(NodeBuilder rootBuilder) {
- this.path = "/";
+ super("/");
this.builder = rootBuilder;
}
- private Node(String parentPath, String name) {
- this.path = PathUtils.concat(parentPath, name);
- this.builder = MemoryNodeState.EMPTY_NODE.builder();
+ private Node(String parentPath, String name, NodeState state) {
+ super(parentPath, name);
+ this.builder = state.builder();
}
private Node(Node parent, String name) {
+ super(parent.getPath(), name);
this.builder = parent.builder.child(name);
- this.path = PathUtils.concat(parent.path, name);
}
- private String getName() {
- return Text.getName(path);
+ NodeState getNodeState() {
+ return builder.getNodeState();
}
+ }
- private NodeState getNodeState() {
- return builder.getNodeState();
+ private static final class Entry {
+
+ private final String accessControlledPath;
+ private final int index;
+
+ private final String principalName;
+ private final PrivilegeBits privilegeBits;
+ private final boolean isAllow;
+
+ private Entry(@Nonnull String accessControlledPath,
+ int index,
+ @Nonnull String principalName,
+ @Nonnull PrivilegeBits privilegeBits,
+ boolean isAllow) {
+ this.accessControlledPath = accessControlledPath;
+ this.index = index;
+
+ this.principalName = principalName;
+ this.privilegeBits = privilegeBits;
+ this.isAllow = isAllow;
+ }
+
+ private void writeTo(NodeBuilder principalRoot) {
+ String entryName = generateName(principalRoot, this);
+ principalRoot.child(entryName)
+ .setProperty("rep:accessControlledPath", accessControlledPath)
+ .setProperty("rep:index", index)
+ .setProperty(privilegeBits.asPropertyState("rep:privileges"));
+ // TODO: append restrictions
+
+ PropertyState ordering = principalRoot.getProperty(TreeImpl.OAK_CHILD_ORDER);
+ if (ordering == null) {
+ principalRoot.setProperty(TreeImpl.OAK_CHILD_ORDER, Collections.singleton(entryName), Type.NAMES);
+ } else {
+ PropertyBuilder pb = MemoryPropertyBuilder.copy(Type.NAME, ordering);
+ // TODO: determine ordering index
+ int index = 0;
+ pb.setValue(entryName, index);
+ principalRoot.setProperty(pb.getPropertyState());
+ }
+ }
+
+ private boolean isSame(String name, NodeState node) {
+ Tree entry = getTree(name, node);
+
+ if (isAllow == (name.charAt(0) == 'a')) {
+ return false;
+ }
+ if (!privilegeBits.equals(PrivilegeBits.getInstance(node.getProperty(REP_PRIVILEGES)))) {
+ return false;
+ }
+ if (!principalName.equals(TreeUtil.getString(entry, REP_PRINCIPAL_NAME))) {
+ return false;
+ }
+ if (index != entry.getProperty("rep:index").getValue(Type.LONG)) {
+ return false;
+ }
+ if (!accessControlledPath.equals(TreeUtil.getString(entry, "rep:accessControlledPath"))) {
+ return false;
+ }
+ // TODO: respect restrictions
+
+ return true;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("entry: ").append(accessControlledPath);
+ sb.append(';').append(principalName);
+ sb.append(';').append(isAllow ? "allow" : "deny");
+ sb.append(';').append(privilegeBits);
+ return sb.toString();
}
}
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/PermissionProviderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/PermissionProviderImpl.java?rev=1447202&r1=1447201&r2=1447202&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/PermissionProviderImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/PermissionProviderImpl.java Mon Feb 18 11:19:00 2013
@@ -100,8 +100,8 @@ public class PermissionProviderImpl impl
@Override
public boolean canRead(@Nonnull Tree tree) {
- if (acContext.definesTree(tree)) {
- return compiledPermissions.isGranted(tree, Permissions.READ_ACCESS_CONTROL);
+ if (isAccessControlContent(tree)) {
+ return canReadAccessControlContent(tree, null);
} else if (isVersionContent(tree)) {
return canReadVersionContent(tree, null);
} else {
@@ -111,8 +111,8 @@ public class PermissionProviderImpl impl
@Override
public boolean canRead(@Nonnull Tree tree, @Nonnull PropertyState property) {
- if (acContext.definesTree(tree)) {
- return compiledPermissions.isGranted(tree, property, Permissions.READ_ACCESS_CONTROL);
+ if (isAccessControlContent(tree)) {
+ return canReadAccessControlContent(tree, property);
} else if (isVersionContent(tree)) {
return canReadVersionContent(tree, property);
} else {
@@ -174,6 +174,35 @@ public class PermissionProviderImpl impl
return (tree == null) ? null : (ReadOnlyTree) tree;
}
+ private boolean isAccessControlContent(@Nonnull Tree tree) {
+ return acContext.definesTree(tree);
+ }
+
+ private boolean canReadAccessControlContent(@Nonnull Tree acTree, @Nullable PropertyState acProperty) {
+ if (acProperty != null) {
+ return compiledPermissions.isGranted(acTree, acProperty, Permissions.READ_ACCESS_CONTROL);
+ } else {
+ return compiledPermissions.isGranted(acTree, Permissions.READ_ACCESS_CONTROL);
+ }
+ }
+
+ private static boolean isVersionContent(@Nonnull Tree tree) {
+ if (tree.isRoot()) {
+ return false;
+ }
+ if (VersionConstants.VERSION_NODE_NAMES.contains(tree.getName())) {
+ return true;
+ } else if (VersionConstants.VERSION_NODE_TYPE_NAMES.contains(TreeUtil.getPrimaryTypeName(tree))) {
+ return true;
+ } else {
+ return isVersionContent(tree.getPath());
+ }
+ }
+
+ private static boolean isVersionContent(@Nonnull String path) {
+ return VersionConstants.SYSTEM_PATHS.contains(Text.getAbsoluteParent(path, 1));
+ }
+
private boolean canReadVersionContent(@Nonnull Tree versionStoreTree, @Nullable PropertyState property) {
String versionablePath = getVersionablePath(versionStoreTree, property);
if (versionablePath != null) {
@@ -211,21 +240,4 @@ public class PermissionProviderImpl impl
}
return Strings.emptyToNull(versionablePath);
}
-
- private static boolean isVersionContent(@Nonnull Tree tree) {
- if (tree.isRoot()) {
- return false;
- }
- if (VersionConstants.VERSION_NODE_NAMES.contains(tree.getName())) {
- return true;
- } else if (VersionConstants.VERSION_NODE_TYPE_NAMES.contains(TreeUtil.getPrimaryTypeName(tree))) {
- return true;
- } else {
- return isVersionContent(tree.getPath());
- }
- }
-
- private static boolean isVersionContent(@Nonnull String path) {
- return VersionConstants.SYSTEM_PATHS.contains(Text.getAbsoluteParent(path, 1));
- }
}
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=1447202&r1=1447201&r2=1447202&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 Mon Feb 18 11:19:00 2013
@@ -77,20 +77,18 @@ public class CompiledPermissionImpl impl
@Override
public boolean isGranted(long permissions) {
- // TODO
+ // TODO: only evaluate entries that are defined for the "" path.
return false;
}
@Override
public boolean isGranted(Tree tree, long permissions) {
- // TODO
- return false;
+ return hasPermissions(tree, null, permissions);
}
@Override
public boolean isGranted(Tree parent, PropertyState property, long permissions) {
- // TODO
- return false;
+ return hasPermissions(parent, property, permissions);
}
@Override
@@ -110,9 +108,16 @@ public class CompiledPermissionImpl impl
}
//------------------------------------------------------------< private >---
+ private boolean hasPermissions(@Nonnull Tree tree, @Nullable PropertyState property,
+ long permissions) {
+ // TODO
+ return false;
+ }
+
private PrivilegeBits getPrivilegeBits(@Nullable Tree tree) {
- return PrivilegeBits.EMPTY; // TODO
+ // TODO
+ return PrivilegeBits.EMPTY;
}
private static final class Key implements Comparable<Key> {