All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.acegisecurity.acl.basic.BasicAclProvider Maven / Gradle / Ivy

There is a newer version: 1.0.7
Show newest version
/* 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 org.acegisecurity.acl.basic;

import org.acegisecurity.Authentication;
import org.acegisecurity.acl.AclEntry;
import org.acegisecurity.acl.AclProvider;
import org.acegisecurity.acl.basic.cache.NullAclEntryCache;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import java.lang.reflect.Constructor;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;


/**
 * 

* Retrieves access control lists (ACL) entries for domain object instances * from a data access object (DAO). *

* *

* This implementation will provide ACL lookup services for any object that it * can determine the {@link AclObjectIdentity} for by calling the {@link * #obtainIdentity(Object)} method. Subclasses can override this method if * they only want the BasicAclProvider responding to particular * domain object instances. *

* *

* BasicAclProvider will walk an inheritance hierarchy if a * BasicAclEntry returned by the DAO indicates it has a parent. * NB: inheritance occurs at a domain instance object level. It does * not occur at an ACL recipient level. This means * allBasicAclEntrys for a given domain instance object * must have the same parent identity, or * allBasicAclEntrys must have null as their * parent identity. *

* *

* A cache should be used. This is provided by the {@link BasicAclEntryCache}. * BasicAclProvider by default is setup to use the {@link * NullAclEntryCache}, which performs no caching. *

* *

* To implement the {@link #getAcls(Object, Authentication)} method, * BasicAclProvider requires a {@link EffectiveAclsResolver} to * be configured against it. By default the {@link * GrantedAuthorityEffectiveAclsResolver} is used. *

* * @author Ben Alex * @version $Id: BasicAclProvider.java,v 1.5 2005/11/17 00:55:47 benalex Exp $ */ public class BasicAclProvider implements AclProvider, InitializingBean { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(BasicAclProvider.class); /** * Marker added to the cache to indicate an AclObjectIdentity has no * corresponding BasicAclEntry[]s */ private static String RECIPIENT_FOR_CACHE_EMPTY = "RESERVED_RECIPIENT_NOBODY"; //~ Instance fields ======================================================== /** * Must be set to an appropriate data access object. Defaults to * null. */ private BasicAclDao basicAclDao; private BasicAclEntryCache basicAclEntryCache = new NullAclEntryCache(); private Class defaultAclObjectIdentityClass = NamedEntityObjectIdentity.class; private Class restrictSupportToClass = null; private EffectiveAclsResolver effectiveAclsResolver = new GrantedAuthorityEffectiveAclsResolver(); //~ Methods ================================================================ public AclEntry[] getAcls(Object domainInstance) { Map map = new HashMap(); AclObjectIdentity aclIdentity = obtainIdentity(domainInstance); Assert.notNull(aclIdentity, "domainInstance is not supported by this provider"); if (logger.isDebugEnabled()) { logger.debug("Looking up: " + aclIdentity.toString()); } BasicAclEntry[] instanceAclEntries = lookup(aclIdentity); // Exit if there is no ACL information or parent for this instance if (instanceAclEntries == null) { return null; } // Add the leaf objects to the Map, keyed on recipient for (int i = 0; i < instanceAclEntries.length; i++) { if (logger.isDebugEnabled()) { logger.debug("Explicit add: " + instanceAclEntries[i].toString()); } map.put(instanceAclEntries[i].getRecipient(), instanceAclEntries[i]); } AclObjectIdentity parent = instanceAclEntries[0] .getAclObjectParentIdentity(); while (parent != null) { BasicAclEntry[] parentAclEntries = lookup(parent); if (logger.isDebugEnabled()) { logger.debug("Parent lookup: " + parent.toString()); } // Exit loop if parent couldn't be found (unexpected condition) if (parentAclEntries == null) { if (logger.isDebugEnabled()) { logger.debug("Parent could not be found in ACL repository"); } break; } // Now add each _NEW_ recipient to the list for (int i = 0; i < parentAclEntries.length; i++) { if (!map.containsKey(parentAclEntries[i].getRecipient())) { if (logger.isDebugEnabled()) { logger.debug("Added parent to map: " + parentAclEntries[i].toString()); } map.put(parentAclEntries[i].getRecipient(), parentAclEntries[i]); } else { if (logger.isDebugEnabled()) { logger.debug("Did NOT add parent to map: " + parentAclEntries[i].toString()); } } } // Prepare for next iteration of while loop parent = parentAclEntries[0].getAclObjectParentIdentity(); } Collection collection = map.values(); return (AclEntry[]) collection.toArray(new AclEntry[]{}); } public AclEntry[] getAcls(Object domainInstance, Authentication authentication) { AclEntry[] allAcls = (AclEntry[]) this.getAcls(domainInstance); return this.effectiveAclsResolver.resolveEffectiveAcls(allAcls, authentication); } public void setBasicAclDao(BasicAclDao basicAclDao) { this.basicAclDao = basicAclDao; } public BasicAclDao getBasicAclDao() { return basicAclDao; } public void setBasicAclEntryCache(BasicAclEntryCache basicAclEntryCache) { this.basicAclEntryCache = basicAclEntryCache; } public BasicAclEntryCache getBasicAclEntryCache() { return basicAclEntryCache; } /** * Allows selection of the AclObjectIdentity class that an * attempt should be made to construct if the passed object does not * implement AclObjectIdentityAware. * *

* NB: Any defaultAclObjectIdentityClassmust provide a * public constructor that accepts an Object. Otherwise it is * not possible for the BasicAclProvider to try to create the * AclObjectIdentity instance at runtime. *

* * @param defaultAclObjectIdentityClass */ public void setDefaultAclObjectIdentityClass( Class defaultAclObjectIdentityClass) { this.defaultAclObjectIdentityClass = defaultAclObjectIdentityClass; } public Class getDefaultAclObjectIdentityClass() { return defaultAclObjectIdentityClass; } public void setEffectiveAclsResolver( EffectiveAclsResolver effectiveAclsResolver) { this.effectiveAclsResolver = effectiveAclsResolver; } public EffectiveAclsResolver getEffectiveAclsResolver() { return effectiveAclsResolver; } /** * If set to a value other than null, the {@link * #supports(Object)} method will only support the indicates class. * This is useful if you wish to wire multiple * BasicAclProviders in a list of * AclProviderManager.providers but only have particular * instances respond to particular domain object types. * * @param restrictSupportToClass the class to restrict this * BasicAclProvider to service request for, or * null (the default) if the * BasicAclProvider should respond to every class * presented */ public void setRestrictSupportToClass(Class restrictSupportToClass) { this.restrictSupportToClass = restrictSupportToClass; } public Class getRestrictSupportToClass() { return restrictSupportToClass; } public void afterPropertiesSet() { Assert.notNull(basicAclDao, "basicAclDao required"); Assert.notNull(basicAclEntryCache, "basicAclEntryCache required"); Assert.notNull(basicAclEntryCache, "basicAclEntryCache required"); Assert.notNull(effectiveAclsResolver, "effectiveAclsResolver required"); Assert.notNull(defaultAclObjectIdentityClass, "defaultAclObjectIdentityClass required"); Assert.isTrue(AclObjectIdentity.class.isAssignableFrom(this.defaultAclObjectIdentityClass), "defaultAclObjectIdentityClass must implement AclObjectIdentity"); try { Constructor constructor = defaultAclObjectIdentityClass .getConstructor(new Class[]{Object.class}); } catch (NoSuchMethodException nsme) { throw new IllegalArgumentException("defaultAclObjectIdentityClass must provide a constructor that accepts the domain object instance!"); } } /** * Indicates support for the passed object. * *

* An object will only be supported if it (i) is allowed to be supported as * defined by the {@link #setRestrictSupportToClass(Class)} method, * and (ii) if an AclObjectIdentity is returned by * {@link #obtainIdentity(Object)} for that object. *

* * @param domainInstance the instance to check * * @return true if this provider supports the passed object, * false otherwise */ public boolean supports(Object domainInstance) { if (domainInstance == null) { if (logger.isDebugEnabled()) { logger.debug("domainInstance is null"); } return false; } if ((restrictSupportToClass != null) && !restrictSupportToClass.isAssignableFrom( domainInstance.getClass())) { if (logger.isDebugEnabled()) { logger.debug("domainInstance not instance of " + restrictSupportToClass); } return false; } if (obtainIdentity(domainInstance) == null) { if (logger.isDebugEnabled()) { logger.debug("obtainIdentity returned null"); } return false; } else { if (logger.isDebugEnabled()) { logger.debug("obtainIdentity returned " + obtainIdentity(domainInstance)); } return true; } } /** * This method looks up the AclObjectIdentity of a passed * domain object instance. * *

* This implementation attempts to obtain the * AclObjectIdentity via reflection inspection of the class * for the {@link AclObjectIdentityAware} interface. If this fails, an * attempt is made to construct a {@link * #getDefaultAclObjectIdentityClass()} object by passing the domain * instance object into its constructor. *

* * @param domainInstance the domain object instance (never * null) * * @return an ACL object identity, or null if one could not be * obtained */ protected AclObjectIdentity obtainIdentity(Object domainInstance) { if (domainInstance instanceof AclObjectIdentityAware) { AclObjectIdentityAware aclObjectIdentityAware = (AclObjectIdentityAware) domainInstance; if (logger.isDebugEnabled()) { logger.debug("domainInstance: " + domainInstance + " cast to AclObjectIdentityAware"); } return aclObjectIdentityAware.getAclObjectIdentity(); } try { Constructor constructor = defaultAclObjectIdentityClass .getConstructor(new Class[] {Object.class}); if (logger.isDebugEnabled()) { logger.debug("domainInstance: " + domainInstance + " attempting to pass to constructor: " + constructor); } return (AclObjectIdentity) constructor.newInstance(new Object[] {domainInstance}); } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug("Error attempting construction of " + defaultAclObjectIdentityClass + ": " + ex.getMessage(), ex); if (ex.getCause() != null) { logger.debug("Cause: " + ex.getCause().getMessage(), ex.getCause()); } } return null; } } private BasicAclEntry[] lookup(AclObjectIdentity aclObjectIdentity) { BasicAclEntry[] result = basicAclEntryCache.getEntriesFromCache(aclObjectIdentity); if (result != null) { if (result[0].getRecipient().equals(RECIPIENT_FOR_CACHE_EMPTY)) { return null; } else { return result; } } result = basicAclDao.getAcls(aclObjectIdentity); if (result == null) { SimpleAclEntry[] emptyAclEntries = {new SimpleAclEntry(RECIPIENT_FOR_CACHE_EMPTY, aclObjectIdentity, null, 0)}; basicAclEntryCache.putEntriesInCache(emptyAclEntries); return null; } basicAclEntryCache.putEntriesInCache(result); return result; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy