ソースを参照

Refactor MethodDefinitionMap to use Method, not MethodInvocation. Refactor AbstractSecurityInterceptor to not force use of Throwable. Move AOP Alliance based MethodSecurityInterceptor to separate package.

Ben Alex 21 年 前
コミット
992cf44b36
20 ファイル変更229 行追加211 行削除
  1. 47 56
      core/src/main/java/org/acegisecurity/intercept/AbstractSecurityInterceptor.java
  2. 53 0
      core/src/main/java/org/acegisecurity/intercept/InterceptorStatusToken.java
  3. 0 50
      core/src/main/java/org/acegisecurity/intercept/SecurityInterceptorCallback.java
  4. 49 16
      core/src/main/java/org/acegisecurity/intercept/method/AbstractMethodDefinitionSource.java
  5. 4 7
      core/src/main/java/org/acegisecurity/intercept/method/MethodDefinitionAttributes.java
  6. 12 14
      core/src/main/java/org/acegisecurity/intercept/method/MethodDefinitionMap.java
  7. 1 2
      core/src/main/java/org/acegisecurity/intercept/method/MethodDefinitionSource.java
  8. 4 2
      core/src/main/java/org/acegisecurity/intercept/method/aopalliance/MethodDefinitionSourceAdvisor.java
  9. 19 10
      core/src/main/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptor.java
  10. 6 0
      core/src/main/java/org/acegisecurity/intercept/method/aopalliance/package.html
  11. 2 2
      core/src/main/java/org/acegisecurity/intercept/method/package.html
  12. 9 11
      core/src/main/java/org/acegisecurity/intercept/web/FilterSecurityInterceptor.java
  13. 1 1
      core/src/test/java/org/acegisecurity/intercept/method/MethodDefinitionAttributesTests.java
  14. 2 2
      core/src/test/java/org/acegisecurity/intercept/method/MockMethodDefinitionSource.java
  15. 3 1
      core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodDefinitionSourceAdvisorTests.java
  16. 10 30
      core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptorTests.java
  17. 1 1
      samples/attributes/src/applicationContext.xml
  18. 2 2
      samples/contacts/etc/ca/applicationContext.xml
  19. 2 2
      samples/contacts/etc/cas/applicationContext.xml
  20. 2 2
      samples/contacts/etc/filter/applicationContext.xml

+ 47 - 56
core/src/main/java/org/acegisecurity/intercept/AbstractSecurityInterceptor.java

@@ -76,8 +76,16 @@ import java.util.Set;
  * Perform any run-as replacement via the configured {@link RunAsManager}.
  * </li>
  * <li>
- * Perform a callback to the {@link SecurityInterceptorCallback}, which will
- * actually proceed with executing the object.
+ * Pass control back to the concrete subclass, which will actually proceed with
+ * executing the object. A {@link InterceptorStatusToken} is returned so that
+ * after the subclass has finished proceeding with  execution of the object,
+ * its finally clause can ensure the <code>AbstractSecurityInterceptor</code>
+ * is re-called and tidies up correctly.
+ * </li>
+ * <li>
+ * The concrete subclass will re-call the
+ * <code>AbstractSecurityInterceptor</code> via the {@link
+ * #afterInvocation(InterceptorStatusToken)} method.
  * </li>
  * <li>
  * If the <code>RunAsManager</code> replaced the <code>Authentication</code>
@@ -98,17 +106,20 @@ import java.util.Set;
  * object to false.
  * </li>
  * <li>
- * Perform a callback to the {@link SecurityInterceptorCallback}, which will
- * actually proceed with the invocation.
+ * As described above, the concrete subclass will be returned an
+ * <code>InterceptorStatusToken</code> which is subsequently re-presented to
+ * the <code>AbstractSecurityInterceptor</code> after the secure object has
+ * been executed. The <code>AbstractSecurityInterceptor</code> will take no
+ * further action when its {@link #afterInvocation(InterceptorStatusToken)} is
+ * called.
  * </li>
  * </ol>
  * 
  * </li>
  * <li>
- * Return the result from the <code>SecurityInterceptorCallback</code> to the
- * method that called {@link AbstractSecurityInterceptor#interceptor(Object,
- * SecurityInterceptorCallback)}. This is almost always a concrete subclass of
- * the <code>AbstractSecurityInterceptor</code>.
+ * Control again returns to the concrete subclass, which will return to the
+ * caller any result or exception that occurred when it proceeded with the
+ * execution of the secure object.
  * </li>
  * </ol>
  * </p>
@@ -226,37 +237,24 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean {
         }
     }
 
