/*
* 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.jcr2spi.security.authorization.jackrabbit.acl;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.AccessControlList;
import javax.jcr.security.Privilege;
import junit.framework.Assert;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.QValueFactory;
import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
import org.apache.jackrabbit.spi.commons.value.QValueFactoryImpl;
import org.apache.jackrabbit.test.api.security.AbstractAccessControlTest;
/**
* Tests the functionality of the JCR AccessControlList API implementation. The
* purpose is to test the consistency of the access control list by a, adding ,
* deleting and modifying entries in the list.
*/
public class AccessControlListImplTest extends AbstractAccessControlTest {
private QValueFactory vFactory;
private Principal unknownPrincipal;
private Principal knownPrincipal;
private NamePathResolver resolver;
@Override
public void setUp() throws Exception {
super.setUp();
resolver = new DefaultNamePathResolver(superuser);
vFactory = QValueFactoryImpl.getInstance();
unknownPrincipal = getHelper().getUnknownPrincipal(superuser);
knownPrincipal = new Principal() {
@Override
public String getName() {
return "everyone";
}
};
}
private JackrabbitAccessControlList createAccessControList(String aclPath)
throws RepositoryException {
return new AccessControlListImpl(aclPath, resolver, vFactory);
}
private Map<String, Value> createEmptyRestriction() {
return Collections.<String, Value> emptyMap();
}
public void testAddingDifferentEntries() throws Exception {
JackrabbitAccessControlList acl = createAccessControList(testRoot);
// allow read to unknownPrincipal
Privilege[] p = privilegesFromName(Privilege.JCR_READ);
acl.addAccessControlEntry(unknownPrincipal, p);
// allow addChildNodes to secondPrincipal
p = privilegesFromName(Privilege.JCR_ADD_CHILD_NODES);
acl.addAccessControlEntry(knownPrincipal, p);
// deny modifyAccessControl to 'unknown' principal
p = privilegesFromName(Privilege.JCR_MODIFY_ACCESS_CONTROL);
acl.addEntry(unknownPrincipal, p, false);
// deny jcr:nodeTypeManagement to secondPrincipal
p = privilegesFromName(Privilege.JCR_NODE_TYPE_MANAGEMENT);
acl.addEntry(knownPrincipal, p, false);
// four different entries
Assert.assertEquals(4, acl.size());
// UnknownPrincipal entries
AccessControlEntry[] pentries = getEntries(acl, unknownPrincipal);
Assert.assertEquals(2, pentries.length);
// secondPrincipal entries
AccessControlEntry[] sentries = getEntries(acl, knownPrincipal);
Assert.assertEquals(2, sentries.length);
}
public void testMultipleEntryEffect() throws Exception {
JackrabbitAccessControlList acl = createAccessControList(testRoot);
Privilege[] privileges = privilegesFromName(Privilege.JCR_READ);
// GRANT 'read' privilege to the Admin user -> list now contains one
// allow entry
assertTrue(acl.addAccessControlEntry(unknownPrincipal, privileges));
// policy contains a single entry
assertEquals(1, acl.size());
AccessControlEntry[] entries = acl.getAccessControlEntries();
// ... and the entry grants a single privilege
assertEquals(1, entries[0].getPrivileges().length);
assertEquals("jcr:read", entries[0].getPrivileges()[0].getName());
// GRANT 'add_child_node' privilege for the admin user -> same entry but
// with an additional 'add_child_node' privilege.
privileges = privilegesFromNames(new String[] {Privilege.JCR_ADD_CHILD_NODES, Privilege.JCR_READ });
assertTrue(acl.addAccessControlEntry(unknownPrincipal, privileges));
// A new Entry was added -> entries count should be 2.
assertEquals(2, acl.size());
// The single entry should now contain both 'read' and 'add_child_nodes'
// privileges for the same principal.
assertEquals(1, acl.getAccessControlEntries()[0].getPrivileges().length);
assertEquals(2, acl.getAccessControlEntries()[1].getPrivileges().length);
// adding a privilege that's already granted for the same principal ->
// again modified as the client doesn't care about possible compaction the
// server may want to make.
privileges = privilegesFromNames(new String[] { Privilege.JCR_READ });
assertTrue(acl.addAccessControlEntry(unknownPrincipal, privileges));
assertEquals(3, acl.size());
// revoke the read privilege
assertTrue("Fail to revoke read privilege", acl.addEntry(unknownPrincipal, privileges, false, createEmptyRestriction()));
// should now be 3 entries -> 2 allow entry + a deny entry
assertEquals(4, acl.size());
}
public void testMultipleEntryEffect2() throws Exception {
JackrabbitAccessControlList acl = createAccessControList(testRoot);
// GRANT a read privilege
Privilege[] privileges = privilegesFromNames(new String[] { Privilege.JCR_READ });
assertTrue("New Entry -> grants read privilege", acl.addAccessControlEntry(unknownPrincipal, privileges));
assertTrue("Fail to revoke the read privilege", acl.addEntry(unknownPrincipal, privileges, false, createEmptyRestriction()));
Assert.assertEquals(2, acl.size());
}
// -------------------------------------------------------< utility methods >---
private AccessControlEntry[] getEntries(AccessControlList acl, Principal princ) throws RepositoryException {
AccessControlEntry[] entries = acl.getAccessControlEntries();
List<AccessControlEntry> entriesPerPrincipal = new ArrayList<AccessControlEntry>(2);
for (AccessControlEntry entry : entries) {
if (entry.getPrincipal().getName().equals(princ.getName())) {
entriesPerPrincipal.add(entry);
}
}
return entriesPerPrincipal.toArray(new AccessControlEntry[entriesPerPrincipal.size()]);
}
}