Hi,
I added a support to filter arrays using
BasicAclEntryAfterInvocationCollectionFilteringProvider (see:
http://forum.springframework.org/viewtopic.php?
t=2553&sid=5e5393a3c6a8c4d89f07ad7feda30e4a ). I didn't implement it
using a separate class hierarchy but added the array filtering straight
into the BasicAclEntryAfterInvocationCollectionFilteringProvider class
(it was a small refactoring of the decide-method). I think that this
implementation strategy is more user friendly since it allows one to
refactor the return type from Collection to array (or vice versa)
without a need to change the security configuration. Please review the
attached code and include it to the release if you agree with the
implementation.
--
Joni Suominen <[EMAIL PROTECTED]>
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed 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 net.sf.acegisecurity.afterinvocation;
import net.sf.acegisecurity.AccessDeniedException;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthorizationServiceException;
import net.sf.acegisecurity.ConfigAttribute;
import net.sf.acegisecurity.ConfigAttributeDefinition;
import net.sf.acegisecurity.acl.AclEntry;
import net.sf.acegisecurity.acl.AclManager;
import net.sf.acegisecurity.acl.basic.AbstractBasicAclEntry;
import net.sf.acegisecurity.acl.basic.SimpleAclEntry;
import org.apache.commons.collections.iterators.ArrayIterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* <p>
* Given a <code>Collection</code> of domain object instances returned from a
* secure object invocation, remove any <code>Collection</code> elements the
* principal does not have appropriate permission to access as defined by the
* [EMAIL PROTECTED] AclManager}.
* </p>
*
* <p>
* The <code>AclManager</code> is used to retrieve the access control list
* (ACL) permissions associated with each <code>Collection</code> domain
* object instance element for the current <code>Authentication</code> object.
* This class is designed to process [EMAIL PROTECTED] AclEntry}s that are subclasses of
* [EMAIL PROTECTED] net.sf.acegisecurity.acl.basic.AbstractBasicAclEntry} only.
* Generally these are obtained by using the [EMAIL PROTECTED]
* net.sf.acegisecurity.acl.basic.BasicAclProvider}.
* </p>
*
* <p>
* This after invocation provider will fire if any [EMAIL PROTECTED]
* ConfigAttribute#getAttribute()} matches the [EMAIL PROTECTED]
* #processConfigAttribute}. The provider will then lookup the ACLs from the
* <code>AclManager</code> and ensure the principal is [EMAIL PROTECTED]
* net.sf.acegisecurity.acl.basic.AbstractBasicAclEntry#isPermitted(int)} for
* at least one of the [EMAIL PROTECTED] #requirePermission}s for each
* <code>Collection</code> element. If the principal does not have at least
* one of the permissions, that element will not be included in the returned
* <code>Collection</code>.
* </p>
*
* <p>
* Often users will setup a <code>BasicAclEntryAfterInvocationProvider</code>
* with a [EMAIL PROTECTED] #processConfigAttribute} of
* <code>AFTER_ACL_COLLECTION_READ</code> and a [EMAIL PROTECTED] #requirePermission} of
* <code>SimpleAclEntry.READ</code>. These are also the defaults.
* </p>
*
* <p>
* The <code>AclManager</code> is allowed to return any implementations of
* <code>AclEntry</code> it wishes. However, this provider will only be able
* to validate against <code>AbstractBasicAclEntry</code>s, and thus a
* <code>Collection</code> element will be filtered from the resulting
* <code>Collection</code> if no <code>AclEntry</code> is of type
* <code>AbstractBasicAclEntry</code>.
* </p>
*
* <p>
* If the provided <code>returnObject</code> is <code>null</code>, a
* <code>null</code><code>Collection</code> will be returned. If the provided
* <code>returnObject</code> is not a <code>Collection</code>, an [EMAIL PROTECTED]
* AuthorizationServiceException} will be thrown.
* </p>
*
* <p>
* All comparisons and prefixes are case sensitive.
* </p>
*
* @author Ben Alex
* @version $Id: BasicAclEntryAfterInvocationCollectionFilteringProvider.java,v 1.2 2004/11/20 04:10:05 benalex Exp $
*/
public class BasicAclEntryAfterInvocationCollectionFilteringProvider
implements AfterInvocationProvider, InitializingBean {
//~ Static fields/initializers =============================================
protected static final Log logger = LogFactory.getLog(BasicAclEntryAfterInvocationCollectionFilteringProvider.class);
//~ Instance fields ========================================================
private AclManager aclManager;
private String processConfigAttribute = "AFTER_ACL_COLLECTION_READ";
private int[] requirePermission = {SimpleAclEntry.READ};
//~ Methods ================================================================
public void setAclManager(AclManager aclManager) {
this.aclManager = aclManager;
}
public AclManager getAclManager() {
return aclManager;
}
public void setProcessConfigAttribute(String processConfigAttribute) {
this.processConfigAttribute = processConfigAttribute;
}
public String getProcessConfigAttribute() {
return processConfigAttribute;
}
public void setRequirePermission(int[] requirePermission) {
this.requirePermission = requirePermission;
}
public int[] getRequirePermission() {
return requirePermission;
}
public void afterPropertiesSet() throws Exception {
if (processConfigAttribute == null) {
throw new IllegalArgumentException(
"A processConfigAttribute is mandatory");
}
if ((requirePermission == null) || (requirePermission.length == 0)) {
throw new IllegalArgumentException(
"One or more requirePermission entries is mandatory");
}
if (aclManager == null) {
throw new IllegalArgumentException("An aclManager is mandatory");
}
}
public Object decide(Authentication authentication, Object object,
ConfigAttributeDefinition config, Object returnedObject)
throws AccessDeniedException {
Iterator iter = config.getConfigAttributes();
while (iter.hasNext()) {
ConfigAttribute attr = (ConfigAttribute) iter.next();
if (this.supports(attr)) {
// Need to process the Collection for this invocation
if (returnedObject == null) {
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, skipping");
}
return null;
}
Filterer filterer = null;
if (returnedObject instanceof Collection) {
Collection collection = (Collection) returnedObject;
filterer = new CollectionFilterer(collection);
}
else if (returnedObject.getClass().isArray()) {
Object[] array = (Object[]) returnedObject;
filterer = new ArrayFilterer(array);
}
else {
throw new AuthorizationServiceException(
"A Collection or an array (or null) was required as the returnedObject, but the returnedObject was: "
+ returnedObject);
}
// Locate unauthorised Collection elements
Iterator collectionIter = filterer.iterator();
while (collectionIter.hasNext()) {
Object domainObject = collectionIter.next();
boolean hasPermission = false;
AclEntry[] acls = null;
if (domainObject == null) {
hasPermission = true;
} else {
acls = aclManager.getAcls(domainObject, authentication);
}
if ((acls != null) && (acls.length != 0)) {
for (int i = 0; i < acls.length; i++) {
// Locate processable AclEntrys
if (acls[i] instanceof AbstractBasicAclEntry) {
AbstractBasicAclEntry processableAcl = (AbstractBasicAclEntry) acls[i];
// See if principal has any of the required permissions
for (int y = 0; y < requirePermission.length;
y++) {
if (processableAcl.isPermitted(
requirePermission[y])) {
hasPermission = true;
if (logger.isDebugEnabled()) {
logger.debug(
"Principal is authorised for element: "
+ domainObject
+ " due to ACL: "
+ processableAcl.toString());
}
}
}
}
}
}
if (!hasPermission) {
filterer.remove(domainObject);
if (logger.isDebugEnabled()) {
logger.debug(
"Principal is NOT authorised for element: "
+ domainObject);
}
}
}
return filterer.getFilteredObject();
}
}
return returnedObject;
}
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null)
&& attribute.getAttribute().equals(getProcessConfigAttribute())) {
return true;
} else {
return false;
}
}
/**
* This implementation supports any type of class, because it does not
* query the presented secure object.
*
* @param clazz the secure object
*
* @return always <code>true</code>
*/
public boolean supports(Class clazz) {
return true;
}
}
/**
* Filter strategy interface.
*/
interface Filterer {
/**
* Returns an iterator over the filtered collection or array.
*
* @return an Iterator
*/
public Iterator iterator();
/**
* Removes the the given object from the resulting list.
*
* @param object the object to be removed
*/
public void remove(Object object);
/**
* Gets the filtered collection or array.
*
* @return the filtered collection or array
*/
public Object getFilteredObject();
}
/**
* A filter used to filter Collections.
*/
class CollectionFilterer implements Filterer {
protected static final Log logger = LogFactory.getLog(
BasicAclEntryAfterInvocationCollectionFilteringProvider.class);
private Set removeList;
private Collection collection;
CollectionFilterer(Collection collection) {
this.collection = collection;
// We create a Set of objects to be removed from the Collection,
// as ConcurrentModificationException prevents removal during
// iteration, and making a new Collection to be returned is
// problematic as the original Collection implementation passed
// to the method may not necessarily be re-constructable (as
// the Collection(collection) constructor is not guaranteed and
// manually adding may lose sort order or other capabilities)
removeList = new HashSet();
}
/**
* @see net.sf.acegisecurity.afterinvocation.Filterer#iterator()
*/
public Iterator iterator() {
return collection.iterator();
}
/**
* @see net.sf.acegisecurity.afterinvocation.Filterer#remove(java.lang.Object)
*/
public void remove(Object object) {
removeList.add(object);
}
/**
* @see net.sf.acegisecurity.afterinvocation.Filterer#getFilteredObject()
*/
public Object getFilteredObject() {
// Now the Iterator has ended, remove Objects from Collection
Iterator removeIter = removeList.iterator();
int originalSize = collection.size();
while (removeIter.hasNext()) {
collection.remove(removeIter.next());
}
if (logger.isDebugEnabled()) {
logger.debug("Original collection contained "
+ originalSize + " elements; now contains "
+ collection.size() + " elements");
}
return collection;
}
}
/**
* A filter used to filter arrays.
*/
class ArrayFilterer implements Filterer {
protected static final Log logger = LogFactory.getLog(
BasicAclEntryAfterInvocationCollectionFilteringProvider.class);
private Set removeList;
private Object[] list;
ArrayFilterer(Object[] list) {
this.list = list;
// Collect the removed objects to a HashSet so that
// it is fast to lookup them when a filtered array
// is constructed.
removeList = new HashSet();
}
/**
* @see net.sf.acegisecurity.afterinvocation.Filterer#iterator()
*/
public Iterator iterator() {
return new ArrayIterator(list);
}
/**
* @see net.sf.acegisecurity.afterinvocation.Filterer#remove(java.lang.Object)
*/
public void remove(Object object) {
removeList.add(object);
}
/**
* @see net.sf.acegisecurity.afterinvocation.Filterer#getFilteredObject()
*/
public Object getFilteredObject() {
// Recreate an array of same type and filter the removed objects.
int originalSize = list.length;
int sizeOfResultingList = originalSize - removeList.size();
Object[] filtered = (Object[]) Array.newInstance(
list.getClass().getComponentType(), sizeOfResultingList);
for (int i = 0, j = 0; i < list.length; i++) {
Object object = list[i];
if (!removeList.contains(object)) {
filtered[j] = object;
j++;
}
}
if (logger.isDebugEnabled()) {
logger.debug("Original array contained "
+ originalSize + " elements; now contains "
+ sizeOfResultingList + " elements");
}
return filtered;
}
}/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed 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 net.sf.acegisecurity.afterinvocation;
import junit.framework.TestCase;
import net.sf.acegisecurity.AuthorizationServiceException;
import net.sf.acegisecurity.ConfigAttributeDefinition;
import net.sf.acegisecurity.MockAclManager;
import net.sf.acegisecurity.MockMethodInvocation;
import net.sf.acegisecurity.SecurityConfig;
import net.sf.acegisecurity.acl.AclEntry;
import net.sf.acegisecurity.acl.AclManager;
import net.sf.acegisecurity.acl.basic.MockAclObjectIdentity;
import net.sf.acegisecurity.acl.basic.SimpleAclEntry;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import java.util.List;
import java.util.Vector;
/**
* Tests [EMAIL PROTECTED] BasicAclEntryAfterInvocationCollectionFilteringProvider}.
*
* @author Ben Alex
* @version $Id: BasicAclEntryAfterInvocationCollectionFilteringProviderTests.java,v 1.1 2004/12/03 06:46:36 benalex Exp $
*/
public class BasicAclEntryAfterInvocationCollectionFilteringProviderTests
extends TestCase {
//~ Constructors ===========================================================
public BasicAclEntryAfterInvocationCollectionFilteringProviderTests() {
super();
}
public BasicAclEntryAfterInvocationCollectionFilteringProviderTests(
String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(BasicAclEntryAfterInvocationCollectionFilteringProviderTests.class);
}
public void testCorrectOperationWhenPrincipalHasIncorrectPermissionToDomainObject()
throws Exception {
// Create an AclManager, granting scott only ADMINISTRATION rights
AclManager aclManager = new MockAclManager("belmont", "scott",
new AclEntry[] {new SimpleAclEntry("scott",
new MockAclObjectIdentity(), null,
SimpleAclEntry.ADMINISTRATION)});
BasicAclEntryAfterInvocationCollectionFilteringProvider provider = new BasicAclEntryAfterInvocationCollectionFilteringProvider();
provider.setAclManager(aclManager);
provider.afterPropertiesSet();
// Create a Collection containing many items
List list = new Vector();
list.add("sydney");
list.add("melbourne");
list.add("belmont");
list.add("brisbane");
// Create the Authentication and Config Attribs we'll be presenting
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("scott",
"NOT_USED");
ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
attr.addConfigAttribute(new SecurityConfig("AFTER_ACL_COLLECTION_READ"));
// Filter
List filteredList = (List) provider.decide(auth,
new MockMethodInvocation(), attr, list);
assertEquals(0, filteredList.size());
}
public void testCorrectOperationWhenPrincipalHasNoPermissionToDomainObject()
throws Exception {
// Create an AclManager
AclManager aclManager = new MockAclManager("belmont", "marissa",
new AclEntry[] {new MockAclEntry(), new SimpleAclEntry(
"marissa", new MockAclObjectIdentity(), null,
SimpleAclEntry.ADMINISTRATION), new SimpleAclEntry(
"marissa", new MockAclObjectIdentity(), null,
SimpleAclEntry.READ), new SimpleAclEntry("marissa",
new MockAclObjectIdentity(), null, SimpleAclEntry.DELETE)});
BasicAclEntryAfterInvocationCollectionFilteringProvider provider = new BasicAclEntryAfterInvocationCollectionFilteringProvider();
provider.setAclManager(aclManager);
provider.afterPropertiesSet();
// Create a Collection containing many items, which only "belmont"
// should remain in after filtering by provider
List list = new Vector();
list.add("sydney");
list.add("melbourne");
list.add("belmont");
list.add("brisbane");
// Create the Authentication and Config Attribs we'll be presenting
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("scott",
"NOT_USED");
ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
attr.addConfigAttribute(new SecurityConfig("AFTER_ACL_COLLECTION_READ"));
// Filter
List filteredList = (List) provider.decide(auth,
new MockMethodInvocation(), attr, list);
assertEquals(0, filteredList.size());
}
public void testCorrectOperationWhenPrincipalIsAuthorised()
throws Exception {
// Create an AclManager
AclManager aclManager = new MockAclManager("belmont", "marissa",
new AclEntry[] {new MockAclEntry(), new SimpleAclEntry(
"marissa", new MockAclObjectIdentity(), null,
SimpleAclEntry.ADMINISTRATION), new SimpleAclEntry(
"marissa", new MockAclObjectIdentity(), null,
SimpleAclEntry.READ), new SimpleAclEntry("marissa",
new MockAclObjectIdentity(), null, SimpleAclEntry.DELETE)});
BasicAclEntryAfterInvocationCollectionFilteringProvider provider = new BasicAclEntryAfterInvocationCollectionFilteringProvider();
provider.setAclManager(aclManager);
assertEquals(aclManager, provider.getAclManager());
provider.afterPropertiesSet();
// Create a Collection containing many items, which only "belmont"
// should remain in after filtering by provider
List list = new Vector();
list.add("sydney");
list.add("melbourne");
list.add("belmont");
list.add("brisbane");
// Create the Authentication and Config Attribs we'll be presenting
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("marissa",
"NOT_USED");
ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
attr.addConfigAttribute(new SecurityConfig("AFTER_ACL_COLLECTION_READ"));
// Filter
List filteredList = (List) provider.decide(auth,
new MockMethodInvocation(), attr, list);
assertEquals(1, filteredList.size());
assertEquals("belmont", filteredList.get(0));
}
public void testDetectsIfReturnedObjectIsNotACollection()
throws Exception {
// Create an AclManager
AclManager aclManager = new MockAclManager("belmont", "marissa",
new AclEntry[] {new SimpleAclEntry("marissa",
new MockAclObjectIdentity(), null,
SimpleAclEntry.ADMINISTRATION), new SimpleAclEntry(
"marissa", new MockAclObjectIdentity(), null,
SimpleAclEntry.READ), new SimpleAclEntry("marissa",
new MockAclObjectIdentity(), null, SimpleAclEntry.DELETE), new MockAclEntry()});
BasicAclEntryAfterInvocationCollectionFilteringProvider provider = new BasicAclEntryAfterInvocationCollectionFilteringProvider();
provider.setAclManager(aclManager);
provider.afterPropertiesSet();
// Create the Authentication and Config Attribs we'll be presenting
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("marissa",
"NOT_USED");
ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
attr.addConfigAttribute(new SecurityConfig("AFTER_ACL_COLLECTION_READ"));
// Filter
try {
provider.decide(auth, new MockMethodInvocation(), attr,
new String("RETURN_OBJECT_NOT_COLLECTION"));
fail("Should have thrown AuthorizationServiceException");
} catch (AuthorizationServiceException expected) {
assertTrue(true);
}
}
public void testGrantsAccessIfReturnedObjectIsNull()
throws Exception {
// Create an AclManager
AclManager aclManager = new MockAclManager("belmont", "marissa",
new AclEntry[] {new SimpleAclEntry("marissa",
new MockAclObjectIdentity(), null,
SimpleAclEntry.ADMINISTRATION), new SimpleAclEntry(
"marissa", new MockAclObjectIdentity(), null,
SimpleAclEntry.READ), new SimpleAclEntry("marissa",
new MockAclObjectIdentity(), null, SimpleAclEntry.DELETE), new MockAclEntry()});
BasicAclEntryAfterInvocationCollectionFilteringProvider provider = new BasicAclEntryAfterInvocationCollectionFilteringProvider();
provider.setAclManager(aclManager);
provider.afterPropertiesSet();
// Create the Authentication and Config Attribs we'll be presenting
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("marissa",
"NOT_USED");
ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
attr.addConfigAttribute(new SecurityConfig("AFTER_ACL_COLLECTION_READ"));
// Filter
List filteredList = (List) provider.decide(auth,
new MockMethodInvocation(), attr, null);
assertNull(filteredList);
}
public void testRespectsModificationsToProcessConfigAttribute()
throws Exception {
// Create an AclManager
AclManager aclManager = new MockAclManager("sydney", "marissa",
new AclEntry[] {new SimpleAclEntry("marissa",
new MockAclObjectIdentity(), null, SimpleAclEntry.READ), new MockAclEntry()});
BasicAclEntryAfterInvocationCollectionFilteringProvider provider = new BasicAclEntryAfterInvocationCollectionFilteringProvider();
provider.setAclManager(aclManager);
assertEquals("AFTER_ACL_COLLECTION_READ",
provider.getProcessConfigAttribute());
provider.setProcessConfigAttribute("AFTER_ACL_COLLECTION_ADMIN");
assertEquals("AFTER_ACL_COLLECTION_ADMIN",
provider.getProcessConfigAttribute());
provider.afterPropertiesSet();
// Create a Collection containing many items, which only "sydney"
// should remain in after filtering by provider
List list = new Vector();
list.add("sydney");
list.add("melbourne");
list.add("belmont");
list.add("brisbane");
// Create the Authentication and Config Attribs we'll be presenting
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("marissa",
"NOT_USED");
ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
attr.addConfigAttribute(new SecurityConfig("AFTER_ACL_COLLECTION_READ"));
// As no matching config attrib, ensure provider doesn't change list
assertEquals(4,
((List) provider.decide(auth, new MockMethodInvocation(), attr, list))
.size());
// Filter, this time with the conf attrib provider setup to answer
attr.addConfigAttribute(new SecurityConfig("AFTER_ACL_COLLECTION_ADMIN"));
List filteredList = (List) provider.decide(auth,
new MockMethodInvocation(), attr, list);
assertEquals(1, filteredList.size());
assertEquals("sydney", filteredList.get(0));
}
public void testRespectsModificationsToRequirePermissions()
throws Exception {
// Create an AclManager
AclManager aclManager = new MockAclManager("sydney", "marissa",
new AclEntry[] {new SimpleAclEntry("marissa",
new MockAclObjectIdentity(), null,
SimpleAclEntry.ADMINISTRATION), new MockAclEntry()});
BasicAclEntryAfterInvocationCollectionFilteringProvider provider = new BasicAclEntryAfterInvocationCollectionFilteringProvider();
provider.setAclManager(aclManager);
assertEquals(SimpleAclEntry.READ, provider.getRequirePermission()[0]);
provider.setRequirePermission(new int[] {SimpleAclEntry.ADMINISTRATION});
assertEquals(SimpleAclEntry.ADMINISTRATION,
provider.getRequirePermission()[0]);
provider.afterPropertiesSet();
// Create a Collection containing many items, which only "sydney"
// should remain in after filtering by provider
List list = new Vector();
list.add("sydney");
list.add("melbourne");
list.add("belmont");
list.add("brisbane");
// Create the Authentication and Config Attribs we'll be presenting
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("marissa",
"NOT_USED");
ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
attr.addConfigAttribute(new SecurityConfig("AFTER_ACL_COLLECTION_READ"));
// Filter
List filteredList = (List) provider.decide(auth,
new MockMethodInvocation(), attr, list);
assertEquals(1, filteredList.size());
assertEquals("sydney", filteredList.get(0));
}
public void testStartupDetectsMissingAclManager() throws Exception {
BasicAclEntryAfterInvocationCollectionFilteringProvider provider = new BasicAclEntryAfterInvocationCollectionFilteringProvider();
try {
provider.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("An aclManager is mandatory", expected.getMessage());
}
}
public void testStartupDetectsMissingProcessConfigAttribute()
throws Exception {
BasicAclEntryAfterInvocationCollectionFilteringProvider provider = new BasicAclEntryAfterInvocationCollectionFilteringProvider();
AclManager aclManager = new MockAclManager("sydney", "marissa",
new AclEntry[] {new SimpleAclEntry("marissa",
new MockAclObjectIdentity(), null,
SimpleAclEntry.ADMINISTRATION), new MockAclEntry()});
provider.setAclManager(aclManager);
provider.setProcessConfigAttribute(null);
try {
provider.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("A processConfigAttribute is mandatory",
expected.getMessage());
}
}
public void testStartupDetectsMissingRequirePermission()
throws Exception {
BasicAclEntryAfterInvocationCollectionFilteringProvider provider = new BasicAclEntryAfterInvocationCollectionFilteringProvider();
AclManager aclManager = new MockAclManager("sydney", "marissa",
new AclEntry[] {new SimpleAclEntry("marissa",
new MockAclObjectIdentity(), null,
SimpleAclEntry.ADMINISTRATION), new MockAclEntry()});
provider.setAclManager(aclManager);
provider.setRequirePermission(null);
try {
provider.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("One or more requirePermission entries is mandatory",
expected.getMessage());
}
}
public void testSupportsAnything() {
assertTrue(new BasicAclEntryAfterInvocationCollectionFilteringProvider()
.supports(String.class));
}
public void testCorrectOperationWhenReturnedObjectIsArray()
throws Exception {
// Create an AclManager
AclManager aclManager = new MockAclManager("belmont", "marissa",
new AclEntry[] {new MockAclEntry(), new SimpleAclEntry(
"marissa", new MockAclObjectIdentity(), null,
SimpleAclEntry.ADMINISTRATION), new SimpleAclEntry(
"marissa", new MockAclObjectIdentity(), null,
SimpleAclEntry.READ), new SimpleAclEntry("marissa",
new MockAclObjectIdentity(), null, SimpleAclEntry.DELETE)});
BasicAclEntryAfterInvocationCollectionFilteringProvider provider = new BasicAclEntryAfterInvocationCollectionFilteringProvider();
provider.setAclManager(aclManager);
assertEquals(aclManager, provider.getAclManager());
provider.afterPropertiesSet();
// Create a Collection containing many items, which only "belmont"
// should remain in after filtering by provider
String[] list = new String[4];
list[0] = "sydney";
list[1] = "melbourne";
list[2] = "belmont";
list[3] = "brisbane";
// Create the Authentication and Config Attribs we'll be presenting
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("marissa",
"NOT_USED");
ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
attr.addConfigAttribute(new SecurityConfig("AFTER_ACL_COLLECTION_READ"));
// Filter
String[] filteredList = (String[]) provider.decide(auth,
new MockMethodInvocation(), attr, list);
assertEquals(1, filteredList.length);
assertEquals("belmont", filteredList[0]);
}
//~ Inner Classes ==========================================================
private class MockAclEntry implements AclEntry {
// just so AclTag iterates some different types of AclEntrys
}
}