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

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

The newest version!
/* Copyright 2004, 2005, 2006 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 1782 2007-02-22 23:57:49Z luke_t $ */ 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 final 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 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!"); } } 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 BasicAclDao getBasicAclDao() { return basicAclDao; } public BasicAclEntryCache getBasicAclEntryCache() { return basicAclEntryCache; } public Class getDefaultAclObjectIdentityClass() { return defaultAclObjectIdentityClass; } public EffectiveAclsResolver getEffectiveAclsResolver() { return effectiveAclsResolver; } public Class getRestrictSupportToClass() { return restrictSupportToClass; } 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; } /** * 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; } } public void setBasicAclDao(BasicAclDao basicAclDao) { this.basicAclDao = basicAclDao; } public void setBasicAclEntryCache(BasicAclEntryCache basicAclEntryCache) { this.basicAclEntryCache = 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 void setEffectiveAclsResolver(EffectiveAclsResolver effectiveAclsResolver) { this.effectiveAclsResolver = 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; } /** * 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; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy