diff --git a/core/src/main/java/org/acegisecurity/vote/BasicAclEntryVoter.java b/core/src/main/java/org/acegisecurity/vote/BasicAclEntryVoter.java
index a41b80a49a..d41f8ddd0e 100644
--- a/core/src/main/java/org/acegisecurity/vote/BasicAclEntryVoter.java
+++ b/core/src/main/java/org/acegisecurity/vote/BasicAclEntryVoter.java
@@ -25,8 +25,14 @@ import net.sf.acegisecurity.acl.basic.AbstractBasicAclEntry;
import org.aopalliance.intercept.MethodInvocation;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
import org.springframework.beans.factory.InitializingBean;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
import java.util.Iterator;
@@ -120,10 +126,15 @@ import java.util.Iterator;
*/
public class BasicAclEntryVoter implements AccessDecisionVoter,
InitializingBean {
+ //~ Static fields/initializers =============================================
+
+ private static final Log logger = LogFactory.getLog(BasicAclEntryVoter.class);
+
//~ Instance fields ========================================================
private AclManager aclManager;
private Class processDomainObjectClass;
+ private String internalMethod;
private String processConfigAttribute;
private int[] requirePermission;
@@ -137,6 +148,27 @@ public class BasicAclEntryVoter implements AccessDecisionVoter,
return aclManager;
}
+ public void setInternalMethod(String internalMethod) {
+ this.internalMethod = internalMethod;
+ }
+
+ /**
+ * Optionally specifies a method of the domain object that will be used to
+ * obtain a contained domain object. That contained domain object will be
+ * used for the ACL evaluation. This is useful if a domain object contains
+ * a parent that an ACL evaluation should be targeted for, instead of the
+ * child domain object (which perhaps is being created and as such does
+ * not yet have any ACL permissions)
+ *
+ * @return null to use the domain object, or the name of a
+ * method (that requires no arguments) that should be invoked to
+ * obtain an Object which will be the domain object
+ * used for ACL evaluation
+ */
+ public String getInternalMethod() {
+ return internalMethod;
+ }
+
public void setProcessConfigAttribute(String processConfigAttribute) {
this.processConfigAttribute = processConfigAttribute;
}
@@ -222,6 +254,48 @@ public class BasicAclEntryVoter implements AccessDecisionVoter,
return AccessDecisionVoter.ACCESS_ABSTAIN;
}
+ // Evaluate if we are required to use an inner domain object
+ if ((internalMethod != null) && !"".equals(internalMethod)) {
+ try {
+ Class clazz = domainObject.getClass();
+ Method method = clazz.getMethod(internalMethod, null);
+ domainObject = method.invoke(domainObject, null);
+ } catch (NoSuchMethodException nsme) {
+ throw new AuthorizationServiceException(
+ "Object of class '" + domainObject.getClass()
+ + "' does not provide the requested internalMethod: "
+ + internalMethod);
+ } catch (IllegalAccessException iae) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("IllegalAccessException", iae);
+
+ if (iae.getCause() != null) {
+ logger.debug("Cause: "
+ + iae.getCause().getMessage(),
+ iae.getCause());
+ }
+ }
+
+ throw new AuthorizationServiceException(
+ "Problem invoking internalMethod: "
+ + internalMethod + " for object: " + domainObject);
+ } catch (InvocationTargetException ite) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("InvocationTargetException", ite);
+
+ if (ite.getCause() != null) {
+ logger.debug("Cause: "
+ + ite.getCause().getMessage(),
+ ite.getCause());
+ }
+ }
+
+ throw new AuthorizationServiceException(
+ "Problem invoking internalMethod: "
+ + internalMethod + " for object: " + domainObject);
+ }
+ }
+
// Obtain the ACLs applicable to the domain object
AclEntry[] acls = aclManager.getAcls(domainObject,
authentication);