Added:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalPolicyValidatorProvider.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalPolicyValidatorProvider.java?rev=1857551&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalPolicyValidatorProvider.java
(added)
+++
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalPolicyValidatorProvider.java
Mon Apr 15 07:16:49 2019
@@ -0,0 +1,270 @@
+/*
+ * 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.spi.security.authorization.principalbased.impl;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+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.commons.PathUtils;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.nodetype.TypePredicate;
+import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.DefaultValidator;
+import org.apache.jackrabbit.oak.spi.commit.Validator;
+import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
+import org.apache.jackrabbit.oak.spi.commit.VisibleValidator;
+import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
+import
org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
+import
org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.Privilege;
+import java.security.Principal;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkState;
+import static org.apache.jackrabbit.oak.api.CommitFailedException.ACCESS;
+import static
org.apache.jackrabbit.oak.api.CommitFailedException.ACCESS_CONTROL;
+import static org.apache.jackrabbit.oak.api.CommitFailedException.CONSTRAINT;
+import static org.apache.jackrabbit.oak.api.CommitFailedException.OAK;
+
+class PrincipalPolicyValidatorProvider extends ValidatorProvider implements
Constants {
+
+ private final MgrProvider mgrProvider;
+ private final Set<Principal> principals;
+ private final String workspaceName;
+
+ private PermissionProvider permissionProvider;
+ private TypePredicate isMixPrincipalBased;
+
+ PrincipalPolicyValidatorProvider(@NotNull MgrProvider mgrProvider,
@NotNull Set<Principal> principals, @NotNull String workspaceName) {
+ this.mgrProvider = mgrProvider;
+ this.principals = principals;
+ this.workspaceName = workspaceName;
+ }
+
+ @Override
+ protected PolicyValidator getRootValidator(NodeState before, NodeState
after, CommitInfo info) {
+ Root rootBefore =
mgrProvider.getRootProvider().createReadOnlyRoot(before);
+ permissionProvider =
mgrProvider.getSecurityProvider().getConfiguration(AuthorizationConfiguration.class).getPermissionProvider(rootBefore,
workspaceName, principals);
+ isMixPrincipalBased = new TypePredicate(after,
MIX_REP_PRINCIPAL_BASED_MIXIN);
+ return new PolicyValidator(before, after);
+ }
+
+ private final class PolicyValidator extends DefaultValidator {
+
+ private final Tree parentBefore;
+ private final Tree parentAfter;
+ private final boolean isNodetypeTree;
+
+ private PolicyValidator(@NotNull NodeState rootStateBefore, @NotNull
NodeState rootState) {
+
mgrProvider.reset(mgrProvider.getRootProvider().createReadOnlyRoot(rootState),
NamePathMapper.DEFAULT);
+ this.parentBefore =
mgrProvider.getTreeProvider().createReadOnlyTree(rootStateBefore);
+ this.parentAfter =
mgrProvider.getTreeProvider().createReadOnlyTree(rootState);
+ this.isNodetypeTree = false;
+ }
+
+ private PolicyValidator(@NotNull PolicyValidator parentValidator,
@NotNull Tree before, @NotNull Tree after) {
+ this.parentBefore = before;
+ this.parentAfter = after;
+ if (parentValidator.isNodetypeTree) {
+ this.isNodetypeTree = true;
+ } else {
+ this.isNodetypeTree =
NodeTypeConstants.JCR_NODE_TYPES.equals(after.getName()) &&
NodeTypeConstants.JCR_SYSTEM.equals(parentValidator.getName());
+ }
+ }
+
+ private PolicyValidator(@NotNull PolicyValidator parentValidator,
@NotNull Tree tree, boolean isAfter) {
+ this.parentBefore = (isAfter) ? null : tree;
+ this.parentAfter = (isAfter) ? tree : null;
+ if (parentValidator.isNodetypeTree) {
+ this.isNodetypeTree = true;
+ } else {
+ this.isNodetypeTree =
NodeTypeConstants.JCR_NODE_TYPES.equals(tree.getName()) &&
NodeTypeConstants.JCR_SYSTEM.equals(parentValidator.getName());
+ }
+ }
+
+ @NotNull
+ private String getName() {
+ return (parentBefore == null) ?
verifyNotNull(parentAfter).getName() : parentBefore.getName();
+ }
+
+ //------------------------------------------------------< Validator
>---
+ @Override
+ public void propertyAdded(PropertyState after) throws
CommitFailedException {
+ String propertyName = after.getName();
+ if (JcrConstants.JCR_PRIMARYTYPE.equals(propertyName)) {
+ if (NT_REP_PRINCIPAL_POLICY.equals(after.getValue(Type.NAME))
&& !REP_PRINCIPAL_POLICY.equals(verifyNotNull(parentAfter).getName())) {
+ throw accessControlViolation(30, "Attempt create policy
node with different name than '"+REP_PRINCIPAL_POLICY+"'.");
+ }
+ }
+ }
+
+ @Override
+ public void propertyChanged(PropertyState before, PropertyState after)
throws CommitFailedException {
+ String name = after.getName();
+ if (JcrConstants.JCR_PRIMARYTYPE.equals(name)) {
+ if
(NT_REP_PRINCIPAL_POLICY.equals(before.getValue(Type.STRING)) ||
NT_REP_PRINCIPAL_POLICY.equals(after.getValue(Type.STRING))) {
+ throw accessControlViolation(31, "Attempt to change
primary type of/to rep:PrincipalPolicy.");
+ }
+ }
+ }
+
+ @Override
+ public Validator childNodeAdded(String name, NodeState after) throws
CommitFailedException {
+ if (!isNodetypeTree) {
+ if (REP_PRINCIPAL_POLICY.equals(name)) {
+ validatePolicyNode(verifyNotNull(parentAfter), after);
+ } else if (REP_RESTRICTIONS.equals(name)) {
+ validateRestrictions(after);
+ } else if
(NT_REP_PRINCIPAL_ENTRY.equals(NodeStateUtils.getPrimaryTypeName(after))) {
+ validateEntry(name, after);
+ }
+ }
+ return new VisibleValidator(nextValidator(name, after, true),
true, true);
+ }
+
+ @Override
+ public Validator childNodeChanged(String name, NodeState before,
NodeState after) throws CommitFailedException {
+ if (!isNodetypeTree) {
+ if (after.hasChildNode(REP_PRINCIPAL_POLICY)) {
+ Tree parent =
mgrProvider.getTreeProvider().createReadOnlyTree(verifyNotNull(parentAfter),
name, after);
+ validatePolicyNode(parent,
after.getChildNode(REP_PRINCIPAL_POLICY));
+ } else if (REP_RESTRICTIONS.equals(name)) {
+ validateRestrictions(after);
+ } else if
(NT_REP_PRINCIPAL_ENTRY.equals(NodeStateUtils.getPrimaryTypeName(after))) {
+ validateEntry(name, after);
+ }
+ }
+ return new VisibleValidator(nextValidator(name, before, after),
true, true);
+ }
+
+ @Override
+ public Validator childNodeDeleted(String name, NodeState before)
throws CommitFailedException {
+ if (!isNodetypeTree) {
+ PropertyState effectivePath = null;
+ if (REP_RESTRICTIONS.equals(name)) {
+ effectivePath =
verifyNotNull(parentBefore).getProperty(REP_EFFECTIVE_PATH);
+ } else if
(NT_REP_PRINCIPAL_ENTRY.equals(NodeStateUtils.getPrimaryTypeName(before))) {
+ effectivePath = before.getProperty(REP_EFFECTIVE_PATH);
+ }
+ if (effectivePath != null &&
!Utils.hasModAcPermission(permissionProvider,
effectivePath.getValue(Type.PATH))) {
+ throw new CommitFailedException(ACCESS, 3, "Access
denied");
+ }
+ }
+ return new VisibleValidator(nextValidator(name, before, false),
true, true); }
+
+
//----------------------------------------------------------------------
+ private void validatePolicyNode(@NotNull Tree parent, @NotNull
NodeState nodeState) throws CommitFailedException {
+ if
(!NT_REP_PRINCIPAL_POLICY.equals(NodeStateUtils.getPrimaryTypeName(nodeState)))
{
+ throw accessControlViolation(32, "Reserved node name
'rep:principalPolicy' must only be used for nodes of type
'rep:PrincipalPolicy'.");
+ }
+ if (!isMixPrincipalBased.apply(parent)) {
+ throw accessControlViolation(33, "Parent node not of mixin
type 'rep:PrincipalBasedMixin'.");
+ }
+ }
+
+ private void validateRestrictions(@NotNull NodeState nodeState) throws
CommitFailedException {
+ if
(!NT_REP_RESTRICTIONS.equals(NodeStateUtils.getPrimaryTypeName(nodeState))) {
+ throw accessControlViolation(34, "Reserved node name
'rep:restrictions' must only be used for nodes of type 'rep:Restrictions'.");
+ }
+ Tree parent = verifyNotNull(parentAfter);
+ if
(NT_REP_PRINCIPAL_ENTRY.equals(TreeUtil.getPrimaryTypeName(parent))) {
+ try {
+ String oakPath =
Strings.emptyToNull(TreeUtil.getString(parent, REP_EFFECTIVE_PATH));
+
mgrProvider.getRestrictionProvider().validateRestrictions(oakPath, parent);
+ } catch (AccessControlException e) {
+ throw new CommitFailedException(ACCESS_CONTROL, 35,
"Invalid restrictions", e);
+ } catch (RepositoryException e) {
+ throw new CommitFailedException(OAK, 13, "Internal error",
e);
+ }
+ } else {
+ // assert the restrictions node resides within access control
content
+ if (!mgrProvider.getContext().definesTree(parent)) {
+ throw new CommitFailedException(ACCESS_CONTROL, 2,
"Expected access control entry parent (isolated restriction).");
+ }
+ }
+ }
+
+ private void validateEntry(@NotNull String name, @NotNull NodeState
nodeState) throws CommitFailedException {
+ Tree parent = verifyNotNull(parentAfter);
+ String entryPath = PathUtils.concat(parent.getPath(), name);
+ if (!REP_PRINCIPAL_POLICY.equals(parent.getName())) {
+ throw accessControlViolation(36, "Isolated entry of principal
policy at " + entryPath);
+ }
+ Iterable<String> privilegeNames =
nodeState.getNames(REP_PRIVILEGES);
+ if (Iterables.isEmpty(privilegeNames)) {
+ throw accessControlViolation(37, "Empty rep:privileges
property at " + entryPath);
+ }
+ PrivilegeManager privilegeManager =
mgrProvider.getPrivilegeManager();
+ for (String privilegeName : privilegeNames) {
+ try {
+ Privilege privilege =
privilegeManager.getPrivilege(privilegeName);
+ if (privilege.isAbstract()) {
+ throw accessControlViolation(38, "Abstract privilege "
+ privilegeName + " at " + entryPath);
+ }
+ } catch (AccessControlException e) {
+ throw accessControlViolation(39, "Invalid privilege " +
privilegeName + " at " + entryPath);
+ } catch (RepositoryException e) {
+ throw new CommitFailedException(OAK, 13, "Internal error",
e);
+ }
+ }
+ // check mod-access-control permission on the effective path
+ PropertyState effectivePath =
nodeState.getProperty(REP_EFFECTIVE_PATH);
+ if (effectivePath == null) {
+ throw new CommitFailedException(CONSTRAINT, 21, "Missing
mandatory rep:effectivePath property at " + entryPath);
+ }
+ if (!Utils.hasModAcPermission(permissionProvider,
effectivePath.getValue(Type.PATH))) {
+ throw new CommitFailedException(ACCESS, 3, "Access denied");
+ }
+ }
+
+ private CommitFailedException accessControlViolation(int code, String
message) {
+ return new CommitFailedException(ACCESS_CONTROL, code, message);
+ }
+
+ private PolicyValidator nextValidator(@NotNull String name, @NotNull
NodeState beforeState, @NotNull NodeState afterState) {
+ Tree before =
mgrProvider.getTreeProvider().createReadOnlyTree(verifyNotNull(parentBefore),
name, beforeState);
+ Tree after =
mgrProvider.getTreeProvider().createReadOnlyTree(verifyNotNull(parentAfter),
name, afterState);
+ return new PolicyValidator(this, before, after);
+ }
+
+ private PolicyValidator nextValidator(@NotNull String name, @NotNull
NodeState nodeState, boolean isAfter) {
+ Tree parent = (isAfter) ? parentAfter : parentBefore;
+ Tree tree =
mgrProvider.getTreeProvider().createReadOnlyTree(verifyNotNull(parent), name,
nodeState);
+ return new PolicyValidator(this, tree, isAfter);
+ }
+
+ @NotNull
+ private Tree verifyNotNull(@Nullable Tree tree) {
+ checkState(tree != null);
+ return tree;
+ }
+ }
+}
Propchange:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/PrincipalPolicyValidatorProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/Utils.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/Utils.java?rev=1857551&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/Utils.java
(added)
+++
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/Utils.java
Mon Apr 15 07:16:49 2019
@@ -0,0 +1,124 @@
+/*
+ * 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.spi.security.authorization.principalbased.impl;
+
+import com.google.common.base.Predicates;
+import com.google.common.base.Strings;
+import com.google.common.collect.Collections2;
+import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
+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.authorization.principalbased.Filter;
+import org.apache.jackrabbit.oak.spi.xml.ImportBehavior;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.Privilege;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.Set;
+
+final class Utils implements Constants {
+
+ private static final Logger log = LoggerFactory.getLogger(Utils.class);
+
+ private Utils() {}
+
+ /**
+ * Returns {@code true} if the given tree exists and represents a valid
principal policy node, i.e. name equals to
+ * {@link #REP_PRINCIPAL_POLICY} and primary type name equals to {@link
#NT_REP_PRINCIPAL_POLICY}. Otherwise this
+ * method returns {@code false}.
+ *
+ * @param tree The tree to be tested.
+ * @return {@code true} if the given tree exists and represents a valid
principal policy node, i.e. name equals to
+ * {@link #REP_PRINCIPAL_POLICY} and primary type name equals to {@link
#NT_REP_PRINCIPAL_POLICY}; otherwise
+ * returns {@code false}.
+ */
+ public static boolean isPrincipalPolicyTree(@NotNull Tree tree) {
+ return tree.exists() && REP_PRINCIPAL_POLICY.equals(tree.getName()) &&
NT_REP_PRINCIPAL_POLICY.equals(TreeUtil.getPrimaryTypeName(tree));
+ }
+
+ public static boolean isPrincipalEntry(@NotNull Tree tree) {
+ return
NT_REP_PRINCIPAL_ENTRY.equals(TreeUtil.getPrimaryTypeName(tree));
+ }
+
+ /**
+ * Validate the specified {@code principal} taking the configured
+ * {@link ImportBehavior} into account.
+ *
+ * @param principal The principal to validate.
+ * @return if the principal can be handled by the filter
+ * @throws AccessControlException If the principal has an invalid name or
+ * if {@link ImportBehavior#ABORT} is configured and this principal cannot
be handled by the filter.
+ */
+ public static boolean canHandle(@NotNull Principal principal, @NotNull
Filter filter, int importBehavior) throws AccessControlException {
+ String name = principal.getName();
+ if (Strings.isNullOrEmpty(name)) {
+ throw new AccessControlException("Invalid principal " + name);
+ }
+
+ boolean canHandle = filter.canHandle(Collections.singleton(principal));
+ switch (importBehavior) {
+ case ImportBehavior.ABORT:
+ if (!canHandle) {
+ throw new AccessControlException("Unsupported principal "
+ name);
+ }
+ break;
+ case ImportBehavior.IGNORE:
+ case ImportBehavior.BESTEFFORT:
+ log.debug("Ignoring unsupported principal {}", name);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported import
behavior " + importBehavior);
+ }
+ return canHandle;
+ }
+
+ /**
+ * Returns an array of privileges from the given Oak names. Note that
{@link RepositoryException} thrown by
+ * {@link PrivilegeManager#getPrivilege(String)} will be swallowed but
notified in the error log.
+ *
+ * @param privilegeNames The Oak names of privileges as stored in the
repository.
+ * @param privilegeManager The {@link PrivilegeManager} to retrieve the
privileges.
+ * @param namePathMapper The {@link NamePathMapper} to convert the Oak
names to JCR names.
+ * @return An array of {@link Privilege} for the given names.
+ */
+ public static Privilege[] privilegesFromOakNames(@NotNull Set<String>
privilegeNames, @NotNull PrivilegeManager privilegeManager, @NotNull
NamePathMapper namePathMapper) {
+ return Collections2.filter(Collections2.transform(privilegeNames,
privilegeName -> {
+ try {
+ return
privilegeManager.getPrivilege(namePathMapper.getJcrName(privilegeName));
+ } catch (RepositoryException e) {
+ log.error("Unknown privilege in access control entry : {}",
privilegeName);
+ return null;
+ }
+ }), Predicates.notNull()).toArray(new Privilege[0]);
+ }
+
+ public static boolean hasModAcPermission(@NotNull PermissionProvider
permissionProvider, @NotNull String effectivePath) {
+ if (REPOSITORY_PERMISSION_PATH.equals(effectivePath)) {
+ return
permissionProvider.getRepositoryPermission().isGranted(Permissions.MODIFY_ACCESS_CONTROL);
+ } else {
+ return permissionProvider.isGranted(effectivePath,
Permissions.getString(Permissions.MODIFY_ACCESS_CONTROL));
+ }
+ }
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/Utils.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/package-info.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/package-info.java?rev=1857551&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/package-info.java
(added)
+++
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/package-info.java
Mon Apr 15 07:16:49 2019
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+@Version("1.0.0")
+package org.apache.jackrabbit.oak.spi.security.authorization.principalbased;
+
+import org.osgi.annotation.versioning.Version;
Propchange:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/package-info.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/resources/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/nodetypes.cnd
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/resources/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/nodetypes.cnd?rev=1857551&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/resources/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/nodetypes.cnd
(added)
+++
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/resources/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/nodetypes.cnd
Mon Apr 15 07:16:49 2019
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+<rep='internal'>
+<jcr='http://www.jcp.org/jcr/1.0'>
+<nt='http://www.jcp.org/jcr/nt/1.0'>
+<mix='http://www.jcp.org/jcr/mix/1.0'>
+<oak='http://jackrabbit.apache.org/oak/ns/1.0'>
+
+//
-----------------------------------------------------------------------------
+// Authorization: Principal Based
+//
-----------------------------------------------------------------------------
+/**
+ * @since oak 1.14
+ */
+[rep:PrincipalBasedMixin]
+ mixin
+ + rep:principalPolicy (rep:PrincipalPolicy) protected IGNORE
+
+/**
+ * @since oak 1.14
+ */
+[rep:PrincipalPolicy] > rep:Policy
+ orderable
+ - rep:principalName (STRING) protected mandatory IGNORE
+ + * (rep:PrincipalEntry) = rep:PrincipalEntry protected IGNORE
+
+/**
+ * @since oak 1.14
+ */
+[rep:PrincipalEntry]
+ - rep:effectivePath (PATH) protected mandatory
+ - rep:privileges (NAME) multiple protected mandatory multiple
+ + rep:restrictions (rep:Restrictions) = rep:Restrictions protected
Propchange:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/main/resources/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/nodetypes.cnd
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java?rev=1857551&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java
(added)
+++
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java
Mon Apr 15 07:16:49 2019
@@ -0,0 +1,227 @@
+/*
+ * 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.spi.security.authorization.principalbased.impl;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.ObjectArrays;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy;
+import org.apache.jackrabbit.api.security.user.User;
+import
org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.namepath.impl.LocalNameMapper;
+import org.apache.jackrabbit.oak.namepath.impl.NamePathMapperImpl;
+import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
+import org.apache.jackrabbit.oak.security.internal.SecurityProviderHelper;
+import org.apache.jackrabbit.oak.spi.mount.Mounts;
+import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
+import
org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
+import
org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
+import
org.apache.jackrabbit.oak.spi.security.authorization.principalbased.FilterProvider;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Before;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.Privilege;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.Map;
+import java.util.UUID;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static
org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.NT_OAK_UNSTRUCTURED;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AbstractPrincipalBasedTest extends AbstractSecurityTest {
+
+ static final String INTERMEDIATE_PATH =
UserConstants.DEFAULT_SYSTEM_RELATIVE_PATH + "/test";
+ static final String SUPPORTED_PATH =
PathUtils.concat(UserConstants.DEFAULT_USER_PATH, INTERMEDIATE_PATH);
+
+ static final String TEST_OAK_PATH =
"/oak:content/child/grandchild/oak:subtree";
+
+ static final Map<String, String> LOCAL_NAME_MAPPINGS = ImmutableMap.of(
+ "a","internal",
+ "b","http://www.jcp.org/jcr/1.0",
+ "c","http://jackrabbit.apache.org/oak/ns/1.0"
+ );
+
+ private User testSystemUser;
+ private MgrProvider mgrProvider;
+ private PrincipalBasedAuthorizationConfiguration
principalBasedAuthorizationConfiguration;
+
+ String testJcrPath;
+ String testContentJcrPath;
+
+ @Before
+ public void before() throws Exception {
+ super.before();
+ namePathMapper = new NamePathMapperImpl(new LocalNameMapper(root,
LOCAL_NAME_MAPPINGS));
+ testJcrPath = getNamePathMapper().getJcrPath(TEST_OAK_PATH);
+ testContentJcrPath = PathUtils.getAncestorPath(testJcrPath, 3);
+ }
+
+ @Override
+ public void after() throws Exception {
+ try {
+ root.refresh();
+ if (testSystemUser != null) {
+ testSystemUser.remove();
+ root.commit();
+ }
+ } finally {
+ super.after();
+ }
+ }
+
+ @Override
+ @NotNull
+ protected SecurityProvider initSecurityProvider() {
+ SecurityProvider sp = super.initSecurityProvider();
+ principalBasedAuthorizationConfiguration = new
PrincipalBasedAuthorizationConfiguration();
+
principalBasedAuthorizationConfiguration.bindFilterProvider(getFilterProvider());
+
principalBasedAuthorizationConfiguration.bindMountInfoProvider(Mounts.defaultMountInfoProvider());
+ SecurityProviderHelper.updateConfig(sp,
principalBasedAuthorizationConfiguration, AuthorizationConfiguration.class);
+ return sp;
+ }
+
+ @Override
+ @NotNull
+ protected Privilege[] privilegesFromNames(@NotNull String...
privilegeNames) throws RepositoryException {
+ Iterable<String> pn =
Iterables.transform(ImmutableSet.copyOf(privilegeNames), privName ->
getNamePathMapper().getJcrName(privName));
+ return super.privilegesFromNames(pn);
+ }
+
+ @NotNull
+ User getTestSystemUser() throws Exception {
+ if (testSystemUser == null) {
+ String uid = "testSystemUser" + UUID.randomUUID();
+ testSystemUser = getUserManager(root).createSystemUser(uid,
INTERMEDIATE_PATH);
+ root.commit();
+ }
+ return testSystemUser;
+
+ }
+
+ void setupContentTrees(@NotNull String oakPath) throws Exception {
+ setupContentTrees(NT_OAK_UNSTRUCTURED, oakPath);
+ }
+
+ void setupContentTrees(@NotNull String ntName, @NotNull String...
oakPaths) throws Exception {
+ Tree rootTree = root.getTree(PathUtils.ROOT_PATH);
+ for (String absPath : oakPaths) {
+ Tree t = rootTree;
+ for (String element : PathUtils.elements(absPath)) {
+ t = TreeUtil.getOrAddChild(t, element, ntName);
+ }
+ }
+ }
+
+ @NotNull
+ PrincipalPolicyImpl getPrincipalPolicyImpl(@NotNull Principal
testPrincipal, @NotNull JackrabbitAccessControlManager acMgr) throws Exception {
+ for (JackrabbitAccessControlPolicy policy :
ObjectArrays.concat(acMgr.getApplicablePolicies(testPrincipal),
acMgr.getPolicies(testPrincipal), JackrabbitAccessControlPolicy.class)) {
+ if (policy instanceof PrincipalPolicyImpl) {
+ return (PrincipalPolicyImpl) policy;
+ }
+ }
+ throw new IllegalStateException("unable to obtain
PrincipalPolicyImpl");
+ }
+
+ @NotNull
+ PrincipalPolicyImpl setupPrincipalBasedAccessControl(@NotNull Principal
testPrincipal, @Nullable String effectivePath, @NotNull String... privNames)
throws Exception {
+ // set principal-based policy for 'testPrincipal'
+ JackrabbitAccessControlManager jacm = getAccessControlManager(root);
+ PrincipalPolicyImpl policy = getPrincipalPolicyImpl(testPrincipal,
jacm);
+ policy.addEntry(effectivePath, privilegesFromNames(privNames));
+ jacm.setPolicy(policy.getPath(), policy);
+ return policy;
+ }
+
+ boolean addPrincipalBasedEntry(@NotNull PrincipalPolicyImpl policy,
@Nullable String effectivePath, @NotNull String... privNames) throws Exception {
+ boolean mod = policy.addEntry(effectivePath,
privilegesFromNames(privNames));
+ getAccessControlManager(root).setPolicy(policy.getPath(), policy);
+ return mod;
+ }
+
+ boolean addDefaultEntry(@Nullable String path, @NotNull Principal
principal, @NotNull String... privNames) throws Exception {
+ return addDefaultEntry(path, principal, null, null, privNames);
+ }
+
+ boolean addDefaultEntry(@Nullable String path, @NotNull Principal
principal, @Nullable Map<String, Value> restr, @Nullable Map<String, Value[]>
mvRestr, @NotNull String... privNames) throws Exception {
+ JackrabbitAccessControlManager jacm = getAccessControlManager(root);
+ JackrabbitAccessControlList acl =
AccessControlUtils.getAccessControlList(jacm, path);
+ checkNotNull(acl);
+
+ boolean mod = acl.addEntry(principal, privilegesFromNames(privNames),
true, restr, mvRestr);
+ jacm.setPolicy(acl.getPath(), acl);
+ return mod;
+ }
+
+ @NotNull
+ PrincipalBasedPermissionProvider createPermissionProvider(@NotNull Root
root, @NotNull Principal... principals) {
+ PermissionProvider pp =
principalBasedAuthorizationConfiguration.getPermissionProvider(root,
root.getContentSession().getWorkspaceName(), ImmutableSet.copyOf(principals));
+ if (pp instanceof PrincipalBasedPermissionProvider) {
+ return (PrincipalBasedPermissionProvider) pp;
+ } else {
+ throw new IllegalStateException("not a
PrincipalBasedPermissionProvider");
+ }
+ }
+
+ PrincipalBasedAccessControlManager createAccessControlManager(@NotNull
Root root) {
+ AccessControlManager acMgr =
principalBasedAuthorizationConfiguration.getAccessControlManager(root,
getNamePathMapper());
+ if (acMgr instanceof PrincipalBasedAccessControlManager) {
+ return (PrincipalBasedAccessControlManager) acMgr;
+ } else {
+ throw new IllegalStateException("not a
PrincipalBasedAccessControlManager");
+ }
+ }
+
+ @NotNull
+ FilterProvider getFilterProvider() {
+ return createFilterProviderImpl(SUPPORTED_PATH);
+ }
+
+ @NotNull
+ static FilterProviderImpl createFilterProviderImpl(@NotNull final String
path) {
+ FilterProviderImpl fp = new FilterProviderImpl();
+
fp.activate(when(mock(FilterProviderImpl.Configuration.class).path()).thenReturn(path).getMock(),
Collections.emptyMap());
+ return fp;
+ }
+
+ @NotNull
+ MgrProvider getMgrProvider(Root root) {
+ if (mgrProvider == null) {
+ mgrProvider = new
MgrProviderImpl(principalBasedAuthorizationConfiguration, root,
getNamePathMapper());
+ }
+ return mgrProvider;
+ }
+
+ @NotNull
+ PrincipalBasedAuthorizationConfiguration
getPrincipalBasedAuthorizationConfiguration() {
+ return principalBasedAuthorizationConfiguration;
+ }
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractPrincipalBasedTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractTreePermissionTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractTreePermissionTest.java?rev=1857551&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractTreePermissionTest.java
(added)
+++
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractTreePermissionTest.java
Mon Apr 15 07:16:49 2019
@@ -0,0 +1,145 @@
+/*
+ * 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.spi.security.authorization.principalbased.impl;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.plugins.tree.TreeType;
+import
org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.jetbrains.annotations.NotNull;
+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.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+public class AbstractTreePermissionTest {
+
+ private Tree tree;
+ private PrincipalBasedPermissionProvider pp;
+
+ @Before
+ public void before() {
+ tree = mock(Tree.class);
+ pp = mock(PrincipalBasedPermissionProvider.class);
+
+ }
+
+ private AbstractTreePermission createAbstractTreePermission(@NotNull Tree
tree, @NotNull TreeType type, @NotNull PrincipalBasedPermissionProvider pp) {
+ return new AbstractTreePermission(tree, type) {
+ @Override
+ PrincipalBasedPermissionProvider getPermissionProvider() {
+ return pp;
+ }
+ };
+ }
+
+ @Test
+ public void testGetTree() {
+ AbstractTreePermission atp = createAbstractTreePermission(tree,
TreeType.DEFAULT, pp);
+ assertEquals(tree, atp.getTree());
+ }
+
+ @Test
+ public void testGetType() {
+ AbstractTreePermission atp = createAbstractTreePermission(tree,
TreeType.INTERNAL, pp);
+ assertSame(TreeType.INTERNAL, atp.getType());
+ }
+
+ @Test
+ public void testGetChildPermission() {
+ NodeState childState = mock(NodeState.class);
+ AbstractTreePermission atp = createAbstractTreePermission(tree,
TreeType.HIDDEN, pp);
+ atp.getChildPermission("childName", childState);
+
+ verify(pp, times(1)).getTreePermission("childName", childState, atp);
+ }
+
+ @Test
+ public void testCanRead() {
+ AbstractTreePermission atp = createAbstractTreePermission(tree,
TreeType.DEFAULT, pp);
+ atp.canRead();
+
+ verify(pp, times(1)).isGranted(tree, null, Permissions.READ_NODE);
+ }
+
+ @Test
+ public void testCanReadAcType() {
+ AbstractTreePermission atp = createAbstractTreePermission(tree,
TreeType.ACCESS_CONTROL, pp);
+ atp.canRead();
+
+ verify(pp, times(1)).isGranted(tree, null,
Permissions.READ_ACCESS_CONTROL);
+ }
+
+ @Test
+ public void testCanReadWithProperty() {
+ PropertyState ps = mock(PropertyState.class);
+
+ AbstractTreePermission atp = createAbstractTreePermission(tree,
TreeType.VERSION, pp);
+ atp.canRead(ps);
+
+ verify(pp, times(1)).isGranted(tree, ps, Permissions.READ_PROPERTY);
+ }
+
+ @Test
+ public void testCanReadWithPropertyAcType() {
+ PropertyState ps = mock(PropertyState.class);
+
+ AbstractTreePermission atp = createAbstractTreePermission(tree,
TreeType.ACCESS_CONTROL, pp);
+ atp.canRead(ps);
+
+ verify(pp, times(1)).isGranted(tree, ps,
Permissions.READ_ACCESS_CONTROL);
+ }
+
+ @Test
+ public void testCanReadAll() {
+ AbstractTreePermission atp = createAbstractTreePermission(tree,
TreeType.DEFAULT, pp);
+ assertFalse(atp.canReadAll());
+ }
+
+ @Test
+ public void testCanReadProperties() {
+ AbstractTreePermission atp = createAbstractTreePermission(tree,
TreeType.DEFAULT, pp);
+ assertFalse(atp.canReadProperties());
+ }
+
+ @Test
+ public void testIsGranted() {
+ AbstractTreePermission atp = createAbstractTreePermission(tree,
TreeType.ACCESS_CONTROL, pp);
+ atp.isGranted(Permissions.ALL);
+
+ verify(pp, times(1)).isGranted(tree, null, Permissions.ALL);
+ }
+
+ @Test
+ public void testIsGrantedWithProperty() {
+ PropertyState ps = mock(PropertyState.class);
+
+ AbstractTreePermission atp = createAbstractTreePermission(tree,
TreeType.VERSION, pp);
+ atp.isGranted(Permissions.SET_PROPERTY|Permissions.VERSION_MANAGEMENT,
ps);
+
+ verify(pp, times(1)).isGranted(tree, ps,
Permissions.SET_PROPERTY|Permissions.VERSION_MANAGEMENT);
+ verify(pp, never()).isGranted(tree, null,
Permissions.SET_PROPERTY|Permissions.VERSION_MANAGEMENT);
+ }
+
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AbstractTreePermissionTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedSystemUserTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedSystemUserTest.java?rev=1857551&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedSystemUserTest.java
(added)
+++
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedSystemUserTest.java
Mon Apr 15 07:16:49 2019
@@ -0,0 +1,77 @@
+/*
+ * 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.spi.security.authorization.principalbased.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.oak.api.AuthInfo;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.spi.security.authentication.AuthInfoImpl;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Test;
+
+import javax.jcr.AccessDeniedException;
+import javax.security.auth.Subject;
+import java.security.Principal;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collections;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * Tests for PrincipalBasedAccessControlManager where the editing session
(based on a system user with both default and
+ * principal-based permission evaluation) lacks permissions to read/modify
access control on the target system-principal.
+ */
+public class AccessControlManagerLimitedSystemUserTest extends
AccessControlManagerLimitedUserTest {
+
+ private final String UID = "testSystemSession" + UUID.randomUUID();
+
+ @Override
+ public void after() throws Exception {
+ try {
+ Authorizable a = getUserManager(root).getAuthorizable(UID);
+ if (a != null) {
+ a.remove();
+ root.commit();
+ }
+ } finally {
+ super.after();
+ }
+ }
+
+ Principal createTestPrincipal() throws Exception {
+ User testUser = getUserManager(root).createSystemUser(UID,
INTERMEDIATE_PATH);
+ root.commit();
+ return testUser.getPrincipal();
+ }
+
+ Root createTestRoot() throws Exception {
+ Set<Principal> principals = ImmutableSet.of(testPrincipal);
+ AuthInfo authInfo = new AuthInfoImpl(UID, Collections.<String,
Object>emptyMap(), principals);
+ Subject subject = new Subject(true, principals,
ImmutableSet.of(authInfo), ImmutableSet.of());
+ return Subject.doAsPrivileged(subject,
(PrivilegedExceptionAction<Root>) () -> getContentRepository().login(null,
null).getLatestRoot(), null);
+ }
+
+ void grant(@NotNull Principal principal, @Nullable String path, @NotNull
String... privNames) throws Exception {
+ super.grant(principal, path, privNames);
+ setupPrincipalBasedAccessControl(principal, path, privNames);
+ }
+
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedSystemUserTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedUserTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedUserTest.java?rev=1857551&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedUserTest.java
(added)
+++
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedUserTest.java
Mon Apr 15 07:16:49 2019
@@ -0,0 +1,769 @@
+/*
+ * 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.spi.security.authorization.principalbased.impl;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+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.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
+import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
+import
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.ImmutableACL;
+import
org.apache.jackrabbit.oak.spi.security.authorization.principalbased.PrincipalPolicy;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.RepositoryException;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.Privilege;
+import java.security.Principal;
+
+import static
org.apache.jackrabbit.oak.spi.security.authorization.principalbased.impl.Constants.NT_REP_PRINCIPAL_ENTRY;
+import static
org.apache.jackrabbit.oak.spi.security.authorization.principalbased.impl.Constants.REP_EFFECTIVE_PATH;
+import static
org.apache.jackrabbit.oak.spi.security.authorization.principalbased.impl.Constants.REP_PRINCIPAL_POLICY;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for PrincipalBasedAccessControlManager where the editing session
(based on a regular user with default
+ * permission evaluation) lacks permissions to read/modify access control on
the target system-principal.
+ */
+public class AccessControlManagerLimitedUserTest extends
AbstractPrincipalBasedTest implements PrivilegeConstants {
+
+ Principal systemPrincipal;
+ String systemPrincipalPath;
+
+ Principal testPrincipal;
+ Root testRoot;
+ JackrabbitAccessControlManager testAcMgr;
+
+ @Before
+ public void before() throws Exception {
+ super.before();
+
+ User systemUser = getTestSystemUser();
+ systemPrincipalPath = systemUser.getPath();
+ systemPrincipal = getTestSystemUser().getPrincipal();
+
+ testPrincipal = createTestPrincipal();
+
+ setupContentTrees(TEST_OAK_PATH);
+
+ // grant test-user full read access (but not read-access control!)
+ grant(testPrincipal, PathUtils.ROOT_PATH, JCR_READ);
+
+ // trigger creation of principal policy with testPrincipal with 2
random entries
+ PrincipalPolicyImpl policy =
setupPrincipalBasedAccessControl(systemPrincipal, testContentJcrPath,
JCR_NODE_TYPE_MANAGEMENT);
+ addPrincipalBasedEntry(policy, null, JCR_NAMESPACE_MANAGEMENT);
+ root.commit();
+
+ testRoot = createTestRoot();
+ testAcMgr = createAccessControlManager(testRoot);
+ }
+
+ @Override
+ public void after() throws Exception {
+ try {
+ if (testRoot != null) {
+ testRoot.getContentSession().close();
+ }
+ } finally {
+ super.after();
+ }
+ }
+
+ Principal createTestPrincipal() throws Exception {
+ return getTestUser().getPrincipal();
+ }
+
+ Root createTestRoot() throws Exception {
+ User testUser = getTestUser();
+ return login(new SimpleCredentials(testUser.getID(),
testUser.getID().toCharArray())).getLatestRoot();
+ }
+
+ void grant(@NotNull Principal principal, @Nullable String path, @NotNull
String... privNames) throws Exception {
+ addDefaultEntry(path, principal, privNames);
+ }
+
+ private static void assertEmptyPolicies(@NotNull AccessControlPolicy[]
policies) {
+ assertEquals(0, policies.length);
+ }
+
+ private static void assertPolicies(@NotNull AccessControlPolicy[]
policies, Class<? extends JackrabbitAccessControlList> expectedClass, int
expectedSize, int expectedEntrySize) {
+ assertEquals(expectedSize, policies.length);
+ if (expectedSize > 0) {
+ assertTrue(expectedClass.isAssignableFrom(policies[0].getClass()));
+ assertEquals(expectedEntrySize, ((JackrabbitAccessControlList)
policies[0]).size());
+ }
+ }
+
+ private static void assertEntry(@NotNull PrincipalPolicyImpl.EntryImpl
entry, @Nullable String effectivePath, @NotNull PrivilegeBits expectedBits) {
+ assertEquals(expectedBits, entry.getPrivilegeBits());
+ if (effectivePath == null) {
+ assertNull(entry.getEffectivePath());
+ } else {
+ assertEquals(effectivePath, entry.getEffectivePath());
+ }
+ }
+
+ @NotNull
+ private String getPolicyPath() throws Exception {
+ JackrabbitAccessControlPolicy[] policies =
createAccessControlManager(root).getPolicies(systemPrincipal);
+ assertEquals(1, policies.length);
+ return PathUtils.concat(((PrincipalPolicyImpl)
policies[0]).getOakPath(), REP_PRINCIPAL_POLICY);
+ }
+
+ @NotNull
+ private String getEntryPath() throws Exception {
+ Tree policyTree = root.getTree(getPolicyPath());
+ assertTrue(policyTree.exists());
+
+ for (Tree child : policyTree.getChildren()) {
+ if (Utils.isPrincipalEntry(child)) {
+ return child.getPath();
+ }
+ }
+ throw new RepositoryException("unable to locate policy entry");
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testGetApplicableByPath() throws RepositoryException {
+ testAcMgr.getApplicablePolicies(testJcrPath);
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testGetPoliciesByPath() throws RepositoryException {
+ testAcMgr.getPolicies(testJcrPath);
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testGetEffectiveByPathNoAccess() throws RepositoryException {
+ testAcMgr.getEffectivePolicies(testJcrPath);
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testGetEffectiveByNullPath() throws RepositoryException {
+ testAcMgr.getEffectivePolicies((String) null);
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testGetEffectiveByRooyPath() throws RepositoryException {
+ testAcMgr.getEffectivePolicies(PathUtils.ROOT_PATH);
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testGetEffectiveByPathReadAccessControlOnPrincipal() throws
Exception {
+ // grant testuser read-access control on testPrincipal-path but NOT on
effective paths null and /oak:content
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ // since default permission evaluation is in charge for 'testUser' ->
access to full principal policy is now
+ // granted
+ AccessControlPolicy[] effective =
testAcMgr.getEffectivePolicies((String) testJcrPath);
+ assertEquals(1, effective.length);
+ assertTrue(effective[0] instanceof PrincipalPolicyImpl);
+ }
+
+ @Test
+ public void testGetEffectiveByPathMissingReadAccessControlOnPrincipal()
throws Exception {
+ // test-user: granted read-access-control on effective null-path
+ grant(testPrincipal, null, JCR_READ_ACCESS_CONTROL);
+ // test-user: granted read-access-control on effective /oak:content
+ grant(testPrincipal, PathUtils.getAncestorPath(testJcrPath, 3),
JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ assertEmptyPolicies(testAcMgr.getEffectivePolicies((String) null));
+ assertEmptyPolicies(testAcMgr.getEffectivePolicies(testJcrPath));
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testGetApplicableByPrincipalNoAccess() throws
RepositoryException {
+ testAcMgr.getApplicablePolicies(systemPrincipal);
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testGetPoliciesByPrincipalNoAccess() throws
RepositoryException {
+ testAcMgr.getPolicies(systemPrincipal);
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testGetEffectiveByPrincipalNoAccess() throws
RepositoryException {
+ testAcMgr.getEffectivePolicies(ImmutableSet.of(systemPrincipal));
+ }
+
+ @Test
+ public void testGetPoliciesByPrincipal() throws Exception {
+ // grant testuser read-access control on testPrincipal-path but NOT on
effective paths null and /oak:content
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ // no read-ac permission on effective paths
+ assertPolicies(testAcMgr.getPolicies(systemPrincipal),
PrincipalPolicyImpl.class, 1, 2);
+
+ // grant testuser read-access control on /oak:content
+ grant(testPrincipal, testContentJcrPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+ assertPolicies(testAcMgr.getPolicies(systemPrincipal),
PrincipalPolicyImpl.class, 1, 2);
+
+ // additionally grant testuser read-access control on null
+ grant(testPrincipal, null, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+ assertPolicies(testAcMgr.getPolicies(systemPrincipal),
PrincipalPolicyImpl.class, 1, 2);
+ }
+
+ @Test
+ public void testGetEffectiveByPrincipal() throws Exception {
+ // grant testuser read-access control on testPrincipal-path but NOT on
effective paths null and /oak:content
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ // read-access-control is only granted for the principalpolicy itself
+
assertPolicies(testAcMgr.getEffectivePolicies(ImmutableSet.of(systemPrincipal)),
ImmutableACL.class, 1, 2);
+
+ // grant testuser read-access control on /oak:content
+ grant(testPrincipal, testContentJcrPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
assertPolicies(testAcMgr.getEffectivePolicies(ImmutableSet.of(systemPrincipal)),
ImmutableACL.class, 1, 2);
+
+ // additionally grant testuser read-access control on null
+ grant(testPrincipal, null, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
assertPolicies(testAcMgr.getEffectivePolicies(ImmutableSet.of(systemPrincipal)),
ImmutableACL.class, 1, 2);
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testSetPolicyMissingModifyAccessControlOnPrincipal() throws
Exception {
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ PrincipalPolicyImpl policy = (PrincipalPolicyImpl)
testAcMgr.getPolicies(systemPrincipal)[0];
+ policy.addEntry(null, privilegesFromNames(JCR_WORKSPACE_MANAGEMENT));
+
+ testAcMgr.setPolicy(policy.getPath(), policy);
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testSetPolicyMissingModifyAccessControlOnEffectivePath()
throws Exception {
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ PrincipalPolicyImpl policy = (PrincipalPolicyImpl)
testAcMgr.getPolicies(systemPrincipal)[0];
+ policy.addEntry(null, privilegesFromNames(JCR_WORKSPACE_MANAGEMENT));
+ policy.addEntry(testJcrPath, privilegesFromNames(JCR_READ));
+
+ testAcMgr.setPolicy(policy.getPath(), policy);
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testSetPolicyMissingModifyAccessControlOnEffectivePath2()
throws Exception {
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ grant(testPrincipal, testContentJcrPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ PrincipalPolicyImpl policy = (PrincipalPolicyImpl)
testAcMgr.getPolicies(systemPrincipal)[0];
+ policy.addEntry(null, privilegesFromNames(JCR_WORKSPACE_MANAGEMENT));
+ policy.addEntry(testJcrPath, privilegesFromNames(JCR_READ));
+
+ testAcMgr.setPolicy(policy.getPath(), policy);
+ }
+
+ @Test
+ public void testSetPolicy() throws Exception {
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ grant(testPrincipal, testContentJcrPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ grant(testPrincipal, null, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ PrincipalPolicyImpl policy = (PrincipalPolicyImpl)
testAcMgr.getPolicies(systemPrincipal)[0];
+ policy.addEntry(null, privilegesFromNames(JCR_WORKSPACE_MANAGEMENT));
+ policy.addEntry(testJcrPath, privilegesFromNames(JCR_READ));
+
+ testAcMgr.setPolicy(policy.getPath(), policy);
+ testRoot.commit();
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testRemovePolicyMissingModifyAccessControlOnPrincipal() throws
Exception {
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ PrincipalPolicyImpl policy = (PrincipalPolicyImpl)
testAcMgr.getPolicies(systemPrincipal)[0];
+ testAcMgr.removePolicy(policy.getPath(), policy);
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testRemovePolicyMissingModifyAccessControlOnEffectivePath()
throws Exception {
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ PrincipalPolicyImpl policy = (PrincipalPolicyImpl)
testAcMgr.getPolicies(systemPrincipal)[0];
+ testAcMgr.removePolicy(policy.getPath(), policy);
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testRemovePolicyMissingModifyAccessControlOnEffectivePath2()
throws Exception {
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ grant(testPrincipal, testContentJcrPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ PrincipalPolicyImpl policy = (PrincipalPolicyImpl)
testAcMgr.getPolicies(systemPrincipal)[0];
+ testAcMgr.removePolicy(policy.getPath(), policy);
+ }
+
+ @Test
+ public void testRemovePolicy() throws Exception {
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ grant(testPrincipal, null, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ grant(testPrincipal, testContentJcrPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ PrincipalPolicyImpl policy = (PrincipalPolicyImpl)
testAcMgr.getPolicies(systemPrincipal)[0];
+ testAcMgr.removePolicy(policy.getPath(), policy);
+ testRoot.commit();
+ }
+
+ @Test
+ public void testRemovePolicyWithNonEntryChild() throws Exception {
+ // clear all entries from policy
+ PrincipalPolicyImpl policy = getPrincipalPolicyImpl(systemPrincipal,
getAccessControlManager(root));
+ for (AccessControlEntry entry : policy.getAccessControlEntries()) {
+ policy.removeAccessControlEntry(entry);
+ }
+ getAccessControlManager(root).setPolicy(policy.getPath(), policy);
+ // grant permission to read/modify policy
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ // transiently add non-entry tree
+ Tree policyTree = testRoot.getTree(getPolicyPath());
+ assertFalse(policyTree.getChildren().iterator().hasNext());
+ TreeUtil.addChild(policyTree, "nonEntry",
NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+
+ policy = getPrincipalPolicyImpl(systemPrincipal, testAcMgr);
+ testAcMgr.removePolicy(policy.getPath(), policy);
+ testRoot.commit();
+ }
+
+ @Test(expected = AccessControlException.class)
+ public void testRemovePolicyMissingEffectivePaths() throws Exception {
+ // grant permission to read/modify policy
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ // first read policy
+ PrincipalPolicyImpl policy = getPrincipalPolicyImpl(systemPrincipal,
testAcMgr);
+
+ // transiently remove rep:effectivePath properties from all entries.
+ Tree policyTree = testRoot.getTree(getPolicyPath());
+ for (Tree child : policyTree.getChildren()) {
+ child.removeProperty(REP_EFFECTIVE_PATH);
+ }
+
+ // removing policy must fail, because effective paths cannot be
evaluated
+ testAcMgr.removePolicy(policy.getPath(), policy);
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testHasPrivilegeSystemUser() throws Exception {
+ // test session has no access
+ testAcMgr.hasPrivileges(testContentJcrPath,
ImmutableSet.of(systemPrincipal),
privilegesFromNames(JCR_NODE_TYPE_MANAGEMENT));
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testHasPrivilegeSystemUserWithPartialReadAc() throws Exception
{
+ // grant read-ac access on principal policy (but not on targetPath)
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ testAcMgr.hasPrivileges(testContentJcrPath,
ImmutableSet.of(systemPrincipal),
privilegesFromNames(JCR_NODE_TYPE_MANAGEMENT));
+ }
+
+ @Test
+ public void testHasPrivilegeSystemUserWithPartialReadAc2() throws
Exception {
+ // grant read-ac access on effective path -> no entries accessible
+ grant(testPrincipal, testContentJcrPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ assertFalse(testAcMgr.hasPrivileges(testContentJcrPath,
ImmutableSet.of(systemPrincipal),
privilegesFromNames(JCR_NODE_TYPE_MANAGEMENT)));
+ }
+
+ @Test
+ public void testHasPrivilegeSystemUserWithReadAc() throws Exception {
+ // grant read-ac access on effective path and on principal policy
+ grant(testPrincipal, testContentJcrPath, JCR_READ_ACCESS_CONTROL);
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ // default model lacks jcr:nodeTypeManagement privilege -> not granted
+ assertFalse(testAcMgr.hasPrivileges(testContentJcrPath,
ImmutableSet.of(systemPrincipal),
privilegesFromNames(JCR_NODE_TYPE_MANAGEMENT)));
+
+ addDefaultEntry(testContentJcrPath, systemPrincipal, JCR_READ,
JCR_NODE_TYPE_MANAGEMENT);
+ root.commit();
+ testRoot.refresh();
+
+ // once default model grants permissions as well -> granted
+ assertTrue(testAcMgr.hasPrivileges(testContentJcrPath,
ImmutableSet.of(systemPrincipal),
privilegesFromNames(JCR_NODE_TYPE_MANAGEMENT)));
+
+ // but combination read/nt-mgt is not granted because jcr:read is
missing on principal-based setup.
+ assertFalse(testAcMgr.hasPrivileges(testContentJcrPath,
ImmutableSet.of(systemPrincipal), privilegesFromNames(JCR_READ,
JCR_NODE_TYPE_MANAGEMENT)));
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testGetPrivilegeSystemUser() throws Exception {
+ // test session has no access
+ testAcMgr.getPrivileges(null, ImmutableSet.of(systemPrincipal));
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void testGetPrivilegeSystemUserWithPartialReadAc() throws Exception
{
+ // grant read ac on principal policy but not on target path
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ testAcMgr.getPrivileges(null, ImmutableSet.of(systemPrincipal));
+ }
+
+ @Test
+ public void testGetPrivilegeSystemUserWithPartialReadAc2() throws
Exception {
+ // grant read-ac access on target path (but not on principal policy)
+ grant(testPrincipal, null, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ assertEquals(0, testAcMgr.getPrivileges(null,
ImmutableSet.of(systemPrincipal)).length);
+ }
+
+ @Test
+ public void testGetPrivilegeSystemUserWithWithReadAc() throws Exception {
+ // grant read-ac access on effective path and on principal policy
+ grant(testPrincipal, null, JCR_READ_ACCESS_CONTROL);
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ // default model lacks jcr:nodeTypeManagement privilege -> not granted
+ assertArrayEquals(new Privilege[0], testAcMgr.getPrivileges(null,
ImmutableSet.of(systemPrincipal)));
+
+ addDefaultEntry(null, systemPrincipal, JCR_NAMESPACE_MANAGEMENT,
REP_PRIVILEGE_MANAGEMENT);
+ root.commit();
+ testRoot.refresh();
+
+ // once default model grants namespace-mgt privilege as well -> granted
+ // but not rep:privilegeMgt because the principal-based model doesn't
grant that one
+ assertArrayEquals(privilegesFromNames(JCR_NAMESPACE_MANAGEMENT),
testAcMgr.getPrivileges(null, ImmutableSet.of(systemPrincipal)));
+ }
+
+ @Test
+ public void testReadPolicyTree() throws Exception {
+ Tree policyTree = testRoot.getTree(getPolicyPath());
+ assertNotNull(policyTree);
+ assertFalse(policyTree.exists());
+ }
+
+ @Test
+ public void testReadPolicyTreeWithReadAc() throws Exception {
+ // grant read-ac access and check again
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ Tree policyTree = testRoot.getTree(getPolicyPath());
+ assertNotNull(policyTree);
+ assertTrue(policyTree.exists());
+ }
+
+ @Test
+ public void testReadEntryTree() throws Exception {
+ Tree entryTree = testRoot.getTree(getEntryPath());
+ assertNotNull(entryTree);
+ assertFalse(entryTree.exists());
+ }
+
+ @Test
+ public void testReadEntryTreeWithReadAc() throws Exception {
+ // grant read-ac access and check again
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ Tree entryTree = testRoot.getTree(getEntryPath());
+ assertNotNull(entryTree);
+ assertTrue(entryTree.exists());
+ }
+
+ @Test(expected = CommitFailedException.class)
+ public void testAddEntryTree() throws Exception {
+ // grant read-ac access on principal policy
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ try {
+ Tree policyTree = testRoot.getTree(getPolicyPath());
+ Tree entry = TreeUtil.addChild(policyTree, "entry",
NT_REP_PRINCIPAL_ENTRY);
+ entry.setProperty(REP_EFFECTIVE_PATH, TEST_OAK_PATH, Type.PATH);
+ entry.setProperty(Constants.REP_PRIVILEGES,
ImmutableList.of(JCR_ADD_CHILD_NODES), Type.NAMES);
+ testRoot.commit();
+ } catch (CommitFailedException e) {
+ assertEquals(CommitFailedException.ACCESS, e.getType());
+ assertEquals(3, e.getCode());
+ throw e;
+ }
+ }
+
+ @Test(expected = CommitFailedException.class)
+ public void testAddEntryTreeModAcOnSystemPrincipal() throws Exception {
+ // grant read-ac + mod-ac access on principal policy
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ try {
+ Tree policyTree = testRoot.getTree(getPolicyPath());
+ Tree entry = TreeUtil.addChild(policyTree, "entry",
NT_REP_PRINCIPAL_ENTRY);
+ entry.setProperty(REP_EFFECTIVE_PATH, TEST_OAK_PATH, Type.PATH);
+ entry.setProperty(Constants.REP_PRIVILEGES,
ImmutableList.of(JCR_ADD_CHILD_NODES), Type.NAMES);
+ testRoot.commit();
+ } catch (CommitFailedException e) {
+ assertEquals(CommitFailedException.ACCESS, e.getType());
+ assertEquals(3, e.getCode());
+ throw e;
+ }
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testAddEntryTreeModAcOnEffectivePath() throws Exception {
+ // grant read-ac + mod-ac access on effective path only -> cannot read
principal policy
+ grant(testPrincipal, testJcrPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ Tree policyTree = testRoot.getTree(getPolicyPath());
+ Tree entry = TreeUtil.addChild(policyTree, "entry",
NT_REP_PRINCIPAL_ENTRY);
+
+ }
+
+ @Test
+ public void testAddEntryTreeFullModAc() throws Exception {
+ grant(testPrincipal, testJcrPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ Tree policyTree = testRoot.getTree(getPolicyPath());
+ Tree entry = TreeUtil.addChild(policyTree, "entry",
NT_REP_PRINCIPAL_ENTRY);
+ entry.setProperty(REP_EFFECTIVE_PATH, TEST_OAK_PATH, Type.PATH);
+ entry.setProperty(Constants.REP_PRIVILEGES,
ImmutableList.of(JCR_ADD_CHILD_NODES), Type.NAMES);
+ testRoot.commit();
+ }
+
+ @Test(expected = CommitFailedException.class)
+ public void testRemovePolicyTree() throws Exception {
+ // grant read-ac access on principal policy
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ try {
+ testRoot.getTree(getPolicyPath()).remove();
+ testRoot.commit();
+ } catch (CommitFailedException e) {
+ assertEquals(CommitFailedException.ACCESS, e.getType());
+ assertEquals(0, e.getCode());
+ throw e;
+ }
+ }
+
+ @Test(expected = CommitFailedException.class)
+ public void testRemovePolicyTreeWithModAcOnSystemPrincipal() throws
Exception {
+ // grant read-ac + mod-ac access on principal policy but not on target
paths
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ try {
+ testRoot.getTree(getPolicyPath()).remove();
+ testRoot.commit();
+ } catch (CommitFailedException e) {
+ assertEquals(CommitFailedException.ACCESS, e.getType());
+ assertEquals(3, e.getCode());
+ throw e;
+ }
+ }
+
+ @Test(expected = CommitFailedException.class)
+ public void testRemovePolicyTreeWithModAcOnOneEffectivePath() throws
Exception {
+ // grant read-ac + mod-ac access on principal policy and on
testcontent target paths (but not on null path)
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ grant(testPrincipal, testContentJcrPath, JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ try {
+ testRoot.getTree(getPolicyPath()).remove();
+ testRoot.commit();
+ } catch (CommitFailedException e) {
+ assertEquals(CommitFailedException.ACCESS, e.getType());
+ assertEquals(3, e.getCode());
+ throw e;
+ }
+ }
+
+ @Test(expected = CommitFailedException.class)
+ public void testRemovePolicyTreeWithModAcOnOneEffectivePath2() throws
Exception {
+ // grant read-ac + mod-ac access on principal policy and on nul target
paths (but not on testcontent path)
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ grant(testPrincipal, null, JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ try {
+ testRoot.getTree(getPolicyPath()).remove();
+ testRoot.commit();
+ } catch (CommitFailedException e) {
+ assertEquals(CommitFailedException.ACCESS, e.getType());
+ assertEquals(3, e.getCode());
+ throw e;
+ }
+ }
+
+ @Test(expected = CommitFailedException.class)
+ public void testRemoveEmptyPolicyTree() throws Exception {
+ PrincipalPolicy policy = getPrincipalPolicyImpl(systemPrincipal,
getAccessControlManager(root));
+ for (AccessControlEntry entry : ((PrincipalPolicyImpl)
policy).getEntries()) {
+ policy.removeAccessControlEntry(entry);
+ }
+ getAccessControlManager(root).setPolicy(policy.getPath(), policy);
+ // grant permission to read policy
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+
+ root.commit();
+ testRoot.refresh();
+
+ Tree policyTree = testRoot.getTree(getPolicyPath());
+ assertTrue(policyTree.exists());
+ policyTree.remove();
+ testRoot.commit();
+ }
+
+ @Test(expected = CommitFailedException.class)
+ public void testRemoveEntryTree() throws Exception {
+ // grant read-ac access on principal policy
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ try {
+ testRoot.getTree(getEntryPath()).remove();
+ testRoot.commit();
+ } catch (CommitFailedException e) {
+ assertEquals(CommitFailedException.ACCESS, e.getType());
+ assertEquals(3, e.getCode());
+ throw e;
+ }
+ }
+
+ @Test(expected = CommitFailedException.class)
+ public void testRemoveEntryTreeModAcOnSystemPrincipal() throws Exception {
+ // grant read-ac + mod-ac access on principal policy but not on target
path
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ try {
+ testRoot.getTree(getEntryPath()).remove();
+ testRoot.commit();
+ } catch (CommitFailedException e) {
+ assertEquals(CommitFailedException.ACCESS, e.getType());
+ assertEquals(3, e.getCode());
+ throw e;
+ }
+ }
+
+ @Test(expected = CommitFailedException.class)
+ public void testRemoveEntryTreeModAcOnEffectivePath() throws Exception {
+ // grant read-ac on principal policy but not mod-ac
+ // on target path grant mod-ac
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL);
+ grant(testPrincipal, testContentJcrPath, JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ try {
+ testRoot.getTree(getEntryPath()).remove();
+ testRoot.commit();
+ } catch (CommitFailedException e) {
+ assertEquals(CommitFailedException.ACCESS, e.getType());
+ assertEquals(0, e.getCode());
+ throw e;
+ }
+ }
+
+ @Test
+ public void testRemoveEntryTreeFullModAc() throws Exception {
+ // grant read-ac and mod-ac on principal policy
+ // on target path grant mod-ac
+ grant(testPrincipal, systemPrincipalPath, JCR_READ_ACCESS_CONTROL,
JCR_MODIFY_ACCESS_CONTROL);
+ grant(testPrincipal, testContentJcrPath, JCR_MODIFY_ACCESS_CONTROL);
+ root.commit();
+ testRoot.refresh();
+
+ testRoot.getTree(getEntryPath()).remove();
+ testRoot.commit();
+ }
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-authorization-principalbased/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/principalbased/impl/AccessControlManagerLimitedUserTest.java
------------------------------------------------------------------------------
svn:eol-style = native