blob: d49a99a7ff0653a1e6968c78487a183c3895a789 [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.base.Strings;
import org.apache.jackrabbit.guava.common.collect.ImmutableList;
import org.apache.jackrabbit.guava.common.collect.ImmutableMap;
import org.apache.jackrabbit.guava.common.collect.ImmutableSet;
import org.apache.jackrabbit.guava.common.collect.Iterables;
import org.apache.jackrabbit.api.security.authorization.PrincipalAccessControlList;
import org.apache.jackrabbit.api.security.authorization.PrivilegeCollection;
import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
import org.apache.jackrabbit.oak.spi.security.authorization.restriction.Restriction;
import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionDefinition;
import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionDefinitionImpl;
import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
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.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.ValueFormatException;
import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.AccessControlException;
import javax.jcr.security.Privilege;
import java.security.Principal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants.REP_GLOB;
import static org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants.REP_ITEM_NAMES;
import static org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants.REP_NODE_PATH;
import static org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants.REP_SUBTREES;
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_PRIVILEGES;
import static org.apache.jackrabbit.oak.spi.security.authorization.principalbased.impl.Constants.REP_RESTRICTIONS;
import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_ALL;
import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_NAMESPACE_MANAGEMENT;
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.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class PrincipalPolicyImplTest extends AbstractPrincipalBasedTest {
private static final String TEST_OAK_PATH = "/oak:test";
private static final String POLICY_OAK_PATH = SUPPORTED_PATH + "/oak:testPath";
private Principal principal;
private String testJcrPath;
private String policyJcrPath;
private PrincipalPolicyImpl emptyPolicy;
private PrincipalPolicyImpl policy;
private PrivilegeBitsProvider privilegeBitsProvider;
@Before
public void before() throws Exception {
super.before();
testJcrPath = getNamePathMapper().getJcrPath(TEST_OAK_PATH);
policyJcrPath = getNamePathMapper().getJcrPath(POLICY_OAK_PATH);
principal = new PrincipalImpl("principalName");
emptyPolicy = createPolicy(POLICY_OAK_PATH);
policy = createPolicy(POLICY_OAK_PATH);
policy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_NODE_TYPE_MANAGEMENT, PrivilegeConstants.REP_WRITE));
policy.addEntry(null, privilegesFromNames(PrivilegeConstants.JCR_NODE_TYPE_DEFINITION_MANAGEMENT));
privilegeBitsProvider = new PrivilegeBitsProvider(root);
}
private PrincipalPolicyImpl createPolicy(@NotNull String oakPath) {
return new PrincipalPolicyImpl(principal, oakPath, getMgrProvider(root));
}
private Tree createEntryTree(@NotNull PrincipalPolicyImpl.EntryImpl entry) {
Tree t = mock(Tree.class);
PropertyState path = PropertyStates.createProperty(REP_EFFECTIVE_PATH, Strings.nullToEmpty(entry.getOakPath()));
when(t.getProperty(REP_EFFECTIVE_PATH)).thenReturn(path);
PropertyState privs = PropertyStates.createProperty(REP_PRIVILEGES, privilegeBitsProvider.getPrivilegeNames(entry.getPrivilegeBits()), Type.NAMES);
when(t.getProperty(REP_PRIVILEGES)).thenReturn(privs);
Iterable props = Iterables.transform(entry.getRestrictions(), Restriction::getProperty);
Tree rTree = mock(Tree.class);
if (props.iterator().hasNext()) {
when(rTree.exists()).thenReturn(true);
when(rTree.getProperties()).thenReturn(props);
when(t.hasChild(REP_RESTRICTIONS)).thenReturn(true);
when(t.getChild(REP_RESTRICTIONS)).thenReturn(rTree);
} else {
when(rTree.exists()).thenReturn(false);
when(t.hasChild(REP_RESTRICTIONS)).thenReturn(false);
when(t.getChild(REP_RESTRICTIONS)).thenReturn(rTree);
}
return t;
}
private Tree createEntryTree(@NotNull String oakPath, @NotNull String... privilegeNames) {
Tree t = mock(Tree.class);
PropertyState path = PropertyStates.createProperty(REP_EFFECTIVE_PATH, oakPath);
when(t.getProperty(REP_EFFECTIVE_PATH)).thenReturn(path);
PropertyState privs = PropertyStates.createProperty(REP_PRIVILEGES, ImmutableList.copyOf(privilegeNames), Type.NAMES);
when(t.getProperty(REP_PRIVILEGES)).thenReturn(privs);
Tree rTree = when(mock(Tree.class).getProperties()).thenReturn(Collections.emptySet()).getMock();
when(t.getChild(REP_RESTRICTIONS)).thenReturn(rTree);
return t;
}
private Map<String, Value> createGlobRestriction(@NotNull String value) {
return ImmutableMap.of(getJcrName(REP_GLOB), getValueFactory(root).createValue(value));
}
private Map<String, Value> createRestrictions(@NotNull String oakName, @NotNull String value) {
return ImmutableMap.of(getJcrName(oakName), getValueFactory(root).createValue(value));
}
private Map<String, Value[]> createMvRestrictions(@NotNull String oakName, int propertyType, @NotNull String... values) throws ValueFormatException {
ValueFactory vf = getValueFactory(root);
Value[] vs = new Value[values.length];
for (int i = 0; i<values.length; i++) {
vs[i] = vf.createValue(values[i], propertyType);
}
return ImmutableMap.of(getJcrName(oakName), vs);
}
private String getJcrName(@NotNull String oakName) {
return getNamePathMapper().getJcrName(oakName);
}
@Test
public void testGetInitialSize() {
assertEquals(0, emptyPolicy.size());
}
@Test
public void testGetSize() {
assertEquals(policy.getEntries().size(), policy.size());
}
@Test
public void testInitiallyIsEmpty() {
assertTrue(emptyPolicy.isEmpty());
}
@Test
public void testIsEmpty() {
assertEquals(policy.getEntries().isEmpty(), policy.isEmpty());
}
@Test
public void testGetPath() {
assertEquals(policyJcrPath, policy.getPath());
}
@Test
public void testGetOakPath() {
assertEquals(POLICY_OAK_PATH, policy.getOakPath());
}
@Test
public void testGetNamePathMapper() {
assertSame(getMgrProvider(root).getNamePathMapper(), policy.getNamePathMapper());
}
@Test
public void testGetPrincipal() {
assertSame(principal, policy.getPrincipal());
}
@Test
public void testAddEntry() throws Exception {
assertTrue(emptyPolicy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_ADD_CHILD_NODES)));
assertEquals(1, emptyPolicy.size());
}
@Test
public void testAddEntryTwice() throws Exception {
assertTrue(emptyPolicy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_ADD_CHILD_NODES)));
assertFalse(emptyPolicy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_ADD_CHILD_NODES)));
assertEquals(1, emptyPolicy.getEntries().size());
}
@Test
public void testAddEntriesForSamePath() throws Exception {
assertTrue(emptyPolicy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_ADD_CHILD_NODES)));
assertTrue(emptyPolicy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_REMOVE_CHILD_NODES, PrivilegeConstants.JCR_REMOVE_NODE)));
List<PrincipalPolicyImpl.EntryImpl> entries = emptyPolicy.getEntries();
assertEquals(2, entries.size());
PrivilegeBitsProvider bitsProvider = new PrivilegeBitsProvider(root);
assertEquals(testJcrPath, entries.get(0).getEffectivePath());
assertEquals(bitsProvider.getBits(PrivilegeConstants.JCR_ADD_CHILD_NODES), entries.get(0).getPrivilegeBits());
assertEquals(bitsProvider.getBits(PrivilegeConstants.JCR_REMOVE_CHILD_NODES, PrivilegeConstants.JCR_REMOVE_NODE), entries.get(1).getPrivilegeBits());
}
@Test
public void testAddEntriesWithRestrictionsForSamePath() throws Exception {
assertTrue(emptyPolicy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_ADD_CHILD_NODES)));
assertTrue(emptyPolicy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_REMOVE_CHILD_NODES), ImmutableMap.of(), createMvRestrictions(REP_ITEM_NAMES, PropertyType.NAME, "removable")));
PrivilegeBitsProvider bitsProvider = new PrivilegeBitsProvider(root);
List<PrincipalPolicyImpl.EntryImpl> entries = emptyPolicy.getEntries();
assertEquals(2, entries.size());
PrincipalPolicyImpl.EntryImpl entry = entries.get(0);
assertEquals(testJcrPath, entry.getEffectivePath());
assertEquals(bitsProvider.getBits(PrivilegeConstants.JCR_ADD_CHILD_NODES), entry.getPrivilegeBits());
assertTrue(entry.getRestrictions().isEmpty());
entry = entries.get(1);
assertEquals(testJcrPath, entry.getEffectivePath());
assertEquals(bitsProvider.getBits(PrivilegeConstants.JCR_REMOVE_CHILD_NODES), entry.getPrivilegeBits());
assertEquals(1, entry.getRestrictions().size());
assertEquals(REP_ITEM_NAMES, entry.getRestrictions().iterator().next().getDefinition().getName());
}
@Test
public void testAddEntriesWithMultipleRestrictionsForSamePath() throws Exception {
assertTrue(emptyPolicy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_ADD_CHILD_NODES), createGlobRestriction("/any*/glob"), ImmutableMap.of()));
assertTrue(emptyPolicy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_REMOVE_CHILD_NODES), ImmutableMap.of(), createMvRestrictions(REP_ITEM_NAMES, PropertyType.NAME, "removable")));
PrivilegeBitsProvider bitsProvider = new PrivilegeBitsProvider(root);
List<PrincipalPolicyImpl.EntryImpl> entries = emptyPolicy.getEntries();
assertEquals(2, entries.size());
PrincipalPolicyImpl.EntryImpl entry = entries.get(0);
assertEquals(testJcrPath, entry.getEffectivePath());
assertEquals(bitsProvider.getBits(PrivilegeConstants.JCR_ADD_CHILD_NODES), entry.getPrivilegeBits());
assertEquals(1, entry.getRestrictions().size());
assertEquals(REP_GLOB, entry.getRestrictions().iterator().next().getDefinition().getName());
entry = entries.get(1);
assertEquals(testJcrPath, entry.getEffectivePath());
assertEquals(bitsProvider.getBits(PrivilegeConstants.JCR_REMOVE_CHILD_NODES), entry.getPrivilegeBits());
assertEquals(bitsProvider.getBits(PrivilegeConstants.JCR_REMOVE_CHILD_NODES), entry.getPrivilegeBits());
assertEquals(1, entry.getRestrictions().size());
assertEquals(REP_ITEM_NAMES, entry.getRestrictions().iterator().next().getDefinition().getName());
}
@Test
public void testAddEntryWithRestrictions() throws Exception {
Map<String, Value[]> mvRestrictions = createMvRestrictions(AccessControlConstants.REP_ITEM_NAMES, PropertyType.NAME, getNamePathMapper().getJcrName("oak:test"), "abc");
int expectedSize = policy.getEntries().size()+1;
assertTrue(policy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_WRITE), Collections.emptyMap(), mvRestrictions));
assertEquals(expectedSize, policy.size());
}
@Test
public void testAddEntryWithRestrictionsTwice() throws Exception {
Map<String, Value> restrictions = createGlobRestriction("*/some*glob");
assertTrue(policy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_READ_ACCESS_CONTROL, PrivilegeConstants.JCR_MODIFY_ACCESS_CONTROL), restrictions, Collections.emptyMap()));
assertFalse(policy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_READ_ACCESS_CONTROL, PrivilegeConstants.JCR_MODIFY_ACCESS_CONTROL), restrictions, Collections.emptyMap()));
}
@Test(expected = AccessControlException.class)
public void testAddEntryMissingMandatoryRestriction() throws Exception {
RestrictionProvider restrictionProvider = mock(RestrictionProvider.class);
when(restrictionProvider.getSupportedRestrictions(anyString())).thenReturn(
ImmutableSet.of(new RestrictionDefinitionImpl("oak:mandatory", Type.LONG, true)));
MgrProvider mp = when(mock(MgrProvider.class).getRestrictionProvider()).thenReturn(restrictionProvider).getMock();
when(mp.getNamePathMapper()).thenReturn(getNamePathMapper());
PrincipalPolicyImpl plc = new PrincipalPolicyImpl(principal, POLICY_OAK_PATH, mp);
String jcrName = namePathMapper.getJcrName("oak:mandatory");
Map<String,Value[]> mvRestrictions = ImmutableMap.of(jcrName, new Value[] {getValueFactory(root).createValue(1)});
plc.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_VERSION_MANAGEMENT), ImmutableMap.of(), mvRestrictions);
}
@Test(expected = AccessControlException.class)
public void testAddEntryMissingMandatoryMVRestriction() throws Exception {
RestrictionProvider restrictionProvider = mock(RestrictionProvider.class);
when(restrictionProvider.getSupportedRestrictions(anyString())).thenReturn(
ImmutableSet.of(new RestrictionDefinitionImpl("oak:mandatory", Type.LONGS, true)));
MgrProvider mp = when(mock(MgrProvider.class).getRestrictionProvider()).thenReturn(restrictionProvider).getMock();
when(mp.getNamePathMapper()).thenReturn(getNamePathMapper());
PrincipalPolicyImpl plc = new PrincipalPolicyImpl(principal, POLICY_OAK_PATH, mp);
String jcrName = namePathMapper.getJcrName("oak:mandatory");
Map<String,Value> svRestrictions = ImmutableMap.of(jcrName, getValueFactory(root).createValue(1));
plc.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_VERSION_MANAGEMENT), svRestrictions, ImmutableMap.of());
}
@Test(expected = AccessControlException.class)
public void testAddEntryMandatoryRestrictionWithOakName() throws Exception {
RestrictionProvider restrictionProvider = when(mock(RestrictionProvider.class).getSupportedRestrictions(anyString())).thenReturn(
ImmutableSet.of(new RestrictionDefinitionImpl("oak:mandatory", Type.LONG, true))).getMock();
MgrProvider mp = when(mock(MgrProvider.class).getRestrictionProvider()).thenReturn(restrictionProvider).getMock();
when(mp.getNamePathMapper()).thenReturn(getNamePathMapper());
PrincipalPolicyImpl plc = new PrincipalPolicyImpl(principal, POLICY_OAK_PATH, mp);
Map<String,Value> svRestrictions = ImmutableMap.of("oak:mandatory", getValueFactory(root).createValue(1));
plc.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_VERSION_MANAGEMENT), svRestrictions, ImmutableMap.of());
}
@Test
public void testAddEntryMandatoryRestriction() throws Exception {
RestrictionDefinition def = new RestrictionDefinitionImpl("mandatory", Type.LONG, true);
Restriction r = mock(Restriction.class);
RestrictionProvider restrictionProvider = mock(RestrictionProvider.class);
when(restrictionProvider.getSupportedRestrictions(anyString())).thenReturn(ImmutableSet.of(def));
when(restrictionProvider.createRestriction(anyString(), anyString(), any(Value.class))).thenReturn(r);
MgrProvider mp = when(mock(MgrProvider.class).getRestrictionProvider()).thenReturn(restrictionProvider).getMock();
when(mp.getNamePathMapper()).thenReturn(getNamePathMapper());
when(mp.getPrivilegeManager()).thenReturn(getPrivilegeManager(root));
when(mp.getPrivilegeBitsProvider()).thenReturn(new PrivilegeBitsProvider(root));
PrincipalPolicyImpl plc = new PrincipalPolicyImpl(principal, POLICY_OAK_PATH, mp);
Map<String,Value> svRestrictions = ImmutableMap.of("mandatory", getValueFactory(root).createValue(1));
plc.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_VERSION_MANAGEMENT), svRestrictions, ImmutableMap.of());
assertTrue(plc.getEntries().get(0).getRestrictions().contains(r));
}
@Test
public void testAddEntryForRepositoryLevel() throws Exception {
assertTrue(emptyPolicy.addEntry(null, privilegesFromNames(PrivilegeConstants.JCR_WORKSPACE_MANAGEMENT)));
assertEquals(1, emptyPolicy.getEntries().size());
}
@Test(expected = AccessControlException.class)
public void testAddEntryWithRelativePath() throws Exception {
emptyPolicy.addEntry("relative/path", privilegesFromNames(PrivilegeConstants.JCR_ADD_CHILD_NODES));
}
@Test(expected = AccessControlException.class)
public void testAddEntryWithEmptyPath() throws Exception {
emptyPolicy.addEntry("", privilegesFromNames(PrivilegeConstants.JCR_REMOVE_NODE));
}
@Test(expected = AccessControlException.class)
public void testAddEntryEmptyPrivileges() throws Exception {
policy.addEntry(testJcrPath, new Privilege[0]);
}
@Test(expected = AccessControlException.class)
public void testAddEntryUnknownPrivilege() throws Exception {
Privilege privilege = when(mock(Privilege.class).getName()).thenReturn("unknown").getMock();
policy.addEntry(testJcrPath, new Privilege[] {privilege});
}
@Test(expected = AccessControlException.class)
public void testAddEntryAbstractPrivilege() throws Exception {
Privilege privilege = when(mock(Privilege.class).isAbstract()).thenReturn(true).getMock();
when(privilege.getName()).thenReturn("abstract");
PrivilegeManager privilegeManager = when(mock(PrivilegeManager.class).getPrivilege("abstract")).thenReturn(privilege).getMock();
MgrProvider mp = when(mock(MgrProvider.class).getPrivilegeManager()).thenReturn(privilegeManager).getMock();
when(mp.getNamePathMapper()).thenReturn(getNamePathMapper());
when(mp.getRestrictionProvider()).thenReturn(RestrictionProvider.EMPTY);
PrincipalPolicyImpl policy = new PrincipalPolicyImpl(principal, POLICY_OAK_PATH, mp);
policy.addEntry(testJcrPath, new Privilege[] {privilege});
}
@Test(expected = AccessControlException.class)
public void testAddAccessControlEntryDifferentPrincipal() throws Exception {
policy.addEntry(EveryonePrincipal.getInstance(), privilegesFromNames(JCR_ALL), true, null, Collections.emptyMap());
}
@Test(expected = AccessControlException.class)
public void testAddDenyingAccessControlEntry() throws Exception {
policy.addEntry(principal, privilegesFromNames(PrivilegeConstants.REP_READ_NODES), false, Collections.emptyMap(), null);
}
@Test(expected = AccessControlException.class)
public void testAddAccessControlEntryMissingNodePath() throws Exception {
policy.addEntry(principal, privilegesFromNames(PrivilegeConstants.REP_USER_MANAGEMENT), true, Collections.emptyMap(), Collections.singletonMap(AccessControlConstants.REP_NT_NAMES, new Value[] {getValueFactory(root).createValue(NodeTypeConstants.NT_REP_SYSTEM)}));
}
@Test(expected = AccessControlException.class)
public void testAddAccessControlEntryMissingNodePath2() throws Exception {
policy.addEntry(principal, privilegesFromNames(PrivilegeConstants.REP_WRITE), true, null, null);
}
@Test
public void testAddAccessControlEntryWithEmptyNodePathRestriction() throws Exception {
assertTrue(emptyPolicy.addEntry(principal, privilegesFromNames(PrivilegeConstants.REP_ADD_PROPERTIES), true,
createRestrictions(REP_NODE_PATH, ""), null));
List<PrincipalPolicyImpl.EntryImpl> entries = emptyPolicy.getEntries();
assertEquals(1, entries.size());
PrincipalPolicyImpl.EntryImpl entry = entries.get(0);
assertNull(entry.getOakPath());
// effective-path restriction must be filtered out
assertNull(entry.getRestrictions(getJcrName(REP_NODE_PATH)));
}
@Test
public void testAddAccessControlEntryWithNodePathRestriction() throws Exception {
assertTrue(emptyPolicy.addEntry(principal, privilegesFromNames(PrivilegeConstants.REP_ADD_PROPERTIES), true,
createRestrictions(REP_NODE_PATH, testJcrPath),
createMvRestrictions(AccessControlConstants.REP_ITEM_NAMES, PropertyType.NAME, "itemName")));
List<PrincipalPolicyImpl.EntryImpl> entries = emptyPolicy.getEntries();
assertEquals(1, entries.size());
PrincipalPolicyImpl.EntryImpl entry = entries.get(0);
assertEquals(TEST_OAK_PATH, entry.getOakPath());
// effective-path restriction must be filtered out
assertNull(entry.getRestrictions(getJcrName(REP_NODE_PATH)));
}
@Test
public void testAddAccessControlEntryWithRestrictions() throws Exception {
ValueFactory vf = getValueFactory(root);
Map<String, Value> restr = ImmutableMap.of(getJcrName(REP_NODE_PATH), vf.createValue(testJcrPath), getJcrName(REP_GLOB), vf.createValue("string"));
assertTrue(emptyPolicy.addEntry(principal, privilegesFromNames(PrivilegeConstants.REP_USER_MANAGEMENT), true,
restr, null));
List<PrincipalPolicyImpl.EntryImpl> entries = emptyPolicy.getEntries();
assertEquals(1, entries.size());
PrincipalPolicyImpl.EntryImpl entry = entries.get(0);
assertEquals(TEST_OAK_PATH, entry.getOakPath());
// effective-path restriction must be filtered out
assertNull(entry.getRestrictions(getJcrName(REP_NODE_PATH)));
assertNotNull(entry.getRestrictions(getJcrName(REP_GLOB)));
}
@Test
public void addEntryTree() throws Exception {
assertTrue(emptyPolicy.addEntry(createEntryTree(TEST_OAK_PATH, PrivilegeConstants.JCR_READ, PrivilegeConstants.JCR_WRITE), Collections.emptyList()));
PrincipalPolicyImpl.EntryImpl entry = emptyPolicy.getEntries().get(0);
assertEquals(testJcrPath, entry.getEffectivePath());
assertEquals(TEST_OAK_PATH, entry.getOakPath());
assertEquals(privilegeBitsProvider.getBits(PrivilegeConstants.JCR_READ, PrivilegeConstants.JCR_WRITE), entry.getPrivilegeBits());
}
@Test
public void addEntryTreeRepositoryLevel() throws Exception {
assertTrue(emptyPolicy.addEntry(createEntryTree("", PrivilegeConstants.JCR_READ, PrivilegeConstants.JCR_WRITE), Collections.emptyList()));
PrincipalPolicyImpl.EntryImpl entry = emptyPolicy.getEntries().get(0);
assertNull(entry.getEffectivePath());
assertNull(entry.getOakPath());
}
@Test
public void addEntryTreeJcrAll() throws Exception {
assertTrue(emptyPolicy.addEntry(createEntryTree(TEST_OAK_PATH, JCR_ALL), Collections.emptyList()));
PrincipalPolicyImpl.EntryImpl entry = emptyPolicy.getEntries().get(0);
assertArrayEquals(privilegesFromNames(JCR_ALL), entry.getPrivileges());
}
@Test
public void addEntryTreeExistingEntry() throws Exception {
assertFalse(policy.addEntry(createEntryTree(policy.getEntries().get(0)), Collections.emptyList()));
}
@Test
public void addEntryTreeNullPathWithFilter() throws Exception {
Tree entryTree = createEntryTree("", JCR_ALL);
assertTrue(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(null)));
assertFalse(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList("/not/matching/path")));
assertFalse(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(PathUtils.ROOT_PATH)));
assertFalse(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(TEST_OAK_PATH)));
assertFalse(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(TEST_OAK_PATH + "/subtree")));
}
@Test
public void addEntryTreeWithFilter() throws Exception {
Tree entryTree = createEntryTree(TEST_OAK_PATH, JCR_ALL);
assertFalse(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(null)));
assertFalse(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList("/not/matching/path")));
assertFalse(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(PathUtils.ROOT_PATH)));
assertTrue(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(TEST_OAK_PATH)));
assertTrue(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(TEST_OAK_PATH + "/subtree")));
}
@Test
public void addEntryTreeWithPathFilterAndRestrictions() throws Exception {
PrincipalPolicyImpl policy = createPolicy(POLICY_OAK_PATH);
policy.addEntry(testJcrPath, privilegesFromNames(PrivilegeConstants.JCR_READ), Collections.emptyMap(),
Collections.singletonMap(getJcrName(REP_SUBTREES), new Value[] {getValueFactory(root).createValue("child")}));
// create an entry-tree that limits effect to a subtree of TEST_OAK_PATH
Tree entryTree = createEntryTree(policy.getEntries().get(0));
// paths that don't match the restriction
assertFalse(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(null)));
assertFalse(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList("/not/matching/path")));
assertFalse(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(PathUtils.ROOT_PATH)));
assertFalse(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(TEST_OAK_PATH)));
assertFalse(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(TEST_OAK_PATH + "/subtree")));
// paths that match the restriction
assertTrue(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(TEST_OAK_PATH + "/child")));
assertTrue(createPolicy(POLICY_OAK_PATH).addEntry(entryTree, Collections.singletonList(TEST_OAK_PATH + "/child/subtree")));
}
@Test
public void testRemoveEntry() throws Exception {
for (AccessControlEntry entry : policy.getAccessControlEntries()) {
assertFalse(policy.isEmpty());
policy.removeAccessControlEntry(entry);
}
assertTrue(policy.isEmpty());
}
@Test(expected = AccessControlException.class)
public void testRemoveEntryTwice() throws Exception {
AccessControlEntry entry = policy.getAccessControlEntries()[0];
policy.removeAccessControlEntry(entry);
policy.removeAccessControlEntry(entry);
}
@Test(expected = AccessControlException.class)
public void testRemoveEntryInvalidEntry() throws Exception {
policy.removeAccessControlEntry(invalidEntry(policy.getEntries().get(0)));
}
@Test
public void testOrderBefore() throws Exception {
PrincipalPolicyImpl.Entry entryA = policy.getEntries().get(0);
PrincipalPolicyImpl.Entry entryB = policy.getEntries().get(1);
policy.orderBefore(entryB, entryA);
assertArrayEquals(new AccessControlEntry[] {entryB, entryA}, policy.getAccessControlEntries());
}
@Test
public void testOrderBeforeDestNull() throws Exception {
PrincipalPolicyImpl.Entry entry = policy.getEntries().get(0);
policy.orderBefore(entry, null);
assertEquals(entry, policy.getAccessControlEntries()[1]);
}
@Test
public void testOrderBeforeSame() throws Exception {
policy.orderBefore(policy.getEntries().get(1), policy.getEntries().get(1));
}
@Test(expected = AccessControlException.class)
public void testOrderBeforeNonExistingSrc() throws Exception {
PrincipalPolicyImpl.Entry entry = policy.getEntries().get(0);
policy.removeAccessControlEntry(entry);
policy.orderBefore(entry, null);
}
@Test(expected = AccessControlException.class)
public void testOrderBeforeNonExistingDest() throws Exception {
PrincipalPolicyImpl.Entry entry = policy.getEntries().get(1);
policy.removeAccessControlEntry(entry);
policy.orderBefore(policy.getEntries().get(0), entry);
}
@Test(expected = AccessControlException.class)
public void testOrderBeforeInvalidSrc() throws Exception {
policy.orderBefore(invalidEntry(policy.getEntries().get(1)), policy.getEntries().get(0));
}
@Test(expected = AccessControlException.class)
public void testOrderBeforeInvalidDest() throws Exception {
policy.orderBefore(policy.getEntries().get(1), invalidEntry(policy.getEntries().get(0)));
}
@Test
public void testEntry() throws Exception {
Privilege[] privs = privilegesFromNames(PrivilegeConstants.JCR_ALL);
emptyPolicy.addEntry(testJcrPath, privs);
PrincipalPolicyImpl.EntryImpl entry = emptyPolicy.getEntries().get(0);
assertEquals(TEST_OAK_PATH, entry.getOakPath());
assertEquals(testJcrPath, entry.getEffectivePath());
assertArrayEquals(privs, entry.getPrivileges());
assertEquals(privilegeBitsProvider.getBits(JCR_ALL), entry.getPrivilegeBits());
assertSame(principal, entry.getPrincipal());
assertTrue(entry.isAllow());
}
@Test
public void testEntryRepositoryLevel() throws Exception {
Privilege[] privs = privilegesFromNames(JCR_NAMESPACE_MANAGEMENT);
emptyPolicy.addEntry(null, privs);
PrincipalPolicyImpl.EntryImpl entry = emptyPolicy.getEntries().get(0);
assertEquals(null, entry.getOakPath());
assertEquals(null, entry.getEffectivePath());
assertArrayEquals(privs, entry.getPrivileges());
assertEquals(privilegeBitsProvider.getBits(JCR_NAMESPACE_MANAGEMENT), entry.getPrivilegeBits());
assertSame(principal, entry.getPrincipal());
assertTrue(entry.isAllow());
}
private static PrincipalAccessControlList.Entry invalidEntry(@NotNull PrincipalAccessControlList.Entry entry) {
return new PrincipalAccessControlList.Entry() {
@Override
public @Nullable String getEffectivePath() {
return entry.getEffectivePath();
}
@Override
public boolean isAllow() {
return entry.isAllow();
}
@NotNull
@Override
public String[] getRestrictionNames() throws RepositoryException {
return entry.getRestrictionNames();
}
@Nullable
@Override
public Value getRestriction(@NotNull String s) throws RepositoryException {
return entry.getRestriction(s);
}
@Nullable
@Override
public Value[] getRestrictions(@NotNull String s) throws RepositoryException {
return entry.getRestrictions(s);
}
@Override
public @NotNull PrivilegeCollection getPrivilegeCollection() throws RepositoryException {
return entry.getPrivilegeCollection();
}
@Override
public Principal getPrincipal() {
return entry.getPrincipal();
}
@Override
public Privilege[] getPrivileges() {
return entry.getPrivileges();
}
};
}
}