| /* |
| * 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.guava.common.collect.ImmutableList; |
| import org.apache.jackrabbit.guava.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.AuthorizationConfiguration; |
| import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.ImmutableACL; |
| import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.ReadPolicy; |
| import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants; |
| 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 java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| 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.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| /** |
| * 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()); |
| } |
| } |
| |
| @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(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); |
| |
| // make sure test-user has read-accesscontrol permission on any readable-path |
| grant(testPrincipal, PathUtils.ROOT_PATH, JCR_READ_ACCESS_CONTROL); |
| root.commit(); |
| testRoot.refresh(); |
| |
| AccessControlPolicy[] effective = testAcMgr.getEffectivePolicies(ImmutableSet.of(systemPrincipal));; |
| assertPolicies(effective, ImmutableACL.class, 2, 2); |
| assertTrue(effective[1] instanceof ReadPolicy); |
| } |
| |
| @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 { |
| PrincipalPolicyImpl policy = getPrincipalPolicyImpl(systemPrincipal, getAccessControlManager(root)); |
| for (AccessControlEntry entry : 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(); |
| } |
| |
| @Test |
| public void testGetEffectivePrincipalsReadablePaths() throws Exception { |
| Set<String> readablePaths = getConfig(AuthorizationConfiguration.class).getParameters().getConfigValue(PermissionConstants.PARAM_READ_PATHS, PermissionConstants.DEFAULT_READ_PATHS); |
| String[] paths = readablePaths.stream().map(oakPath -> namePathMapper.getJcrPath(oakPath)).distinct().toArray(String[]::new); |
| assertEquals(3, paths.length); |
| |
| // readpolicy must not be included if editing session doesn't have sufficient permission on readable paths. |
| try { |
| getAccessControlManager(testRoot).getEffectivePolicies(Collections.singleton(systemPrincipal), paths); |
| fail("AccessDenied exception expected"); |
| } catch (AccessDeniedException e) { |
| // success |
| } |
| } |
| } |