-    /**
-     * Does the work of authenticating and authorizing the request.
-     * 
-     * <P>
-     * Throws {@link net.sf.acegisecurity.AcegiSecurityException} and its
-     * subclasses.
-     * </p>
-     *
-     * @param object details of a secure object invocation
-     * @param callback the object that will complete the target secure object
-     *        invocation
-     *
-     * @return The value that was returned by the
-     *         <code>SecurityInterceptorCallback</code>
-     *
-     * @throws Throwable if any error occurs during the
-     *         <code>SecurityInterceptorCallback</code>
-     * @throws IllegalArgumentException if a required argument was missing or
-     *         invalid
-     * @throws AuthenticationCredentialsNotFoundException if the
-     *         <code>ContextHolder</code> is not populated with a valid
-     *         <code>SecureContext</code>
-     */
-    public Object interceptor(Object object,
-        SecurityInterceptorCallback callback) throws Throwable {
-        if (object == null) {
-            throw new IllegalArgumentException("Object was null");
+    protected void afterInvocation(InterceptorStatusToken token) {
+        if (token == null) {
+            return;
+        }
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Reverting to original Authentication: "
+                + token.getAuthenticated().toString());
         }
 
-        if (callback == null) {
-            throw new IllegalArgumentException("Callback was null");
+        SecureContext secureContext = (SecureContext) ContextHolder.getContext();
+        secureContext.setAuthentication(token.getAuthenticated());
+        ContextHolder.setContext(secureContext);
+    }
+
+    protected InterceptorStatusToken beforeInvocation(Object object) {
+        if (object == null) {
+            throw new IllegalArgumentException("Object was null");
         }
 
         if (!this.obtainObjectDefinitionSource().supports(object.getClass())) {
@@ -294,7 +292,11 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean {
             Authentication authenticated = this.authenticationManager
                 .authenticate(context.getAuthentication());
             authenticated.setAuthenticated(true);
-            logger.debug("Authenticated: " + authenticated.toString());
+
+            if (logger.isDebugEnabled()) {
+                logger.debug("Authenticated: " + authenticated.toString());
+            }
+
             context.setAuthentication(authenticated);
             ContextHolder.setContext((Context) context);
 
@@ -315,31 +317,20 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean {
                         "RunAsManager did not change Authentication object");
                 }
 
-                return callback.proceedWithObject(object);
+                return null; // no further work post-invocation
             } else {
                 if (logger.isDebugEnabled()) {
                     logger.debug("Switching to RunAs Authentication: "
                         + runAs.toString());
                 }
 
-                SecureContext origSecureContext = null;
+                context.setAuthentication(runAs);
+                ContextHolder.setContext((Context) context);
 
-                try {
-                    origSecureContext = (SecureContext) ContextHolder
-                        .getContext();
-                    context.setAuthentication(runAs);
-                    ContextHolder.setContext((Context) context);
+                InterceptorStatusToken token = new InterceptorStatusToken();
+                token.setAuthenticated(authenticated);
 
-                    return callback.proceedWithObject(object);
-                } finally {
-                    if (logger.isDebugEnabled()) {
-                        logger.debug("Reverting to original Authentication: "
-                            + authenticated.toString());
-                    }
-
-                    origSecureContext.setAuthentication(authenticated);
-                    ContextHolder.setContext(origSecureContext);
-                }
+                return token; // revert to token.Authenticated post-invocation
             }
         } else {
             if (logger.isDebugEnabled()) {
@@ -365,7 +356,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean {
                 }
             }
 
-            return callback.proceedWithObject(object);
+            return null; // no further work post-invocation
         }
     }
 }

+ 53 - 0
core/src/main/java/org/acegisecurity/intercept/InterceptorStatusToken.java

@@ -0,0 +1,53 @@
+/* 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.intercept;
+
+import net.sf.acegisecurity.Authentication;
+
+
+/**
+ * A return object received by {@link AbstractSecurityInterceptor} subclasses.
+ * 
+ * <P>
+ * This class reflects the status of the security interception, so that the
+ * final call to <code>AbstractSecurityInterceptor</code> can tidy up
+ * correctly.
+ * </p>
+ * 
+ * <P>
+ * Whilst this class currently only wraps a single object, it has been modelled
+ * as a class so that future changes to the operation of
+ * <code>AbstractSecurityInterceptor</code> are abstracted from subclasses.
+ * </p>
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class InterceptorStatusToken {
+    //~ Instance fields ========================================================
+
+    private Authentication authenticated;
+
+    //~ Methods ================================================================
+
+    public void setAuthenticated(Authentication authenticated) {
+        this.authenticated = authenticated;
+    }
+
+    public Authentication getAuthenticated() {
+        return authenticated;
+    }
+}

+ 0 - 50
core/src/main/java/org/acegisecurity/intercept/SecurityInterceptorCallback.java

@@ -1,50 +0,0 @@
-/* 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.intercept;
-
-/**
- * Allows the {@link AbstractSecurityInterceptor} to continue the secure object
- * invocation at the appropriate time.
- * 
- * <P>
- * Concrete <code>AbstractSecurityInterceptor</code> subclasses are required to
- * provide a <code>SecurityInterceptorCallback</code>. This is called by the
- * <code>AbstractSecurityInterceptor</code> at the exact time the secure
- * object should have its processing continued. The exact way processing is
- * continued is specific to the type of secure object. For example, it may
- * involve proceeding with a method invocation, servicing a request, or
- * continuing a filter chain.
- * </p>
- * 
- * <P>
- * The result from processing the secure object should be returned to the
- * <code>AbstractSecurityInterceptor</code>, which in turn will ultimately
- * return it to the calling class.
- * </p>
- *
- * @author Ben Alex
- * @version $Id$
- */
-public interface SecurityInterceptorCallback {
-    //~ Methods ================================================================
-
-    /**
-     * Continues to process the secured object.
-     *
-     * @return the result (if any) from calling the secured object
-     */
-    public Object proceedWithObject(Object object) throws Throwable;
-}

+ 49 - 16
core/src/main/java/org/acegisecurity/intercept/method/AbstractMethodDefinitionSource.java

@@ -22,6 +22,11 @@ import org.aopalliance.intercept.MethodInvocation;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.reflect.CodeSignature;
+
+import java.lang.reflect.Method;
+
 
 /**
  * Abstract implementation of <Code>MethodDefinitionSource</code>.
@@ -39,26 +44,55 @@ public abstract class AbstractMethodDefinitionSource
 
     public ConfigAttributeDefinition getAttributes(Object object)
         throws IllegalArgumentException {
-        if ((object == null) || !this.supports(object.getClass())) {
-            throw new IllegalArgumentException(
-                "Object must be a MethodInvocation");
+        if (object == null) {
+            throw new IllegalArgumentException("Object cannot be null");
+        }
+
+        if (object instanceof MethodInvocation) {
+            return this.lookupAttributes(((MethodInvocation) object).getMethod());
+        }
+
+        if (object instanceof JoinPoint) {
+            JoinPoint jp = (JoinPoint) object;
+            Class targetClazz = jp.getTarget().getClass();
+            String targetMethodName = jp.getStaticPart().getSignature().getName();
+            Class[] types = ((CodeSignature) jp.getStaticPart().getSignature())
+                .getParameterTypes();
+
+            if (logger.isDebugEnabled()) {
+                logger.debug("Target Class: " + targetClazz);
+                logger.debug("Target Method Name: " + targetMethodName);
+
+                for (int i = 0; i < types.length; i++) {
+                    if (logger.isDebugEnabled()) {
+                        logger.debug("Target Method Arg #" + i + ": "
+                            + types[i]);
+                    }
+                }
+            }
+
+            try {
+                return this.lookupAttributes(targetClazz.getMethod(
+                        targetMethodName, types));
+            } catch (NoSuchMethodException nsme) {
+                throw new IllegalArgumentException(
+                    "Could not obtain target method from JoinPoint: " + jp);
+            }
         }
 
-        return this.lookupAttributes((MethodInvocation) object);
+        throw new IllegalArgumentException(
+            "Object must be a MethodInvocation or JoinPoint");
     }
 
     public boolean supports(Class clazz) {
-        if (MethodInvocation.class.isAssignableFrom(clazz)) {
-            return true;
-        } else {
-            return false;
-        }
+        return (MethodInvocation.class.isAssignableFrom(clazz)
+        || JoinPoint.class.isAssignableFrom(clazz));
     }
 
     /**
      * Performs the actual lookup of the relevant
      * <code>ConfigAttributeDefinition</code> for the specified
-     * <code>MethodInvocation</code>.
+     * <code>Method</code> which is subject of the method invocation.
      * 
      * <P>
      * Provided so subclasses need only to provide one basic method to properly
@@ -67,15 +101,14 @@ public abstract class AbstractMethodDefinitionSource
      * 
      * <p>
      * Returns <code>null</code> if there are no matching attributes for the
-     * method invocation.
+     * method.
      * </p>
      *
-     * @param mi the method being invoked for which configuration attributes
-     *        should be looked up
+     * @param method the method being invoked for which configuration
+     *        attributes should be looked up
      *
      * @return the <code>ConfigAttributeDefinition</code> that applies to the
-     *         specified <code>MethodInvocation</code>
+     *         specified <code>Method</code>
      */
