blob: bbb3329137d4202c692d3c057e3155a885a97171 [file] [log] [blame]
/*
* 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.ImmutableSet;
import org.apache.jackrabbit.guava.common.collect.Iterables;
import org.apache.jackrabbit.guava.common.collect.Iterators;
import org.apache.jackrabbit.guava.common.collect.Sets;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
import org.apache.jackrabbit.oak.api.ContentSession;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
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.junit.Before;
import org.junit.Test;
import javax.jcr.AccessDeniedException;
import javax.jcr.PathNotFoundException;
import javax.jcr.security.AccessControlPolicy;
import javax.jcr.security.Privilege;
import javax.security.auth.Subject;
import java.security.Principal;
import java.security.PrivilegedExceptionAction;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import static org.apache.jackrabbit.oak.commons.PathUtils.ROOT_PATH;
import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_READ;
import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_READ_NODES;
import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_READ_PROPERTIES;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class ReadablePathsAccessControlTest extends AbstractPrincipalBasedTest {
private Principal testPrincipal;
private Iterator<String> readablePaths;
private Iterator<String> readableChildPaths;
private JackrabbitAccessControlManager acMgr;
@Before
public void before() throws Exception {
super.before();
acMgr = new PrincipalBasedAccessControlManager(getMgrProvider(root), getFilterProvider());
testPrincipal = getTestSystemUser().getPrincipal();
Set<String> paths = getConfig(AuthorizationConfiguration.class).getParameters().getConfigValue(PermissionConstants.PARAM_READ_PATHS, PermissionConstants.DEFAULT_READ_PATHS);
assertFalse(paths.isEmpty());
readablePaths = Iterators.cycle(Iterables.transform(paths, f -> getNamePathMapper().getJcrPath(f)));
Set<String> childPaths = Sets.newHashSet();
for (String path : paths) {
Iterables.addAll(childPaths, Iterables.transform(root.getTree(path).getChildren(), tree -> getNamePathMapper().getJcrPath(tree.getPath())));
}
readableChildPaths = Iterators.cycle(childPaths);
}
private Subject getTestSubject() {
return new Subject(true, Collections.singleton(testPrincipal), ImmutableSet.of(), ImmutableSet.of());
}
@Test
public void testHasPrivilege() throws Exception {
try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), (PrivilegedExceptionAction<ContentSession>) () -> getContentRepository().login(null, null), null)) {
PrincipalBasedAccessControlManager testAcMgr = new PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), getFilterProvider());
Set<Principal> principals = Collections.singleton(testPrincipal);
assertTrue(testAcMgr.hasPrivileges(readablePaths.next(), principals, privilegesFromNames(JCR_READ)));
assertTrue(testAcMgr.hasPrivileges(readablePaths.next(), principals, privilegesFromNames(REP_READ_PROPERTIES)));
assertTrue(testAcMgr.hasPrivileges(readableChildPaths.next(), principals, privilegesFromNames(REP_READ_NODES)));
assertTrue(testAcMgr.hasPrivileges(readableChildPaths.next(), principals, privilegesFromNames(REP_READ_NODES, REP_READ_PROPERTIES)));
}
}
@Test
public void testNotHasPrivilege() throws Exception {
try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), (PrivilegedExceptionAction<ContentSession>) () -> getContentRepository().login(null, null), null)) {
PrincipalBasedAccessControlManager testAcMgr = new PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), getFilterProvider());
Set<Principal> principals = Collections.singleton(testPrincipal);
assertFalse(testAcMgr.hasPrivileges(readablePaths.next(), principals, privilegesFromNames(JCR_READ, PrivilegeConstants.JCR_READ_ACCESS_CONTROL)));
assertFalse(testAcMgr.hasPrivileges(readablePaths.next(), principals, privilegesFromNames(PrivilegeConstants.JCR_ALL)));
assertFalse(testAcMgr.hasPrivileges(readableChildPaths.next(), principals, privilegesFromNames(REP_READ_NODES, PrivilegeConstants.JCR_MODIFY_PROPERTIES)));
assertFalse(testAcMgr.hasPrivileges(readableChildPaths.next(), principals, privilegesFromNames(REP_READ_NODES, REP_READ_PROPERTIES, PrivilegeConstants.JCR_NAMESPACE_MANAGEMENT)));
}
}
@Test
public void testHasPrivilegePrincipal() throws Exception {
Set<Principal> principals = Collections.singleton(testPrincipal);
assertTrue(acMgr.hasPrivileges(readablePaths.next(), principals, privilegesFromNames(JCR_READ)));
assertTrue(acMgr.hasPrivileges(readablePaths.next(), principals, privilegesFromNames(REP_READ_PROPERTIES)));
assertTrue(acMgr.hasPrivileges(readableChildPaths.next(), principals, privilegesFromNames(REP_READ_NODES)));
assertTrue(acMgr.hasPrivileges(readableChildPaths.next(), principals, privilegesFromNames(REP_READ_NODES, REP_READ_PROPERTIES)));
}
@Test
public void testNotHasPrivilegePrincipal() throws Exception {
Set<Principal> principals = Collections.singleton(testPrincipal);
assertFalse(acMgr.hasPrivileges(readablePaths.next(), principals, privilegesFromNames(JCR_READ, PrivilegeConstants.JCR_MODIFY_PROPERTIES)));
assertFalse(acMgr.hasPrivileges(readablePaths.next(), principals, privilegesFromNames(PrivilegeConstants.JCR_ALL)));
assertFalse(acMgr.hasPrivileges(readableChildPaths.next(), principals, privilegesFromNames(REP_READ_NODES, PrivilegeConstants.JCR_READ_ACCESS_CONTROL)));
assertFalse(acMgr.hasPrivileges(readableChildPaths.next(), principals, privilegesFromNames(PrivilegeConstants.JCR_VERSION_MANAGEMENT, REP_READ_PROPERTIES)));
assertFalse(acMgr.hasPrivileges(ROOT_PATH, principals, privilegesFromNames(JCR_READ)));
String systemPath = getNamePathMapper().getJcrPath(PathUtils.concat(ROOT_PATH, JcrConstants.JCR_SYSTEM));
assertFalse(acMgr.hasPrivileges(systemPath, principals, privilegesFromNames(REP_READ_PROPERTIES)));
}
@Test
public void testGetPrivileges() throws Exception {
try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), (PrivilegedExceptionAction<ContentSession>) () -> getContentRepository().login(null, null), null)) {
PrincipalBasedAccessControlManager testAcMgr = new PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), getFilterProvider());
Privilege[] expected = privilegesFromNames(JCR_READ);
assertArrayEquals(expected, testAcMgr.getPrivileges(readablePaths.next()));
assertArrayEquals(expected, testAcMgr.getPrivileges(readableChildPaths.next()));
}
}
@Test(expected = PathNotFoundException.class)
public void testGetPrivilegesAtRoot() throws Exception {
try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), (PrivilegedExceptionAction<ContentSession>) () -> getContentRepository().login(null, null), null)) {
PrincipalBasedAccessControlManager testAcMgr = new PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), getFilterProvider());
testAcMgr.getPrivileges(ROOT_PATH);
}
}
@Test
public void testGetPrivilegesByPrincipal() throws Exception {
Privilege[] expected = privilegesFromNames(JCR_READ);
Set<Principal> principals = Collections.singleton(testPrincipal);
assertArrayEquals(expected, acMgr.getPrivileges(readablePaths.next(), principals));
assertArrayEquals(expected, acMgr.getPrivileges(readableChildPaths.next(), principals));
assertEquals(0, acMgr.getPrivileges(ROOT_PATH, principals).length);
assertEquals(0, acMgr.getPrivileges(PathUtils.concat(ROOT_PATH, getNamePathMapper().getJcrName(JcrConstants.JCR_SYSTEM)), principals).length);
}
@Test
public void testGetEffectivePolicies() throws Exception {
AccessControlPolicy[] expected = new AccessControlPolicy[] {ReadPolicy.INSTANCE};
assertArrayEquals(expected, acMgr.getEffectivePolicies(readablePaths.next()));
assertArrayEquals(expected, acMgr.getEffectivePolicies(readableChildPaths.next()));
}
@Test
public void testGetEffectivePoliciesNullPath() throws Exception {
assertEquals(0, acMgr.getEffectivePolicies((String) null).length);
}
@Test(expected = AccessDeniedException.class)
public void testGetEffectivePoliciesLimitedAccess() throws Exception {
try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), (PrivilegedExceptionAction<ContentSession>) () -> getContentRepository().login(null, null), null)) {
PrincipalBasedAccessControlManager testAcMgr = new PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), getFilterProvider());
testAcMgr.getEffectivePolicies(readablePaths.next());
}
}
@Test
public void testGetEffectivePoliciesLimitedAccess2() throws Exception {
String path = readablePaths.next();
setupPrincipalBasedAccessControl(testPrincipal, path, PrivilegeConstants.JCR_READ_ACCESS_CONTROL);
// default: grant read-ac at root node as nodetype/namespace roots cannot have their mixin changed
addDefaultEntry(PathUtils.ROOT_PATH, testPrincipal, PrivilegeConstants.JCR_READ_ACCESS_CONTROL);
root.commit();
// test-session can read-ac at readable path but cannot access principal-based policy
try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), (PrivilegedExceptionAction<ContentSession>) () -> getContentRepository().login(null, null), null)) {
PrincipalBasedAccessControlManager testAcMgr = new PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), getFilterProvider());
Set<AccessControlPolicy> effective = ImmutableSet.copyOf(testAcMgr.getEffectivePolicies(path));
assertEquals(1, effective.size());
assertTrue(effective.contains(ReadPolicy.INSTANCE));
}
}
@Test
public void testGetEffectivePoliciesLimitedAccess3() throws Exception {
String path = readablePaths.next();
setupPrincipalBasedAccessControl(testPrincipal, path, PrivilegeConstants.JCR_READ_ACCESS_CONTROL);
setupPrincipalBasedAccessControl(testPrincipal, getTestSystemUser().getPath(), PrivilegeConstants.JCR_READ, PrivilegeConstants.JCR_READ_ACCESS_CONTROL);
// default: grant read and read-ac at root node to make sure both policies are accessible
addDefaultEntry(PathUtils.ROOT_PATH, testPrincipal, PrivilegeConstants.JCR_READ_ACCESS_CONTROL, PrivilegeConstants.JCR_READ);
root.commit();
// test-session can read-ac at readable path and at principal-based policy
try (ContentSession cs = Subject.doAsPrivileged(getTestSubject(), (PrivilegedExceptionAction<ContentSession>) () -> getContentRepository().login(null, null), null)) {
PrincipalBasedAccessControlManager testAcMgr = new PrincipalBasedAccessControlManager(getMgrProvider(cs.getLatestRoot()), getFilterProvider());
Set<AccessControlPolicy> effective = Sets.newHashSet(testAcMgr.getEffectivePolicies(path));
assertEquals(2, effective.size());
assertTrue(effective.remove(ReadPolicy.INSTANCE));
assertTrue(effective.iterator().next() instanceof ImmutablePrincipalPolicy);
}
}
@Test
public void testGetEffectivePoliciesByPrincipal() throws Exception {
// OAK-10135 : include read-policy in effective policies by principal result
AccessControlPolicy[] effective = acMgr.getEffectivePolicies(Collections.singleton(testPrincipal));
assertEquals(1, effective.length);
assertTrue(effective[0] instanceof ReadPolicy);
}
}