Return-Path: X-Original-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Delivered-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 30204F51D for ; Wed, 17 Apr 2013 10:04:52 +0000 (UTC) Received: (qmail 64382 invoked by uid 500); 17 Apr 2013 10:04:52 -0000 Delivered-To: apmail-jackrabbit-oak-commits-archive@jackrabbit.apache.org Received: (qmail 64259 invoked by uid 500); 17 Apr 2013 10:04:48 -0000 Mailing-List: contact oak-commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: oak-dev@jackrabbit.apache.org Delivered-To: mailing list oak-commits@jackrabbit.apache.org Received: (qmail 64212 invoked by uid 99); 17 Apr 2013 10:04:46 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 17 Apr 2013 10:04:46 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 17 Apr 2013 10:04:39 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 4093423888E4; Wed, 17 Apr 2013 10:04:18 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1468819 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/core/ main/java/org/apache/jackrabbit/oak/security/authorization/ main/java/org/apache/jackrabbit/oak/security/authorization/permission/ main/java/org/apa... Date: Wed, 17 Apr 2013 10:04:17 -0000 To: oak-commits@jackrabbit.apache.org From: angela@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130417100418.4093423888E4@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: angela Date: Wed Apr 17 10:04:17 2013 New Revision: 1468819 URL: http://svn.apache.org/r1468819 Log: OAK-527: permissions (wip) Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeState.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecurityContext.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlContext.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionConstants.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeContext.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserContext.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/Context.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/SecurityConfiguration.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/ReadStatus.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserConstants.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/ReadStatusTest.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java?rev=1468819&r1=1468818&r2=1468819&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java Wed Apr 17 10:04:17 2013 @@ -18,19 +18,12 @@ */ package org.apache.jackrabbit.oak.core; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.apache.jackrabbit.oak.commons.PathUtils.elements; -import static org.apache.jackrabbit.oak.commons.PathUtils.getName; -import static org.apache.jackrabbit.oak.commons.PathUtils.getParentPath; - import java.io.IOException; import java.io.InputStream; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collections; import java.util.List; - import javax.annotation.Nonnull; import javax.security.auth.Subject; @@ -57,6 +50,7 @@ import org.apache.jackrabbit.oak.spi.com import org.apache.jackrabbit.oak.spi.observation.ChangeExtractor; import org.apache.jackrabbit.oak.spi.query.CompositeQueryIndexProvider; import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider; +import org.apache.jackrabbit.oak.spi.security.Context; import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider; import org.apache.jackrabbit.oak.spi.security.SecurityConfiguration; import org.apache.jackrabbit.oak.spi.security.SecurityProvider; @@ -67,6 +61,12 @@ import org.apache.jackrabbit.oak.spi.sta import org.apache.jackrabbit.oak.spi.state.NodeStore; import org.apache.jackrabbit.oak.spi.state.NodeStoreBranch; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.apache.jackrabbit.oak.commons.PathUtils.elements; +import static org.apache.jackrabbit.oak.commons.PathUtils.getName; +import static org.apache.jackrabbit.oak.commons.PathUtils.getParentPath; + public class RootImpl implements Root { /** @@ -426,9 +426,7 @@ public class RootImpl implements Root { @Nonnull private SecurityContext getRootContext(NodeState root) { - TreeTypeProvider typeProvider = new TreeTypeProviderImpl( - securityProvider.getAccessControlConfiguration().getContext()); - return new SecurityContext(root, getPermissionProvider(), typeProvider); + return new SecurityContext(root, getPermissionProvider(), getAcContext()); } @Nonnull @@ -461,6 +459,11 @@ public class RootImpl implements Root { return securityProvider.getAccessControlConfiguration().getPermissionProvider(this, subject.getPrincipals()); } + @Nonnull + private Context getAcContext() { + return securityProvider.getAccessControlConfiguration().getContext(); + } + //---------------------------------------------------------< MoveRecord >--- /** Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeState.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeState.java?rev=1468819&r1=1468818&r2=1468819&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeState.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeState.java Wed Apr 17 10:04:17 2013 @@ -16,7 +16,6 @@ */ package org.apache.jackrabbit.oak.core; -import java.util.Collections; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -58,23 +57,13 @@ class SecureNodeState extends AbstractNo /** * Predicate for testing whether a given property is readable. */ - private final Predicate isPropertyReadable = new Predicate() { - @Override - public boolean apply(@Nonnull PropertyState property) { - return context.canReadProperty(property); - } - }; + private final Predicate isPropertyReadable = new ReadablePropertyPredicate(); /** * Predicate for testing whether the node state in a child node entry * is iterable. */ - private final Predicate isIterableNode = new Predicate() { - @Override - public boolean apply(@Nonnull ChildNodeEntry input) { - return input.getNodeState().exists(); - } - }; + private final Predicate isIterableNode = new IterableNodePredicate(); /** * Function that that adds a security wrapper to node states from @@ -85,30 +74,7 @@ class SecureNodeState extends AbstractNo * or any of its descendants has read access restrictions. Otherwise * we can optimize access by skipping the security wrapper entirely. */ - private final Function wrapChildNodeEntry = new Function() { - @Override @Nonnull - public ChildNodeEntry apply(@Nonnull ChildNodeEntry input) { - String name = input.getName(); - NodeState child = input.getNodeState(); - SecurityContext childContext = context.getChildContext(name, child); - SecureNodeState secureChild = - new SecureNodeState(child, childContext); - if (child.getChildNodeCount() == 0 - && secureChild.context.canReadThisNode() - && secureChild.context.canReadAllProperties()) { - // Since this is an accessible leaf node whose all properties - // are readable, we don't need the SecureNodeState wrapper - // TODO: A further optimization would be to return the raw - // underlying node state even for non-leaf nodes if we can - // tell in advance that the full subtree is readable. Then - // we also wouldn't need the above getChildNodeCount() call - // that's somewhat expensive on the MongoMK. - return input; - } else { - return new MemoryChildNodeEntry(name, secureChild); - } - } - }; + private final WrapChildEntryFunction wrapChildNodeEntry = new WrapChildEntryFunction(); private long childNodeCount = -1; @@ -138,13 +104,10 @@ class SecureNodeState extends AbstractNo @Override public synchronized long getPropertyCount() { if (propertyCount == -1) { - if (context.canReadAllProperties()) { + if (context.canReadAll()) { propertyCount = state.getPropertyCount(); - } else if (context.canReadThisNode()) { - propertyCount = count( - filter(state.getProperties(), isPropertyReadable)); } else { - propertyCount = 0; + propertyCount = count(filter(state.getProperties(), isPropertyReadable)); } } return propertyCount; @@ -152,19 +115,17 @@ class SecureNodeState extends AbstractNo @Override @Nonnull public Iterable getProperties() { - if (context.canReadAllProperties()) { + if (context.canReadAll()) { return state.getProperties(); - } else if (context.canReadThisNode()) { - return filter(state.getProperties(), isPropertyReadable); } else { - return Collections.emptySet(); + return filter(state.getProperties(), isPropertyReadable); } } @Override public NodeState getChildNode(@Nonnull String name) { NodeState child = state.getChildNode(checkNotNull(name)); - if (child.exists()) { + if (child.exists() && !context.canReadAll()) { ChildNodeEntry entry = new MemoryChildNodeEntry(name, child); return wrapChildNodeEntry.apply(entry).getNodeState(); } else { @@ -175,20 +136,22 @@ class SecureNodeState extends AbstractNo @Override public synchronized long getChildNodeCount() { if (childNodeCount == -1) { - childNodeCount = super.getChildNodeCount(); + if (context.canReadAll()) { + childNodeCount = state.getChildNodeCount(); + } else { + childNodeCount = super.getChildNodeCount(); + } } return childNodeCount; } @Override @Nonnull public Iterable getChildNodeEntries() { - if (context.canNotReadChildNodes()) { - return Collections.emptySet(); + if (context.canReadAll()) { + // everything is readable including ac-content -> no secure wrapper needed + return state.getChildNodeEntries(); } else { - // TODO: review if ALLOW_CHILDREN could be used as well although we - // don't know the type of all child-nodes where ac node would need special treatment - Iterable readable = - transform(state.getChildNodeEntries(), wrapChildNodeEntry); + Iterable readable = transform(state.getChildNodeEntries(), wrapChildNodeEntry); return filter(readable, isIterableNode); } } @@ -224,4 +187,59 @@ class SecureNodeState extends AbstractNo return super.equals(object); } + + //------------------------------------------------------< inner classes >--- + /** + * Predicate for testing whether a given property is readable. + */ + private class ReadablePropertyPredicate implements Predicate { + @Override + public boolean apply(@Nonnull PropertyState property) { + return context.canReadProperty(property); + } + } + + /** + * Predicate for testing whether the node state in a child node entry is iterable. + */ + private class IterableNodePredicate implements Predicate { + @Override + public boolean apply(@Nonnull ChildNodeEntry input) { + return input.getNodeState().exists(); + } + } + + /** + * Function that that adds a security wrapper to node states from + * in child node entries. The {@link IterableNodePredicate} predicate should be + * used on the result to filter out non-existing/iterable child nodes. + *