-    protected abstract ConfigAttributeDefinition lookupAttributes(
-        MethodInvocation mi);
+    protected abstract ConfigAttributeDefinition lookupAttributes(Method method);
 }

+ 4 - 7
core/src/main/java/org/acegisecurity/intercept/method/MethodDefinitionAttributes.java

@@ -18,8 +18,6 @@ package net.sf.acegisecurity.intercept.method;
 import net.sf.acegisecurity.ConfigAttribute;
 import net.sf.acegisecurity.ConfigAttributeDefinition;
 
-import org.aopalliance.intercept.MethodInvocation;
-
 import org.springframework.metadata.Attributes;
 
 import java.lang.reflect.Method;
@@ -85,11 +83,10 @@ public class MethodDefinitionAttributes extends AbstractMethodDefinitionSource {
         return null;
     }
 
-    protected ConfigAttributeDefinition lookupAttributes(
-        MethodInvocation invocation) {
+    protected ConfigAttributeDefinition lookupAttributes(Method method) {
         ConfigAttributeDefinition definition = new ConfigAttributeDefinition();
 
-        Class interceptedClass = invocation.getMethod().getDeclaringClass();
+        Class interceptedClass = method.getDeclaringClass();
 
         // add the class level attributes for the implementing class
         addClassAttributes(definition, interceptedClass);
@@ -98,10 +95,10 @@ public class MethodDefinitionAttributes extends AbstractMethodDefinitionSource {
         addClassAttributes(definition, interceptedClass.getInterfaces());
 
         // add the method level attributes for the implemented method
-        addMethodAttributes(definition, invocation.getMethod());
+        addMethodAttributes(definition, method);
 
         // add the method level attributes for the implemented intreface methods
-        addInterfaceMethodAttributes(definition, invocation.getMethod());
+        addInterfaceMethodAttributes(definition, method);
 
         if (definition.size() == 0) {
             return null;

+ 12 - 14
core/src/main/java/org/acegisecurity/intercept/method/MethodDefinitionMap.java

@@ -38,9 +38,9 @@ import java.util.Map;
  * 
  * <p>
  * For consistency with {@link MethodDefinitionAttributes} as well as support
- * for {@link MethodDefinitionSourceAdvisor}, this implementation will return
- * a <code>ConfigAttributeDefinition</code> containing all configuration
- * attributes defined against:
+ * for <code>MethodDefinitionSourceAdvisor</code>, this implementation will
+ * return a <code>ConfigAttributeDefinition</code> containing all
+ * configuration attributes defined against:
  * 
  * <ul>
  * <li>
@@ -83,8 +83,8 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
     /**
      * Obtains the configuration attributes explicitly defined against this
      * bean. This method will not return implicit configuration attributes
-     * that may be returned by {@link #lookupAttributes(MethodInvocation)} as
-     * it does not have access to a method invocation at this time.
+     * that may be returned by {@link #lookupAttributes(Method)} as it does
+     * not have access to a method invocation at this time.
      *
      * @return the attributes explicitly defined against this bean
      */
@@ -95,9 +95,8 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
     /**
      * Obtains the number of configuration attributes explicitly defined
      * against this bean. This method will not return implicit configuration
-     * attributes that may be returned by {@link
-     * #lookupAttributes(MethodInvocation)} as it does not have access to a
-     * method invocation at this time.
+     * attributes that may be returned by {@link #lookupAttributes(Method)} as
+     * it does not have access to a method invocation at this time.
      *
      * @return the number of configuration attributes explicitly defined
      *         against this bean
@@ -209,25 +208,24 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
         }
     }
 
-    protected ConfigAttributeDefinition lookupAttributes(MethodInvocation mi) {
+    protected ConfigAttributeDefinition lookupAttributes(Method method) {
         ConfigAttributeDefinition definition = new ConfigAttributeDefinition();
 
         // Add attributes explictly defined for this method invocation
         ConfigAttributeDefinition directlyAssigned = (ConfigAttributeDefinition) this.methodMap
-            .get(mi.getMethod());
+            .get(method);
         merge(definition, directlyAssigned);
 
         // Add attributes explicitly defined for this method invocation's interfaces
-        Class[] interfaces = mi.getMethod().getDeclaringClass().getInterfaces();
+        Class[] interfaces = method.getDeclaringClass().getInterfaces();
 
         for (int i = 0; i < interfaces.length; i++) {
             Class clazz = interfaces[i];
 
             try {
                 // Look for the method on the current interface
-                Method interfaceMethod = clazz.getDeclaredMethod(mi.getMethod()
-                                                                   .getName(),
-                        mi.getMethod().getParameterTypes());
+                Method interfaceMethod = clazz.getDeclaredMethod(method.getName(),
+                        method.getParameterTypes());
                 ConfigAttributeDefinition interfaceAssigned = (ConfigAttributeDefinition) this.methodMap
                     .get(interfaceMethod);
                 merge(definition, interfaceAssigned);

+ 1 - 2
core/src/main/java/org/acegisecurity/intercept/method/MethodDefinitionSource.java

@@ -20,8 +20,7 @@ import net.sf.acegisecurity.intercept.ObjectDefinitionSource;
 
 /**
  * Marker interface for <code>ObjectDefinitionSource</code> implementations
- * that are designed to perform lookups keyed on
- * <code>MethodInvocation</code>s.
+ * that are designed to perform lookups keyed on <code>Method</code>s.
  *
  * @author Ben Alex
  * @version $Id$

+ 4 - 2
core/src/main/java/org/acegisecurity/intercept/method/MethodDefinitionSourceAdvisor.java → core/src/main/java/org/acegisecurity/intercept/method/aopalliance/MethodDefinitionSourceAdvisor.java

@@ -13,7 +13,9 @@
  * limitations under the License.
  */
 
-package net.sf.acegisecurity.intercept.method;
+package net.sf.acegisecurity.intercept.method.aopalliance;
+
+import net.sf.acegisecurity.intercept.method.MethodDefinitionSource;
 
 import org.aopalliance.intercept.MethodInvocation;
 
@@ -46,7 +48,7 @@ import java.lang.reflect.Method;
  * <p>
  * Based on Spring's TransactionAttributeSourceAdvisor.
  * </p>
- * 
+ *
  * @author Ben Alex
  * @version $Id$
  */

+ 19 - 10
core/src/main/java/org/acegisecurity/intercept/method/MethodSecurityInterceptor.java → core/src/main/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptor.java

@@ -13,22 +13,26 @@
  * limitations under the License.
  */
 
-package net.sf.acegisecurity.intercept.method;
+package net.sf.acegisecurity.intercept.method.aopalliance;
 
 import net.sf.acegisecurity.intercept.AbstractSecurityInterceptor;
+import net.sf.acegisecurity.intercept.InterceptorStatusToken;
 import net.sf.acegisecurity.intercept.ObjectDefinitionSource;
-import net.sf.acegisecurity.intercept.SecurityInterceptorCallback;
+import net.sf.acegisecurity.intercept.method.MethodDefinitionSource;
 
 import org.aopalliance.intercept.MethodInterceptor;
 import org.aopalliance.intercept.MethodInvocation;
 
 
 /**
- * Provides security interception of method invocations.
+ * Provides security interception of AOP Alliance based method invocations.
  * 
  * <p>
  * The <code>ObjectDefinitionSource</code> required by this security
- * interceptor is of type {@link MethodDefinitionSource}.
+ * interceptor is of type {@link MethodDefinitionSource}. This is shared with
+ * the AspectJ based security interceptor
+ * (<code>AspectJSecurityInterceptor</code>), since both work with Java
+ * <code>Method</code>s.
  * </p>
  * 
  * <P>
@@ -39,7 +43,7 @@ import org.aopalliance.intercept.MethodInvocation;
  * @version $Id$
  */
 public class MethodSecurityInterceptor extends AbstractSecurityInterceptor
-    implements MethodInterceptor, SecurityInterceptorCallback {
+    implements MethodInterceptor {
     //~ Instance fields ========================================================
 
     private MethodDefinitionSource objectDefinitionSource;
@@ -79,14 +83,19 @@ public class MethodSecurityInterceptor extends AbstractSecurityInterceptor
      * @throws Throwable if any error occurs
      */
     public Object invoke(MethodInvocation mi) throws Throwable {
-        return super.interceptor(mi, this);
+        Object result;
+        InterceptorStatusToken token = super.beforeInvocation(mi);
+
+        try {
+            result = mi.proceed();
+        } finally {
+            super.afterInvocation(token);
+        }
+
+        return result;
     }
 
     public ObjectDefinitionSource obtainObjectDefinitionSource() {
         return this.objectDefinitionSource;
     }
-
-    public Object proceedWithObject(Object object) throws Throwable {
-        return ((MethodInvocation) object).proceed();
-    }
 }

+ 6 - 0
core/src/main/java/org/acegisecurity/intercept/method/aopalliance/package.html

@@ -0,0 +1,6 @@
+<html>
+<body>
+Enforces security for AOP Alliance <code>MethodInvocation</code>s, such as via
+Spring AOP.
+</body>
+</html>

+ 2 - 2
core/src/main/java/org/acegisecurity/intercept/method/package.html

@@ -1,6 +1,6 @@
 <html>
 <body>
-Enforces security for <code>MethodInvocation</code>s, such as via
-Spring AOP.
+Provides support objects for securing Java method invocations
+via different AOP libraries.
 </body>
 </html>

+ 9 - 11
core/src/main/java/org/acegisecurity/intercept/web/FilterSecurityInterceptor.java

@@ -16,8 +16,8 @@
 package net.sf.acegisecurity.intercept.web;
 
 import net.sf.acegisecurity.intercept.AbstractSecurityInterceptor;
+import net.sf.acegisecurity.intercept.InterceptorStatusToken;
 import net.sf.acegisecurity.intercept.ObjectDefinitionSource;
-import net.sf.acegisecurity.intercept.SecurityInterceptorCallback;
 
 
 /**
@@ -43,8 +43,7 @@ import net.sf.acegisecurity.intercept.SecurityInterceptorCallback;
  * @author Ben Alex
  * @version $Id$
  */
-public class FilterSecurityInterceptor extends AbstractSecurityInterceptor
-    implements SecurityInterceptorCallback {
+public class FilterSecurityInterceptor extends AbstractSecurityInterceptor {
     //~ Instance fields ========================================================
 
     private FilterInvocationDefinitionSource objectDefinitionSource;
@@ -75,17 +74,16 @@ public class FilterSecurityInterceptor extends AbstractSecurityInterceptor
     }
 
     public void invoke(FilterInvocation fi) throws Throwable {
-        super.interceptor(fi, this);
+        InterceptorStatusToken token = super.beforeInvocation(fi);
+
+        try {
+            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
+        } finally {
+            super.afterInvocation(token);
+        }
     }
 
     public ObjectDefinitionSource obtainObjectDefinitionSource() {
         return this.objectDefinitionSource;
     }
-
-    public Object proceedWithObject(Object object) throws Throwable {
-        FilterInvocation fi = (FilterInvocation) object;
-        fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
-
-        return null;
-    }
 }

+ 1 - 1
core/src/test/java/org/acegisecurity/intercept/method/MethodDefinitionAttributesTests.java

@@ -246,7 +246,7 @@ public class MethodDefinitionAttributesTests extends TestCase {
             "attributes");
 
         p.setProperty(PREFIX + "securityInterceptor.class",
-            "net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor");
+            "net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor");
         p.setProperty(PREFIX + "securityInterceptor.authenticationManager(ref)",
             "authentication");
         p.setProperty(PREFIX + "securityInterceptor.accessDecisionManager(ref)",

+ 2 - 2
core/src/test/java/org/acegisecurity/intercept/method/MockMethodDefinitionSource.java

@@ -18,7 +18,7 @@ package net.sf.acegisecurity.intercept.method;
 import net.sf.acegisecurity.ConfigAttributeDefinition;
 import net.sf.acegisecurity.SecurityConfig;
 
-import org.aopalliance.intercept.MethodInvocation;
+import java.lang.reflect.Method;
 
 import java.util.Iterator;
 import java.util.List;
@@ -82,7 +82,7 @@ public class MockMethodDefinitionSource extends AbstractMethodDefinitionSource {
         }
     }
 
-    protected ConfigAttributeDefinition lookupAttributes(MethodInvocation mi) {
+    protected ConfigAttributeDefinition lookupAttributes(Method method) {
         throw new UnsupportedOperationException("mock method not implemented");
     }
 }

+ 3 - 1
core/src/test/java/org/acegisecurity/intercept/method/MethodDefinitionSourceAdvisorTests.java → core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodDefinitionSourceAdvisorTests.java

@@ -13,11 +13,13 @@
  * limitations under the License.
  */
 
-package net.sf.acegisecurity.intercept.method;
+package net.sf.acegisecurity.intercept.method.aopalliance;
 
 import junit.framework.TestCase;
 
 import net.sf.acegisecurity.TargetObject;
+import net.sf.acegisecurity.intercept.method.MethodDefinitionMap;
+import net.sf.acegisecurity.intercept.method.MethodDefinitionSourceEditor;
 
 import org.springframework.aop.framework.AopConfigException;
 

+ 10 - 30
core/src/test/java/org/acegisecurity/intercept/method/MethodSecurityInterceptorTests.java → core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptorTests.java

@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-package net.sf.acegisecurity.intercept.method;
+package net.sf.acegisecurity.intercept.method.aopalliance;
 
 import junit.framework.TestCase;
 
@@ -28,21 +28,23 @@ import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.ITargetObject;
 import net.sf.acegisecurity.MockAccessDecisionManager;
 import net.sf.acegisecurity.MockAuthenticationManager;
+import net.sf.acegisecurity.MockMethodInvocation;
 import net.sf.acegisecurity.MockRunAsManager;
 import net.sf.acegisecurity.RunAsManager;
 import net.sf.acegisecurity.context.ContextHolder;
 import net.sf.acegisecurity.context.ContextImpl;
 import net.sf.acegisecurity.context.SecureContext;
 import net.sf.acegisecurity.context.SecureContextImpl;
-import net.sf.acegisecurity.intercept.SecurityInterceptorCallback;
+import net.sf.acegisecurity.intercept.method.AbstractMethodDefinitionSource;
+import net.sf.acegisecurity.intercept.method.MockMethodDefinitionSource;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 import net.sf.acegisecurity.runas.RunAsManagerImpl;
 
-import org.aopalliance.intercept.MethodInvocation;
-
 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
 
+import java.lang.reflect.Method;
+
 import java.util.Iterator;
 import java.util.Properties;
 
@@ -250,25 +252,13 @@ public class MethodSecurityInterceptorTests extends TestCase {
         }
     }
 
-    public void testRejectsCallsWhenCallbackIsNull() throws Throwable {
-        MethodSecurityInterceptor interceptor = new MethodSecurityInterceptor();
-
-        try {
-            interceptor.interceptor(new Object(), null);
-            fail("Should have thrown IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {
-            assertEquals("Callback was null", expected.getMessage());
-        }
-    }
-
     public void testRejectsCallsWhenObjectDefinitionSourceDoesNotSupportObject()
         throws Throwable {
         MethodSecurityInterceptor interceptor = new MethodSecurityInterceptor();
         interceptor.setObjectDefinitionSource(new MockObjectDefinitionSourceWhichOnlySupportsStrings());
 
         try {
-            interceptor.interceptor(new Integer(1),
-                new MockSecurityInterceptorCallback());
+            interceptor.invoke(new MockMethodInvocation());
             fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException expected) {
             assertTrue(expected.getMessage().startsWith("ObjectDefinitionSource does not support objects of type"));
@@ -279,7 +269,7 @@ public class MethodSecurityInterceptorTests extends TestCase {
         MethodSecurityInterceptor interceptor = new MethodSecurityInterceptor();
 
         try {
-            interceptor.interceptor(null, new MockSecurityInterceptorCallback());
+            interceptor.invoke(null);
             fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException expected) {
             assertEquals("Object was null", expected.getMessage());
@@ -420,7 +410,7 @@ public class MethodSecurityInterceptorTests extends TestCase {
             "net.sf.acegisecurity.MockRunAsManager");
 
         p.setProperty(PREFIX + "securityInterceptor.class",
-            "net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor");
+            "net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor");
         p.setProperty(PREFIX + "securityInterceptor.authenticationManager(ref)",
             "authentication");
         p.setProperty(PREFIX + "securityInterceptor.accessDecisionManager(ref)",
@@ -482,8 +472,7 @@ public class MethodSecurityInterceptorTests extends TestCase {
             }
         }
 
-        protected ConfigAttributeDefinition lookupAttributes(
-            MethodInvocation mi) {
+        protected ConfigAttributeDefinition lookupAttributes(Method method) {
             throw new UnsupportedOperationException(
                 "mock method not implemented");
         }
@@ -509,13 +498,4 @@ public class MethodSecurityInterceptorTests extends TestCase {
             return true;
         }
     }
-
-    private class MockSecurityInterceptorCallback
-        implements SecurityInterceptorCallback {
-        public Object proceedWithObject(Object object)
-            throws Throwable {
-            throw new UnsupportedOperationException(
-                "mock method not implemented");
-        }
-    }
 }

+ 1 - 1
samples/attributes/src/applicationContext.xml

@@ -65,7 +65,7 @@
 	</bean>
 
 	<!-- We don't validate config attributes, as it's unsupported by MethodDefinitionAttributes -->
-	<bean id="securityInterceptor" class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
+	<bean id="securityInterceptor" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
     	<property name="validateConfigAttributes"><value>false</value></property>
     	<property name="authenticationManager"><ref local="authenticationManager"/></property>
     	<property name="accessDecisionManager"><ref local="accessDecisionManager"/></property>

+ 2 - 2
samples/contacts/etc/ca/applicationContext.xml

@@ -82,7 +82,7 @@
 
 	<!-- ===================== SECURITY DEFINITIONS ======================= -->
 	
-	<bean id="publicContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
+	<bean id="publicContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
     	<property name="authenticationManager"><ref local="authenticationManager"/></property>
     	<property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
     	<property name="runAsManager"><ref local="runAsManager"/></property>
@@ -97,7 +97,7 @@
 	</bean>
 
 	<!-- We expect all callers of the backend object to hold the role ROLE_RUN_AS_SERVER -->
-	<bean id="backendContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
+	<bean id="backendContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
     	<property name="authenticationManager"><ref local="authenticationManager"/></property>
     	<property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
     	<property name="runAsManager"><ref local="runAsManager"/></property>

+ 2 - 2
samples/contacts/etc/cas/applicationContext.xml

@@ -104,7 +104,7 @@
 
 	<!-- ===================== SECURITY DEFINITIONS ======================= -->
 	
-	<bean id="publicContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
+	<bean id="publicContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
     	<property name="authenticationManager"><ref local="authenticationManager"/></property>
     	<property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
     	<property name="runAsManager"><ref local="runAsManager"/></property>
@@ -119,7 +119,7 @@
 	</bean>
 
 	<!-- We expect all callers of the backend object to hold the role ROLE_RUN_AS_SERVER -->
-	<bean id="backendContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
+	<bean id="backendContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
     	<property name="authenticationManager"><ref local="authenticationManager"/></property>
     	<property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
     	<property name="runAsManager"><ref local="runAsManager"/></property>

+ 2 - 2
samples/contacts/etc/filter/applicationContext.xml

@@ -93,7 +93,7 @@
 
    <!-- ===================== SECURITY DEFINITIONS ======================= -->
 
-   <bean id="publicContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
+   <bean id="publicContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
       <property name="authenticationManager"><ref local="authenticationManager"/></property>
       <property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
       <property name="runAsManager"><ref local="runAsManager"/></property>
@@ -108,7 +108,7 @@
    </bean>
 
    <!-- We expect all callers of the backend object to hold the role ROLE_RUN_AS_SERVER -->
-   <bean id="backendContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
+   <bean id="backendContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
       <property name="authenticationManager"><ref local="authenticationManager"/></property>
       <property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
       <property name="runAsManager"><ref local="runAsManager"/></property>