+ * Note that the SecureNodeState wrapper is needed only when the child + * or any of its descendants has read access restrictions. Otherwise + * we can optimize access by skipping the security wrapper entirely. + */ + private class WrapChildEntryFunction implements Function { + @Nonnull + @Override + public ChildNodeEntry apply(@Nonnull ChildNodeEntry input) { + String name = input.getName(); + NodeState child = input.getNodeState(); + SecurityContext childContext = context.getChildContext(name, child); + SecureNodeState secureChild = new SecureNodeState(child, childContext); + if (child.getChildNodeCount() == 0 + && secureChild.context.canReadThisNode() + && secureChild.context.canReadAllProperties()) { + // Since this is an accessible leaf node whose all properties + // are readable, we don't need the SecureNodeState wrapper + // TODO: A further optimization would be to return the raw + // underlying node state even for non-leaf nodes if we can + // tell in advance that the full subtree is readable. Then + // we also wouldn't need the above getChildNodeCount() call + // that's somewhat expensive on the MongoMK. + return input; + } else { + return new MemoryChildNodeEntry(name, secureChild); + } + } + } } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecurityContext.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecurityContext.java?rev=1468819&r1=1468818&r2=1468819&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecurityContext.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecurityContext.java Wed Apr 17 10:04:17 2013 @@ -19,6 +19,7 @@ package org.apache.jackrabbit.oak.core; import javax.annotation.Nonnull; import org.apache.jackrabbit.oak.api.PropertyState; +import org.apache.jackrabbit.oak.spi.security.Context; import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider; import org.apache.jackrabbit.oak.spi.security.authorization.permission.ReadStatus; import org.apache.jackrabbit.oak.spi.state.NodeState; @@ -44,15 +45,18 @@ class SecurityContext { private final PermissionProvider permissionProvider; + private final Context acContext; + private ReadStatus readStatus; SecurityContext( @Nonnull NodeState rootState, @Nonnull PermissionProvider permissionProvider, - @Nonnull TreeTypeProvider typeProvider) { + @Nonnull Context acContext) { this.root = checkNotNull(rootState); - this.base = new ImmutableTree(rootState, typeProvider); + this.base = new ImmutableTree(rootState, new TreeTypeProviderImpl(acContext)); this.permissionProvider = permissionProvider; + this.acContext = acContext; // calculate the readstatus for the root this.readStatus = permissionProvider.getReadStatus(base, null); } @@ -63,8 +67,9 @@ class SecurityContext { this.root = checkNotNull(parent).root; this.base = new ImmutableTree(parent.base, name, nodeState); this.permissionProvider = parent.permissionProvider; + this.acContext = parent.acContext; if (base.getType() == parent.base.getType()) { - readStatus = ReadStatus.getChildStatus(parent.readStatus); + readStatus = ReadStatus.getChildStatus(parent.readStatus, acContext.hasChildItems(parent.base)); } else { readStatus = null; } @@ -98,9 +103,8 @@ class SecurityContext { } } - boolean canNotReadChildNodes() { - ReadStatus rs = getReadStatus(); - return rs.includes(ReadStatus.DENY_CHILDREN); + boolean canReadAll() { + return readStatus != null && readStatus.includes(ReadStatus.ALLOW_ALL); } SecurityContext getChildContext(String name, NodeState state) { Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlContext.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlContext.java?rev=1468819&r1=1468818&r2=1468819&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlContext.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlContext.java Wed Apr 17 10:04:17 2013 @@ -62,4 +62,15 @@ final class AccessControlContext impleme return POLICY_NODE_NAMES.contains(name) || ACE_PROPERTY_NAMES.contains(name) || path.startsWith(PERMISSIONS_STORE_PATH); } } + + @Override + public boolean hasChildItems(Tree parent) { + for (String name : POLICY_NODE_NAMES) { + if (parent.hasChild(name)) { + return true; + } + } + String ntName = TreeUtil.getPrimaryTypeName(parent); + return AC_NODETYPE_NAMES.contains(ntName) || PERMISSION_NODETYPE_NAMES.contains(ntName); + } } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionConstants.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionConstants.java?rev=1468819&r1=1468818&r2=1468819&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionConstants.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionConstants.java Wed Apr 17 10:04:17 2013 @@ -36,8 +36,11 @@ public interface PermissionConstants { String REP_ACCESS_CONTROLLED_PATH = "rep:accessControlledPath"; String REP_PRIVILEGE_BITS = "rep:privileges"; String REP_INDEX = "rep:index"; + char PREFIX_ALLOW = 'a'; char PREFIX_DENY = 'd'; Set PERMISSION_NODETYPE_NAMES = ImmutableSet.of(NT_REP_PERMISSIONS, NT_REP_PERMISSION_STORE); + Set PERMISSION_NODE_NAMES = ImmutableSet.of(REP_PERMISSION_STORE); + Set PERMISSION_PROPERTY_NAMES = ImmutableSet.of(REP_ACCESS_CONTROLLED_PATH, REP_PRIVILEGE_BITS, REP_INDEX); } \ No newline at end of file Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java?rev=1468819&r1=1468818&r2=1468819&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java Wed Apr 17 10:04:17 2013 @@ -32,34 +32,40 @@ public interface PrivilegeConstants { String REP_PRIVILEGES = "rep:privileges"; /** - * Internal (oak) path for the privilege store. + * Name of the property that defines if the privilege is abstract. */ - String PRIVILEGES_PATH = '/' + JcrConstants.JCR_SYSTEM + '/' + REP_PRIVILEGES; + String REP_IS_ABSTRACT = "rep:isAbstract"; /** - * Node type name of the root node of the privilege store + * Name of the privilege definition property that stores the aggregate privilege names. */ - String NT_REP_PRIVILEGES = "rep:Privileges"; + String REP_AGGREGATES = "rep:aggregates"; /** - * Node type name of the privilege definition nodes + * Name of the property storing the value of the next available privilege bits. */ - String NT_REP_PRIVILEGE = "rep:Privilege"; + String REP_NEXT = "rep:next"; /** - * Name of the property that defines if the privilege is abstract. + * The internal names of all property definitions that are associated with + * the {@link #NT_REP_PRIVILEGE rep:Privilege} node type */ - String REP_IS_ABSTRACT = "rep:isAbstract"; + Set PRIVILEGE_PROPERTY_NAMES = ImmutableSet.of(REP_IS_ABSTRACT, REP_AGGREGATES, REP_NEXT); /** - * Name of the privilege definition property that stores the aggregate privilege names. + * Internal (oak) path for the privilege store. */ - String REP_AGGREGATES = "rep:aggregates"; + String PRIVILEGES_PATH = '/' + JcrConstants.JCR_SYSTEM + '/' + REP_PRIVILEGES; /** - * Name of the property storing the value of the next available privilege bits. + * Node type name of the root node of the privilege store */ - String REP_NEXT = "rep:next"; + String NT_REP_PRIVILEGES = "rep:Privileges"; + + /** + * Node type name of the privilege definition nodes + */ + String NT_REP_PRIVILEGE = "rep:Privilege"; /** * Name of the privilege definition property that stores the internal representation @@ -192,10 +198,4 @@ public interface PrivilegeConstants { * Internal (oak) name of the rep:removeProperties privilege */ String REP_REMOVE_PROPERTIES = "rep:removeProperties"; - - /** - * The internal names of all property definitions that are associated with - * the {@link #NT_REP_PRIVILEGE rep:Privilege} node type - */ - Set PRIVILEGE_PROPERTY_NAMES = ImmutableSet.of(REP_IS_ABSTRACT, REP_AGGREGATES); } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeContext.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeContext.java?rev=1468819&r1=1468818&r2=1468819&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeContext.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeContext.java Wed Apr 17 10:04:17 2013 @@ -25,7 +25,7 @@ import org.apache.jackrabbit.oak.util.Tr /** * PrivilegeContext... TODO */ -final class PrivilegeContext implements Context { +final class PrivilegeContext implements Context, PrivilegeConstants { private static final Context INSTANCE = new PrivilegeContext(); @@ -39,16 +39,23 @@ final class PrivilegeContext implements //------------------------------------------------------------< Context >--- @Override public boolean definesProperty(Tree parent, PropertyState property) { - return definesTree(parent) && PrivilegeConstants.PRIVILEGE_PROPERTY_NAMES.contains(property.getName()); + return definesTree(parent) && PRIVILEGE_PROPERTY_NAMES.contains(property.getName()); } @Override public boolean definesTree(Tree tree) { - return PrivilegeConstants.NT_REP_PRIVILEGE.equals(TreeUtil.getPrimaryTypeName(tree)); + return NT_REP_PRIVILEGE.equals(TreeUtil.getPrimaryTypeName(tree)); } @Override public boolean definesLocation(TreeLocation location) { - return location.getPath().startsWith(PrivilegeConstants.PRIVILEGES_PATH); + return location.getPath().startsWith(PRIVILEGES_PATH); + } + + @Override + public boolean hasChildItems(Tree parent) { + return parent.hasChild(REP_PRIVILEGES) + || NT_REP_PRIVILEGES.equals(TreeUtil.getPrimaryTypeName(parent)) + || NT_REP_PRIVILEGE.equals(TreeUtil.getPrimaryTypeName(parent)); } } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserContext.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserContext.java?rev=1468819&r1=1468818&r2=1468819&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserContext.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserContext.java Wed Apr 17 10:04:17 2013 @@ -22,6 +22,7 @@ import org.apache.jackrabbit.oak.api.Tre import org.apache.jackrabbit.oak.spi.security.Context; import org.apache.jackrabbit.oak.spi.security.user.UserConstants; import org.apache.jackrabbit.oak.util.TreeUtil; +import org.apache.jackrabbit.util.Text; /** * UserContext... TODO @@ -64,8 +65,31 @@ final class UserContext implements Conte PropertyState p = location.getProperty(); return (p == null) ? definesTree(tree) : definesProperty(tree, p); } else { - // FIXME - return false; + String path = location.getPath(); + String name = Text.getName(path); + if (USER_PROPERTY_NAMES.contains(name) || GROUP_PROPERTY_NAMES.contains(name) || path.contains(REP_MEMBERS)) { + return true; + } else { + // undefined: unable to determine if the specified location + // defines a user or group node (missing node type information + // on non-existing location + return false; + } } } + + @Override + public boolean hasChildItems(Tree parent) { + if (NODE_TYPE_NAMES.contains(TreeUtil.getPrimaryTypeName(parent))) { + // covers all properties + return true; + } + for (Tree child : parent.getChildren()) { + String ntName = TreeUtil.getPrimaryTypeName(child); + if (NODE_TYPE_NAMES.contains(ntName)) { + return true; + } + } + return false; + } } \ No newline at end of file Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/Context.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/Context.java?rev=1468819&r1=1468818&r2=1468819&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/Context.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/Context.java Wed Apr 17 10:04:17 2013 @@ -30,4 +30,28 @@ public interface Context { boolean definesTree(Tree tree); boolean definesLocation(TreeLocation location); + + boolean hasChildItems(Tree parent); + + class Default implements Context { + @Override + public boolean definesProperty(Tree parent, PropertyState property) { + return false; + } + + @Override + public boolean definesTree(Tree tree) { + return false; + } + + @Override + public boolean definesLocation(TreeLocation location) { + return false; + } + + @Override + public boolean hasChildItems(Tree parent) { + return false; + } + } } \ No newline at end of file Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/SecurityConfiguration.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/SecurityConfiguration.java?rev=1468819&r1=1468818&r2=1468819&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/SecurityConfiguration.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/SecurityConfiguration.java Wed Apr 17 10:04:17 2013 @@ -20,9 +20,6 @@ import java.util.Collections; import java.util.List; import javax.annotation.Nonnull; -import org.apache.jackrabbit.oak.api.PropertyState; -import org.apache.jackrabbit.oak.api.Tree; -import org.apache.jackrabbit.oak.api.TreeLocation; import org.apache.jackrabbit.oak.spi.commit.CommitHook; import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider; import org.apache.jackrabbit.oak.spi.lifecycle.WorkspaceInitializer; @@ -96,22 +93,7 @@ public interface SecurityConfiguration { @Override public Context getContext() { - return new Context() { - @Override - public boolean definesProperty(Tree parent, PropertyState property) { - return false; - } - - @Override - public boolean definesTree(Tree tree) { - return false; - } - - @Override - public boolean definesLocation(TreeLocation location) { - return false; - } - }; + return new Context.Default(); } } } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/ReadStatus.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/ReadStatus.java?rev=1468819&r1=1468818&r2=1468819&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/ReadStatus.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/ReadStatus.java Wed Apr 17 10:04:17 2013 @@ -26,21 +26,35 @@ import org.apache.jackrabbit.oak.securit */ public class ReadStatus { - public static final ReadStatus ALLOW_THIS = new ReadStatus(1, true); - public static final ReadStatus ALLOW_CHILDREN = new ReadStatus(2, true); - public static final ReadStatus ALLOW_NODES = new ReadStatus(3, true); - public static final ReadStatus ALLOW_PROPERTIES = new ReadStatus(4, true); - public static final ReadStatus ALLOW_THIS_PROPERTIES = new ReadStatus(5, true); - public static final ReadStatus ALLOW_CHILDITEMS = new ReadStatus(6, true); - public static final ReadStatus ALLOW_ALL = new ReadStatus(7, true); - - public static final ReadStatus DENY_THIS = new ReadStatus(1, false); - public static final ReadStatus DENY_CHILDREN = new ReadStatus(2, false); - public static final ReadStatus DENY_NODES = new ReadStatus(3, false); - public static final ReadStatus DENY_PROPERTIES = new ReadStatus(4, false); - public static final ReadStatus DENY_THIS_PROPERTIES = new ReadStatus(5, false); - public static final ReadStatus DENY_CHILDITEMS = new ReadStatus(6, false); - public static final ReadStatus DENY_ALL = new ReadStatus(7, false); + private static final int STATUS_THIS = 1; + private static final int STATUS_CHILDREN = 2; + private static final int STATUS_NODES = 3; + private static final int STATUS_PROPERTIES = 4; + private static final int STATUS_THIS_PROPERTIES = 5; + private static final int STATUS_CHILDITEMS = 6; + private static final int STATUS_ALL_REGULAR = 7; + private static final int STATUS_ACCESS_CONTROL = 8; + private static final int STATUS_ALL = 15; + + public static final ReadStatus ALLOW_THIS = new ReadStatus(STATUS_THIS, true); + public static final ReadStatus ALLOW_CHILDREN = new ReadStatus(STATUS_CHILDREN, true); + public static final ReadStatus ALLOW_NODES = new ReadStatus(STATUS_NODES, true); + public static final ReadStatus ALLOW_PROPERTIES = new ReadStatus(STATUS_PROPERTIES, true); + public static final ReadStatus ALLOW_THIS_PROPERTIES = new ReadStatus(STATUS_THIS_PROPERTIES, true); + public static final ReadStatus ALLOW_CHILDITEMS = new ReadStatus(STATUS_CHILDITEMS, true); + public static final ReadStatus ALLOW_ALL_REGULAR = new ReadStatus(STATUS_ALL_REGULAR, true); + public static final ReadStatus ALLOW_ACCESS_CONTROL = new ReadStatus(STATUS_ACCESS_CONTROL, true); + public static final ReadStatus ALLOW_ALL = new ReadStatus(STATUS_ALL, true); + + public static final ReadStatus DENY_THIS = new ReadStatus(STATUS_THIS, false); + public static final ReadStatus DENY_CHILDREN = new ReadStatus(STATUS_CHILDREN, false); + public static final ReadStatus DENY_NODES = new ReadStatus(STATUS_NODES, false); + public static final ReadStatus DENY_PROPERTIES = new ReadStatus(STATUS_PROPERTIES, false); + public static final ReadStatus DENY_THIS_PROPERTIES = new ReadStatus(STATUS_THIS_PROPERTIES, false); + public static final ReadStatus DENY_CHILDITEMS = new ReadStatus(STATUS_CHILDITEMS, false); + public static final ReadStatus DENY_ALL_REGULAR = new ReadStatus(STATUS_ALL_REGULAR, false); + public static final ReadStatus DENY_ACCESS_CONTROL = new ReadStatus(STATUS_ACCESS_CONTROL, false); + public static final ReadStatus DENY_ALL = new ReadStatus(STATUS_ALL, false); private final int status; private final boolean isAllow; @@ -64,19 +78,29 @@ public class ReadStatus { } @CheckForNull - public static ReadStatus getChildStatus(@Nullable ReadStatus parentStatus) { + public static ReadStatus getChildStatus(@Nullable ReadStatus parentStatus, + boolean hasAcChildren) { if (parentStatus == null) { return null; } // TODO switch (parentStatus.status) { - case 1: return null; // recalculate for child items - case 2: - case 3: return (parentStatus.isAllow) ? ALLOW_THIS : DENY_THIS; - case 4: - case 5: return null; // recalculate for properties of child node - case 6: - case 7: return (parentStatus.isAllow) ? ALLOW_ALL : DENY_ALL; + case STATUS_THIS: + return null; // recalculate for child items + case STATUS_CHILDREN: + case STATUS_NODES: + return (hasAcChildren) ? null : parentStatus; + case STATUS_PROPERTIES: + case STATUS_THIS_PROPERTIES: + return null; // recalculate for properties of child node + case STATUS_CHILDITEMS: + case STATUS_ALL_REGULAR: + return (hasAcChildren) ? null : parentStatus; + case STATUS_ACCESS_CONTROL: + // TODO + return null; // recalculate + case STATUS_ALL: + return (parentStatus.isAllow) ? ALLOW_ALL : DENY_ALL; default: throw new IllegalArgumentException("invalid status"); } } @@ -94,11 +118,11 @@ public class ReadStatus { } public boolean isAll() { - return status == 7; + return status == STATUS_ALL; } public boolean appliesToThis() { - return status == 1; + return status == STATUS_THIS; } public int getStatus() { Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserConstants.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserConstants.java?rev=1468819&r1=1468818&r2=1468819&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserConstants.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserConstants.java Wed Apr 17 10:04:17 2013 @@ -31,6 +31,7 @@ public interface UserConstants { String NT_REP_GROUP = "rep:Group"; String NT_REP_MEMBERS = "rep:Members"; String MIX_REP_IMPERSONATABLE = "rep:Impersonatable"; + String REP_PRINCIPAL_NAME = "rep:principalName"; String REP_AUTHORIZABLE_ID = "rep:authorizableId"; String REP_PASSWORD = "rep:password"; @@ -52,6 +53,8 @@ public interface UserConstants { REP_IMPERSONATORS ); + Collection NODE_TYPE_NAMES = ImmutableSet.of(NT_REP_AUTHORIZABLE, NT_REP_USER, NT_REP_GROUP, NT_REP_MEMBERS); + /** * Configuration option defining the ID of the administrator user. */ Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/ReadStatusTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/ReadStatusTest.java?rev=1468819&r1=1468818&r2=1468819&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/ReadStatusTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/ReadStatusTest.java Wed Apr 17 10:04:17 2013 @@ -29,12 +29,15 @@ public class ReadStatusTest { @Test public void testAllowAll() { ReadStatus allowAll = ReadStatus.ALLOW_ALL; + assertTrue(allowAll.includes(ReadStatus.ALLOW_THIS)); assertTrue(allowAll.includes(ReadStatus.ALLOW_CHILDREN)); assertTrue(allowAll.includes(ReadStatus.ALLOW_NODES)); assertTrue(allowAll.includes(ReadStatus.ALLOW_PROPERTIES)); assertTrue(allowAll.includes(ReadStatus.ALLOW_THIS_PROPERTIES)); assertTrue(allowAll.includes(ReadStatus.ALLOW_CHILDITEMS)); + assertTrue(allowAll.includes(ReadStatus.ALLOW_ALL_REGULAR)); + assertTrue(allowAll.includes(ReadStatus.ALLOW_ACCESS_CONTROL)); assertTrue(allowAll.includes(ReadStatus.ALLOW_ALL)); } }