Pārlūkot izejas kodu

SEC-999: First commit of expression-based authorization implementation

Luke Taylor 17 gadi atpakaļ
vecāks
revīzija
4aa32f7d06
45 mainītis faili ar 1206 papildinājumiem un 562 dzēšanām
  1. 7 4
      core/pom.xml
  2. 3 30
      core/src/main/java/org/springframework/security/ConfigAttributeDefinition.java
  3. 1 2
      core/src/main/java/org/springframework/security/afterinvocation/ArrayFilterer.java
  4. 1 1
      core/src/main/java/org/springframework/security/afterinvocation/Filterer.java
  5. 36 31
      core/src/main/java/org/springframework/security/annotation/Jsr250MethodDefinitionSource.java
  6. 27 17
      core/src/main/java/org/springframework/security/annotation/SecuredMethodDefinitionSource.java
  7. 42 41
      core/src/main/java/org/springframework/security/config/BeanIds.java
  8. 85 77
      core/src/main/java/org/springframework/security/config/ConfigUtils.java
  9. 27 7
      core/src/main/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParser.java
  10. 4 4
      core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java
  11. 16 16
      core/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java
  12. 67 0
      core/src/main/java/org/springframework/security/expression/ExpressionUtils.java
  13. 14 0
      core/src/main/java/org/springframework/security/expression/MethodInvocationSecurityExpressionRoot.java
  14. 67 0
      core/src/main/java/org/springframework/security/expression/SecurityExpressionRoot.java
  15. 26 0
      core/src/main/java/org/springframework/security/expression/annotation/PostAuthorize.java
  16. 26 0
      core/src/main/java/org/springframework/security/expression/annotation/PostFilter.java
  17. 27 0
      core/src/main/java/org/springframework/security/expression/annotation/PreAuthorize.java
  18. 31 0
      core/src/main/java/org/springframework/security/expression/annotation/PreFilter.java
  19. 42 0
      core/src/main/java/org/springframework/security/expression/support/AbstractExpressionBasedMethodConfigAttribute.java
  20. 111 0
      core/src/main/java/org/springframework/security/expression/support/ExpressionAnnotationMethodDefinitionSource.java
  21. 110 0
      core/src/main/java/org/springframework/security/expression/support/MethodExpressionAfterInvocationProvider.java
  22. 109 0
      core/src/main/java/org/springframework/security/expression/support/MethodExpressionVoter.java
  23. 12 0
      core/src/main/java/org/springframework/security/expression/support/PostInvocationExpressionBasedMethodConfigAttribute.java
  24. 18 0
      core/src/main/java/org/springframework/security/expression/support/PreInvocationExpressionBasedMethodConfigAttribute.java
  25. 12 8
      core/src/main/java/org/springframework/security/intercept/method/AbstractFallbackMethodDefinitionSource.java
  26. 19 12
      core/src/main/java/org/springframework/security/intercept/method/MapBasedMethodDefinitionSource.java
  27. 0 71
      core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionAttributes.java
  28. 10 2
      core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionSourceEditor.java
  29. 8 7
      core/src/main/java/org/springframework/security/intercept/method/ProtectPointcutPostProcessor.java
  30. 3 3
      core/src/main/java/org/springframework/security/util/InMemoryXmlApplicationContext.java
  31. 2 1
      core/src/main/resources/META-INF/spring.schemas
  32. 12 0
      core/src/test/java/org/springframework/security/annotation/BusinessService.java
  33. 16 0
      core/src/test/java/org/springframework/security/annotation/BusinessServiceImpl.java
  34. 16 0
      core/src/test/java/org/springframework/security/annotation/Jsr250BusinessServiceImpl.java
  35. 24 21
      core/src/test/java/org/springframework/security/annotation/Jsr250MethodDefinitionSourceTests.java
  36. 19 24
      core/src/test/java/org/springframework/security/annotation/SecuredMethodDefinitionSourceTests.java
  37. 2 2
      core/src/test/java/org/springframework/security/config/CustomAfterInvocationProviderBeanDefinitionDecoratorTests.java
  38. 47 0
      core/src/test/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParserTests.java
  39. 71 0
      core/src/test/java/org/springframework/security/expression/support/MethodExpressionVoterTests.java
  40. 0 94
      core/src/test/java/org/springframework/security/intercept/method/AbstractMethodDefinitionSourceTests.java
  41. 9 6
      core/src/test/java/org/springframework/security/intercept/method/MapBasedMethodDefinitionSourceTests.java
  42. 0 57
      core/src/test/java/org/springframework/security/intercept/method/MethodDefinitionAttributesTests.java
  43. 12 5
      core/src/test/java/org/springframework/security/intercept/method/MockMethodDefinitionSource.java
  44. 15 10
      pom.xml
  45. 0 9
      samples/pom.xml

+ 7 - 4
core/pom.xml

@@ -10,6 +10,11 @@
     <name>Spring Security - Core</name>
 
     <dependencies>
+        <dependency>
+            <groupId>org.springframework.security</groupId>
+            <artifactId>spring-el-security</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-core</artifactId>
@@ -39,13 +44,11 @@
         </dependency>
         <dependency>
             <groupId>org.aspectj</groupId>
-        <artifactId>aspectjrt</artifactId>
-        <optional>true</optional>
+            <artifactId>com.springsource.org.aspectj.runtime</artifactId>
         </dependency>
         <dependency>
             <groupId>org.aspectj</groupId>
-        <artifactId>aspectjweaver</artifactId>
-        <optional>true</optional>
+            <artifactId>com.springsource.org.aspectj.weaver</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.ldap</groupId>

+ 3 - 30
core/src/main/java/org/springframework/security/ConfigAttributeDefinition.java

@@ -67,7 +67,7 @@ public class ConfigAttributeDefinition implements Serializable {
     public ConfigAttributeDefinition(ConfigAttribute attribute) {
         configAttributes = new ArrayList(1);
         configAttributes.add(attribute);
-        configAttributes = Collections.unmodifiableList(configAttributes);        
+        configAttributes = Collections.unmodifiableList(configAttributes);
     }
 
     /**
@@ -78,7 +78,7 @@ public class ConfigAttributeDefinition implements Serializable {
      */
     public ConfigAttributeDefinition(String[] attributeTokens) {
         configAttributes = new ArrayList(attributeTokens.length);
-        
+
         for (int i = 0; i < attributeTokens.length; i++) {
             configAttributes.add(new SecurityConfig(attributeTokens[i].trim()));
         }
@@ -98,33 +98,6 @@ public class ConfigAttributeDefinition implements Serializable {
 
         this.configAttributes = Collections.unmodifiableList(new ArrayList(configAttributes));
     }
-    
-    /**
-     * Creates a <tt>ConfigAttributeDefinition</tt> by including only those attributes which implement <tt>ConfigAttribute</tt>.
-     * 
-     * @param unfilteredInput a collection of various elements, zero or more which implement <tt>ConfigAttribute</tt> (can also be <tt>null</tt>)
-     * @return a ConfigAttributeDefinition if at least one <tt>ConfigAttribute</tt> was present, or <tt>null</tt> if none implemented it
-     */
-    public static ConfigAttributeDefinition createFiltered(Collection unfilteredInput) {
-    	if (unfilteredInput == null) {
-    		return null;
-    	}
-
-    	List configAttributes = new ArrayList();
-    	Iterator i = unfilteredInput.iterator();
-    	while (i.hasNext()) {
-    		Object element = i.next();
-    		if (element instanceof ConfigAttribute) {
-    			configAttributes.add(element);
-    		}
-    	}
-    	
-    	if (configAttributes.size() == 0) {
-    		return null;
-    	}
-    	
-    	return new ConfigAttributeDefinition(configAttributes);
-    }
 
     //~ Methods ========================================================================================================
 
@@ -160,7 +133,7 @@ public class ConfigAttributeDefinition implements Serializable {
      *
      * @return the configuration attributes stored in this instance.
      */
-    public Collection getConfigAttributes() {
+    public Collection<ConfigAttribute> getConfigAttributes() {
         return this.configAttributes;
     }
 

+ 1 - 2
core/src/main/java/org/springframework/security/afterinvocation/ArrayFilterer.java

@@ -36,8 +36,7 @@ import java.util.Set;
 class ArrayFilterer implements Filterer {
     //~ Static fields/initializers =====================================================================================
 
-    protected static final Log logger =
-            LogFactory.getLog(BasicAclEntryAfterInvocationCollectionFilteringProvider.class);
+    protected static final Log logger = LogFactory.getLog(ArrayFilterer.class);
 
     //~ Instance fields ================================================================================================
 

+ 1 - 1
core/src/main/java/org/springframework/security/afterinvocation/Filterer.java

@@ -19,7 +19,7 @@ import java.util.Iterator;
 
 
 /**
- * Filter strategy interface.
+ * Filterer strategy interface.
  *
  * @author Ben Alex
  * @author Paulo Neves

+ 36 - 31
core/src/main/java/org/springframework/security/annotation/Jsr250MethodDefinitionSource.java

@@ -26,12 +26,13 @@ import javax.annotation.security.PermitAll;
 import javax.annotation.security.RolesAllowed;
 
 import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.security.ConfigAttribute;
 import org.springframework.security.ConfigAttributeDefinition;
 import org.springframework.security.intercept.method.AbstractFallbackMethodDefinitionSource;
 
 
 /**
- * Sources method security metadata from major JSR 250 security annotations. 
+ * Sources method security metadata from major JSR 250 security annotations.
  *
  * @author Ben Alex
  * @version $Id$
@@ -39,38 +40,42 @@ import org.springframework.security.intercept.method.AbstractFallbackMethodDefin
  */
 public class Jsr250MethodDefinitionSource extends AbstractFallbackMethodDefinitionSource {
 
-	protected ConfigAttributeDefinition findAttributes(Class clazz) {
-		return processAnnotations(clazz.getAnnotations());
-	}
+    protected List<ConfigAttribute> findAttributes(Class clazz) {
+        return processAnnotations(clazz.getAnnotations());
+    }
+
+    protected List<ConfigAttribute> findAttributes(Method method, Class targetClass) {
+        return processAnnotations(AnnotationUtils.getAnnotations(method));
+    }
 
-	protected ConfigAttributeDefinition findAttributes(Method method, Class targetClass) {
-		return processAnnotations(AnnotationUtils.getAnnotations(method));
-	}
-	
     public Collection getConfigAttributeDefinitions() {
         return null;
     }
-    
-	private ConfigAttributeDefinition processAnnotations(Annotation[] annotations) {
-		if (annotations == null || annotations.length == 0) {
-			return null;
-		}
-		for (Annotation a: annotations) {
-			if (a instanceof DenyAll) {
-				return new ConfigAttributeDefinition(Jsr250SecurityConfig.DENY_ALL_ATTRIBUTE);
-			}
-			if (a instanceof PermitAll) {
-				return new ConfigAttributeDefinition(Jsr250SecurityConfig.PERMIT_ALL_ATTRIBUTE);
-			}
-			if (a instanceof RolesAllowed) {
-				RolesAllowed ra = (RolesAllowed) a;
-				List attributes = new ArrayList();
-				for (String allowed : ra.value()) {
-					attributes.add(new Jsr250SecurityConfig(allowed));
-				}
-				return new ConfigAttributeDefinition(attributes);
-			}
-		}
-		return null;
-	}
+
+    private List<ConfigAttribute> processAnnotations(Annotation[] annotations) {
+        if (annotations == null || annotations.length == 0) {
+            return null;
+        }
+        List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>();
+
+        for (Annotation a: annotations) {
+            if (a instanceof DenyAll) {
+                attributes.add(Jsr250SecurityConfig.DENY_ALL_ATTRIBUTE);
+                return attributes;
+            }
+            if (a instanceof PermitAll) {
+                attributes.add(Jsr250SecurityConfig.PERMIT_ALL_ATTRIBUTE);
+                return attributes;
+            }
+            if (a instanceof RolesAllowed) {
+                RolesAllowed ra = (RolesAllowed) a;
+
+                for (String allowed : ra.value()) {
+                    attributes.add(new Jsr250SecurityConfig(allowed));
+                }
+                return attributes;
+            }
+        }
+        return null;
+    }
 }

+ 27 - 17
core/src/main/java/org/springframework/security/annotation/SecuredMethodDefinitionSource.java

@@ -17,38 +17,48 @@ package org.springframework.security.annotation;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
 import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.security.ConfigAttribute;
+import org.springframework.security.SecurityConfig;
 import org.springframework.security.intercept.method.AbstractFallbackMethodDefinitionSource;
 
 
 /**
- * Sources method security metadata from Spring Security's {@link Secured} annotation. 
+ * Sources method security metadata from Spring Security's {@link Secured} annotation.
  *
  * @author Ben Alex
  * @version $Id$
  */
 public class SecuredMethodDefinitionSource extends AbstractFallbackMethodDefinitionSource {
 
-	protected ConfigAttributeDefinition findAttributes(Class clazz) {
-		return processAnnotation(clazz.getAnnotation(Secured.class));
-	}
+    protected List<ConfigAttribute> findAttributes(Class clazz) {
+        return processAnnotation(clazz.getAnnotation(Secured.class));
+    }
+
+    protected List<ConfigAttribute> findAttributes(Method method, Class targetClass) {
+        return processAnnotation(AnnotationUtils.findAnnotation(method, Secured.class));
+    }
 
-	protected ConfigAttributeDefinition findAttributes(Method method, Class targetClass) {
-		return processAnnotation(AnnotationUtils.findAnnotation(method, Secured.class));
-	}
-	
     public Collection getConfigAttributeDefinitions() {
         return null;
     }
-    
-	private ConfigAttributeDefinition processAnnotation(Annotation a) {
-		if (a == null || !(a instanceof Secured)) {
-			return null;
-		}
-		Secured secured = (Secured) a;
-		return new ConfigAttributeDefinition(secured.value());
-	}
+
+    private List<ConfigAttribute> processAnnotation(Annotation a) {
+        if (a == null || !(a instanceof Secured)) {
+            return null;
+        }
+
+        String[] attributeTokens = ((Secured) a).value();
+        List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>(attributeTokens.length);
+
+        for(String token : attributeTokens) {
+            attributes.add(new SecurityConfig(token));
+        }
+
+        return attributes;
+    }
 }

+ 42 - 41
core/src/main/java/org/springframework/security/config/BeanIds.java

@@ -11,56 +11,57 @@ package org.springframework.security.config;
 public abstract class BeanIds {
 
     /** External alias for FilterChainProxy bean, for use in web.xml files */
-    public static final String SPRING_SECURITY_FILTER_CHAIN = "springSecurityFilterChain";  
+    public static final String SPRING_SECURITY_FILTER_CHAIN = "springSecurityFilterChain";
 
     /** Package protected as end users shouldn't really be using this BFPP directly */
-	static final String INTERCEPT_METHODS_BEAN_FACTORY_POST_PROCESSOR = "_interceptMethodsBeanfactoryPP";
+    static final String INTERCEPT_METHODS_BEAN_FACTORY_POST_PROCESSOR = "_interceptMethodsBeanfactoryPP";
     static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = "_contextSettingPostProcessor";
     static final String ENTRY_POINT_INJECTION_POST_PROCESSOR = "_entryPointInjectionBeanPostProcessor";
     static final String USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR = "_userServiceInjectionPostProcessor";
-    static final String SESSION_REGISTRY_INJECTION_POST_PROCESSOR = "_sessionRegistryInjectionPostProcessor";    
+    static final String SESSION_REGISTRY_INJECTION_POST_PROCESSOR = "_sessionRegistryInjectionPostProcessor";
     static final String FILTER_CHAIN_POST_PROCESSOR = "_filterChainProxyPostProcessor";
     static final String FILTER_LIST = "_filterChainList";
 
     public static final String JDBC_USER_DETAILS_MANAGER = "_jdbcUserDetailsManager";
-	public static final String USER_DETAILS_SERVICE = "_userDetailsService";
-	public static final String ANONYMOUS_PROCESSING_FILTER = "_anonymousProcessingFilter";
-	public static final String ANONYMOUS_AUTHENTICATION_PROVIDER = "_anonymousAuthenticationProvider";
-	public static final String BASIC_AUTHENTICATION_FILTER = "_basicAuthenticationFilter";
-	public static final String BASIC_AUTHENTICATION_ENTRY_POINT = "_basicAuthenticationEntryPoint";
-	public static final String SESSION_REGISTRY = "_sessionRegistry";
-	public static final String CONCURRENT_SESSION_FILTER = "_concurrentSessionFilter";
-	public static final String CONCURRENT_SESSION_CONTROLLER = "_concurrentSessionController";
-	public static final String ACCESS_MANAGER = "_accessManager";
-	public static final String AUTHENTICATION_MANAGER = "_authenticationManager";
-	public static final String AFTER_INVOCATION_MANAGER = "_afterInvocationManager";	
-	public static final String FORM_LOGIN_FILTER = "_formLoginFilter";
-	public static final String FORM_LOGIN_ENTRY_POINT = "_formLoginEntryPoint";
-	public static final String OPEN_ID_FILTER = "_openIDFilter";
-	public static final String OPEN_ID_ENTRY_POINT = "_openIDFilterEntryPoint";
-    public static final String OPEN_ID_PROVIDER = "_openIDAuthenticationProvider";	
-	public static final String MAIN_ENTRY_POINT = "_mainEntryPoint";	
-	public static final String FILTER_CHAIN_PROXY = "_filterChainProxy";
-	public static final String HTTP_SESSION_CONTEXT_INTEGRATION_FILTER = "_httpSessionContextIntegrationFilter";
-	public static final String LDAP_AUTHENTICATION_PROVIDER = "_ldapAuthenticationProvider";	
-	public static final String LOGOUT_FILTER = "_logoutFilter";
-	public static final String EXCEPTION_TRANSLATION_FILTER = "_exceptionTranslationFilter";
-	public static final String FILTER_SECURITY_INTERCEPTOR = "_filterSecurityInterceptor";
-	public static final String CHANNEL_PROCESSING_FILTER = "_channelProcessingFilter";
-	public static final String CHANNEL_DECISION_MANAGER = "_channelDecisionManager";
-	public static final String REMEMBER_ME_FILTER = "_rememberMeFilter";
-	public static final String REMEMBER_ME_SERVICES = "_rememberMeServices";
-	public static final String REMEMBER_ME_AUTHENTICATION_PROVIDER = "_rememberMeAuthenticationProvider";
-	public static final String DEFAULT_LOGIN_PAGE_GENERATING_FILTER = "_defaultLoginPageFilter";
-	public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
-	public static final String SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter";	
-	public static final String METHOD_SECURITY_INTERCEPTOR = "_methodSecurityInterceptor";
-	public static final String METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR = "_methodSecurityInterceptorPostProcessor";	
-	public static final String METHOD_DEFINITION_SOURCE_ADVISOR = "_methodDefinitionSourceAdvisor";
-	public static final String PROTECT_POINTCUT_POST_PROCESSOR = "_protectPointcutPostProcessor";
-	public static final String DELEGATING_METHOD_DEFINITION_SOURCE = "_delegatingMethodDefinitionSource";
-	public static final String SECURED_METHOD_DEFINITION_SOURCE = "_securedMethodDefinitionSource";
-	public static final String JSR_250_METHOD_DEFINITION_SOURCE = "_jsr250MethodDefinitionSource";
+    public static final String USER_DETAILS_SERVICE = "_userDetailsService";
+    public static final String ANONYMOUS_PROCESSING_FILTER = "_anonymousProcessingFilter";
+    public static final String ANONYMOUS_AUTHENTICATION_PROVIDER = "_anonymousAuthenticationProvider";
+    public static final String BASIC_AUTHENTICATION_FILTER = "_basicAuthenticationFilter";
+    public static final String BASIC_AUTHENTICATION_ENTRY_POINT = "_basicAuthenticationEntryPoint";
+    public static final String SESSION_REGISTRY = "_sessionRegistry";
+    public static final String CONCURRENT_SESSION_FILTER = "_concurrentSessionFilter";
+    public static final String CONCURRENT_SESSION_CONTROLLER = "_concurrentSessionController";
+    public static final String METHOD_ACCESS_MANAGER = "_methodAccessManager";
+    public static final String WEB_ACCESS_MANAGER = "_webAccessManager";
+    public static final String AUTHENTICATION_MANAGER = "_authenticationManager";
+    public static final String AFTER_INVOCATION_MANAGER = "_afterInvocationManager";
+    public static final String FORM_LOGIN_FILTER = "_formLoginFilter";
+    public static final String FORM_LOGIN_ENTRY_POINT = "_formLoginEntryPoint";
+    public static final String OPEN_ID_FILTER = "_openIDFilter";
+    public static final String OPEN_ID_ENTRY_POINT = "_openIDFilterEntryPoint";
+    public static final String OPEN_ID_PROVIDER = "_openIDAuthenticationProvider";
+    public static final String MAIN_ENTRY_POINT = "_mainEntryPoint";
+    public static final String FILTER_CHAIN_PROXY = "_filterChainProxy";
+    public static final String HTTP_SESSION_CONTEXT_INTEGRATION_FILTER = "_httpSessionContextIntegrationFilter";
+    public static final String LDAP_AUTHENTICATION_PROVIDER = "_ldapAuthenticationProvider";
+    public static final String LOGOUT_FILTER = "_logoutFilter";
+    public static final String EXCEPTION_TRANSLATION_FILTER = "_exceptionTranslationFilter";
+    public static final String FILTER_SECURITY_INTERCEPTOR = "_filterSecurityInterceptor";
+    public static final String CHANNEL_PROCESSING_FILTER = "_channelProcessingFilter";
+    public static final String CHANNEL_DECISION_MANAGER = "_channelDecisionManager";
+    public static final String REMEMBER_ME_FILTER = "_rememberMeFilter";
+    public static final String REMEMBER_ME_SERVICES = "_rememberMeServices";
+    public static final String REMEMBER_ME_AUTHENTICATION_PROVIDER = "_rememberMeAuthenticationProvider";
+    public static final String DEFAULT_LOGIN_PAGE_GENERATING_FILTER = "_defaultLoginPageFilter";
+    public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
+    public static final String SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter";
+    public static final String METHOD_SECURITY_INTERCEPTOR = "_methodSecurityInterceptor";
+    public static final String METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR = "_methodSecurityInterceptorPostProcessor";
+    public static final String METHOD_DEFINITION_SOURCE_ADVISOR = "_methodDefinitionSourceAdvisor";
+    public static final String PROTECT_POINTCUT_POST_PROCESSOR = "_protectPointcutPostProcessor";
+    public static final String DELEGATING_METHOD_DEFINITION_SOURCE = "_delegatingMethodDefinitionSource";
+    public static final String SECURED_METHOD_DEFINITION_SOURCE = "_securedMethodDefinitionSource";
+    public static final String JSR_250_METHOD_DEFINITION_SOURCE = "_jsr250MethodDefinitionSource";
     public static final String EMBEDDED_APACHE_DS = "_apacheDirectoryServerContainer";
     public static final String CONTEXT_SOURCE = "_securityContextSource";
     public static final String PORT_MAPPER = "_portMapper";

+ 85 - 77
core/src/main/java/org/springframework/security/config/ConfigUtils.java

@@ -3,8 +3,6 @@ package org.springframework.security.config;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.BeanMetadataElement;
 import org.springframework.beans.MutablePropertyValues;
 import org.springframework.beans.PropertyValue;
@@ -15,6 +13,7 @@ import org.springframework.beans.factory.support.ManagedList;
 import org.springframework.beans.factory.support.RootBeanDefinition;
 import org.springframework.beans.factory.xml.ParserContext;
 import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
+import org.springframework.security.expression.support.MethodExpressionVoter;
 import org.springframework.security.util.UrlUtils;
 import org.springframework.security.vote.AffirmativeBased;
 import org.springframework.security.vote.AuthenticatedVoter;
@@ -29,45 +28,54 @@ import org.w3c.dom.Element;
  * @author Ben Alex
  * @version $Id$
  */
-public abstract class ConfigUtils {
-    private static final Log logger = LogFactory.getLog(ConfigUtils.class);
+abstract class ConfigUtils {
 
-    static void registerDefaultAccessManagerIfNecessary(ParserContext parserContext) {
-
-        if (!parserContext.getRegistry().containsBeanDefinition(BeanIds.ACCESS_MANAGER)) {
-            ManagedList defaultVoters = new ManagedList(2);
+    static void registerDefaultWebAccessManagerIfNecessary(ParserContext parserContext) {
+        if (!parserContext.getRegistry().containsBeanDefinition(BeanIds.WEB_ACCESS_MANAGER)) {
+            parserContext.getRegistry().registerBeanDefinition(BeanIds.WEB_ACCESS_MANAGER,
+                    createAccessManagerBean(RoleVoter.class, AuthenticatedVoter.class));
+        }
+    }
 
-            defaultVoters.add(new RootBeanDefinition(RoleVoter.class));
-            defaultVoters.add(new RootBeanDefinition(AuthenticatedVoter.class));
+    static void registerDefaultMethodAccessManagerIfNecessary(ParserContext parserContext) {
+        if (!parserContext.getRegistry().containsBeanDefinition(BeanIds.METHOD_ACCESS_MANAGER)) {
+            parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_ACCESS_MANAGER,
+                    createAccessManagerBean(MethodExpressionVoter.class, RoleVoter.class, AuthenticatedVoter.class));
+        }
+    }
 
-            BeanDefinitionBuilder accessMgrBuilder = BeanDefinitionBuilder.rootBeanDefinition(AffirmativeBased.class);
-            accessMgrBuilder.addPropertyValue("decisionVoters", defaultVoters);
-            BeanDefinition accessMgr = accessMgrBuilder.getBeanDefinition();
+    private static BeanDefinition createAccessManagerBean(Class... voters) {
+        ManagedList defaultVoters = new ManagedList(voters.length);
 
-            parserContext.getRegistry().registerBeanDefinition(BeanIds.ACCESS_MANAGER, accessMgr);
+        for(Class voter : voters) {
+            defaultVoters.add(new RootBeanDefinition(voter));
         }
+
+        BeanDefinitionBuilder accessMgrBuilder = BeanDefinitionBuilder.rootBeanDefinition(AffirmativeBased.class);
+        accessMgrBuilder.addPropertyValue("decisionVoters", defaultVoters);
+        return accessMgrBuilder.getBeanDefinition();
     }
-    
-    public static int countNonEmpty(String[] objects) {        
-    	int nonNulls = 0;
-    	
-    	for (int i = 0; i < objects.length; i++) {
-    		if (StringUtils.hasText(objects[i])) {
-    			nonNulls++;
-    		}
-    	}
-        
-    	return nonNulls;
+
+    public static int countNonEmpty(String[] objects) {
+        int nonNulls = 0;
+
+        for (int i = 0; i < objects.length; i++) {
+            if (StringUtils.hasText(objects[i])) {
+                nonNulls++;
+            }
+        }
+
+        return nonNulls;
     }
 
-    public static void addVoter(BeanDefinition voter, ParserContext parserContext) {
-        registerDefaultAccessManagerIfNecessary(parserContext);
+    static void addVoter(BeanDefinition voter, ParserContext parserContext) {
+        registerDefaultMethodAccessManagerIfNecessary(parserContext);
 
-        BeanDefinition accessMgr = parserContext.getRegistry().getBeanDefinition(BeanIds.ACCESS_MANAGER);
+        BeanDefinition accessMgr = parserContext.getRegistry().getBeanDefinition(BeanIds.METHOD_ACCESS_MANAGER);
 
         ManagedList voters = (ManagedList) accessMgr.getPropertyValues().getPropertyValue("decisionVoters").getValue();
         voters.add(voter);
-        
+
         accessMgr.getPropertyValues().addPropertyValue("decisionVoters", voters);
     }
 
@@ -92,12 +100,12 @@ public abstract class ConfigUtils {
         BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
         ((ArrayList) authManager.getPropertyValues().getPropertyValue("providerBeanNames").getValue()).add(beanName);
     }
-    
-	static ManagedList getRegisteredAfterInvocationProviders(ParserContext parserContext) {
-		BeanDefinition manager = registerAfterInvocationProviderManagerIfNecessary(parserContext);
-		return (ManagedList) manager.getPropertyValues().getPropertyValue("providers").getValue();
-	}    
-    
+
+    static ManagedList getRegisteredAfterInvocationProviders(ParserContext parserContext) {
+        BeanDefinition manager = registerAfterInvocationProviderManagerIfNecessary(parserContext);
+        return (ManagedList) manager.getPropertyValues().getPropertyValue("providers").getValue();
+    }
+
     private static BeanDefinition registerAfterInvocationProviderManagerIfNecessary(ParserContext parserContext) {
         if(parserContext.getRegistry().containsBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER)) {
             return parserContext.getRegistry().getBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER);
@@ -108,12 +116,12 @@ public abstract class ConfigUtils {
         parserContext.getRegistry().registerBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER, manager);
 
         return manager;
-	}
+    }
 
-	private static void registerFilterChainPostProcessorIfNecessary(ParserContext pc) {
-    	if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR)) {
-    		return;
-    	}
+    private static void registerFilterChainPostProcessorIfNecessary(ParserContext pc) {
+        if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR)) {
+            return;
+        }
         // Post processor specifically to assemble and order the filter chain immediately before the FilterChainProxy is initialized.
         RootBeanDefinition filterChainPostProcessor = new RootBeanDefinition(FilterChainProxyPostProcessor.class);
         filterChainPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
@@ -122,62 +130,62 @@ public abstract class ConfigUtils {
         filterList.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
         pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_LIST, filterList);
     }
-    
+
     static void addHttpFilter(ParserContext pc, BeanMetadataElement filter) {
-    	registerFilterChainPostProcessorIfNecessary(pc);
-    	
-    	RootBeanDefinition filterList = (RootBeanDefinition) pc.getRegistry().getBeanDefinition(BeanIds.FILTER_LIST);
-    	
-    	ManagedList filters;
-    	MutablePropertyValues pvs = filterList.getPropertyValues();
-    	if (pvs.contains("filters")) {
-    		filters = (ManagedList) pvs.getPropertyValue("filters").getValue();
-    	} else {
-    		filters = new ManagedList();
-    		pvs.addPropertyValue("filters", filters);
-    	}
-    	
-    	filters.add(filter);
+        registerFilterChainPostProcessorIfNecessary(pc);
+
+        RootBeanDefinition filterList = (RootBeanDefinition) pc.getRegistry().getBeanDefinition(BeanIds.FILTER_LIST);
+
+        ManagedList filters;
+        MutablePropertyValues pvs = filterList.getPropertyValues();
+        if (pvs.contains("filters")) {
+            filters = (ManagedList) pvs.getPropertyValue("filters").getValue();
+        } else {
+            filters = new ManagedList();
+            pvs.addPropertyValue("filters", filters);
+        }
+
+        filters.add(filter);
     }
 
     /**
-     * Bean which holds the list of filters which are maintained in the context and modified by calls to 
+     * Bean which holds the list of filters which are maintained in the context and modified by calls to
      * addHttpFilter. The post processor retrieves these before injecting the list into the FilterChainProxy.
      */
     public static class FilterChainList {
-    	List filters;
+        List filters;
 
-		public List getFilters() {
-			return filters;
-		}
+        public List getFilters() {
+            return filters;
+        }
 
-		public void setFilters(List filters) {
-			this.filters = filters;
-		}
+        public void setFilters(List filters) {
+            this.filters = filters;
+        }
     }
-    
+
     /**
      * Checks the value of an XML attribute which represents a redirect URL.
-     * If not empty or starting with "$" (potential placeholder), "/" or "http" it will raise an error. 
+     * If not empty or starting with "$" (potential placeholder), "/" or "http" it will raise an error.
      */
     static void validateHttpRedirect(String url, ParserContext pc, Object source) {
-    	if (UrlUtils.isValidRedirectUrl(url) || url.startsWith("$")) {
-    		return;
-    	}
-    	pc.getReaderContext().warning(url + " is not a valid redirect URL (must start with '/' or http(s))", source);
+        if (UrlUtils.isValidRedirectUrl(url) || url.startsWith("$")) {
+            return;
+        }
+        pc.getReaderContext().warning(url + " is not a valid redirect URL (must start with '/' or http(s))", source);
     }
-    
+
     static void setSessionControllerOnAuthenticationManager(ParserContext pc, String beanName, Element sourceElt) {
-    	registerProviderManagerIfNecessary(pc);
-    	BeanDefinition authManager = pc.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
+        registerProviderManagerIfNecessary(pc);
+        BeanDefinition authManager = pc.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
         PropertyValue pv = authManager.getPropertyValues().getPropertyValue("sessionController");
-        
+
         if (pv != null && pv.getValue() != null) {
-        	pc.getReaderContext().error("A session controller has already been set on the authentication manager. " +
-        			"The <concurrent-session-control> element isn't compatible with a custom session controller", 
-        			pc.extractSource(sourceElt));
+            pc.getReaderContext().error("A session controller has already been set on the authentication manager. " +
+                    "The <concurrent-session-control> element isn't compatible with a custom session controller",
+                    pc.extractSource(sourceElt));
         }
-        
+
         authManager.getPropertyValues().addPropertyValue("sessionController", new RuntimeBeanReference(beanName));
     }
 }

+ 27 - 7
core/src/main/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParser.java

@@ -1,5 +1,6 @@
 package org.springframework.security.config;
 
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -14,7 +15,9 @@ import org.springframework.beans.factory.support.ManagedList;
 import org.springframework.beans.factory.support.RootBeanDefinition;
 import org.springframework.beans.factory.xml.BeanDefinitionParser;
 import org.springframework.beans.factory.xml.ParserContext;
-import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.security.ConfigAttribute;
+import org.springframework.security.SecurityConfig;
+import org.springframework.security.expression.support.MethodExpressionAfterInvocationProvider;
 import org.springframework.security.intercept.method.DelegatingMethodDefinitionSource;
 import org.springframework.security.intercept.method.MapBasedMethodDefinitionSource;
 import org.springframework.security.intercept.method.ProtectPointcutPostProcessor;
@@ -33,6 +36,7 @@ import org.w3c.dom.Element;
 class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
     public static final String SECURED_DEPENDENCY_CLASS = "org.springframework.security.annotation.Secured";
     public static final String SECURED_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.annotation.SecuredMethodDefinitionSource";
+    public static final String EXPRESSION_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.expression.support.ExpressionAnnotationMethodDefinitionSource";
     public static final String JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.annotation.Jsr250MethodDefinitionSource";
     public static final String JSR_250_VOTER_CLASS = "org.springframework.security.annotation.Jsr250Voter";
     private static final String ATT_ACCESS = "access";
@@ -40,6 +44,7 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
     private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
     private static final String ATT_USE_JSR250 = "jsr250-annotations";
     private static final String ATT_USE_SECURED = "secured-annotations";
+    private static final String ATT_USE_EXPRESSIONS = "spel-annotations";
 
     public BeanDefinition parse(Element element, ParserContext parserContext) {
         Object source = parserContext.extractSource(element);
@@ -61,17 +66,21 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
 
         registerDelegatingMethodDefinitionSource(parserContext, delegates, source);
 
+        // Add the expression-based after invocation provider
+        ConfigUtils.getRegisteredAfterInvocationProviders(parserContext).add(
+                new RootBeanDefinition(MethodExpressionAfterInvocationProvider.class));
+
         // Register the applicable AccessDecisionManager, handling the special JSR 250 voter if being used
         String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
 
         if (!StringUtils.hasText(accessManagerId)) {
-            ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
+            ConfigUtils.registerDefaultMethodAccessManagerIfNecessary(parserContext);
 
             if (jsr250Enabled) {
                 ConfigUtils.addVoter(new RootBeanDefinition(JSR_250_VOTER_CLASS, null, null), parserContext);
             }
 
-            accessManagerId = BeanIds.ACCESS_MANAGER;
+            accessManagerId = BeanIds.METHOD_ACCESS_MANAGER;
         }
 
         registerMethodSecurityInterceptor(parserContext, accessManagerId, source);
@@ -84,12 +93,17 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
     }
 
     /**
-     * Checks whether JSR-250 and/or Secured annotations are enabled and adds the appropriate
+     * Checks whether el-based, JSR-250 and/or Secured annotations are enabled and adds the appropriate
      * MethodDefinitionSource delegates if required.
      */
     private boolean registerAnnotationBasedMethodDefinitionSources(Element element, ParserContext pc, ManagedList delegates) {
         boolean useJsr250 = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
         boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
+        boolean useExpressions = "enabled".equals(element.getAttribute(ATT_USE_EXPRESSIONS));
+
+        if (useExpressions) {
+            delegates.add(BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
+        }
 
         if (useSecured) {
             delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SECURED_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
@@ -139,8 +153,14 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
                 parserContext.getReaderContext().error("Pointcut expression required", parserContext.extractSource(childElt));
             }
 
-            ConfigAttributeDefinition def = new ConfigAttributeDefinition(StringUtils.commaDelimitedListToStringArray(accessConfig));
-            pointcutMap.put(expression, def);
+            String[] attributeTokens = StringUtils.commaDelimitedListToStringArray(accessConfig);
+            List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>(attributeTokens.length);
+
+            for(String token : attributeTokens) {
+                attributes.add(new SecurityConfig(token));
+            }
+
+            pointcutMap.put(expression, attributes);
         }
 
         return pointcutMap;
@@ -158,7 +178,7 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
         parserContext.registerComponent(new BeanComponentDefinition(interceptor, BeanIds.METHOD_SECURITY_INTERCEPTOR));
 
         parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR,
-        		new RootBeanDefinition(MethodSecurityInterceptorPostProcessor.class));
+                new RootBeanDefinition(MethodSecurityInterceptorPostProcessor.class));
     }
 
     private void registerAdvisor(ParserContext parserContext, Object source) {

+ 4 - 4
core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java

@@ -124,8 +124,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
 
         if (!StringUtils.hasText(accessManagerId)) {
-            ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
-            accessManagerId = BeanIds.ACCESS_MANAGER;
+            ConfigUtils.registerDefaultWebAccessManagerIfNecessary(parserContext);
+            accessManagerId = BeanIds.WEB_ACCESS_MANAGER;
         }
 
         // Register the portMapper. A default will always be created, even if no element exists.
@@ -273,8 +273,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         exceptionTranslationFilterBuilder.addPropertyValue("createSessionAllowed", new Boolean(allowSessionCreation));
 
         if (StringUtils.hasText(accessDeniedPage)) {
-        	BeanDefinition accessDeniedHandler = new RootBeanDefinition(AccessDeniedHandlerImpl.class);
-        	accessDeniedHandler.getPropertyValues().addPropertyValue("errorPage", accessDeniedPage);
+            BeanDefinition accessDeniedHandler = new RootBeanDefinition(AccessDeniedHandlerImpl.class);
+            accessDeniedHandler.getPropertyValues().addPropertyValue("errorPage", accessDeniedPage);
             exceptionTranslationFilterBuilder.addPropertyValue("accessDeniedHandler", accessDeniedHandler);
         }
 

+ 16 - 16
core/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java

@@ -30,8 +30,8 @@ public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDe
 
     public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
         ConfigUtils.registerProviderManagerIfNecessary(parserContext);
-        ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
-        
+        ConfigUtils.registerDefaultMethodAccessManagerIfNecessary(parserContext);
+
         return delegate.decorate(node, definition, parserContext);
     }
 }
@@ -41,8 +41,8 @@ public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDe
  * registration.
  */
 class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractInterceptorDrivenBeanDefinitionDecorator {
-	static final String ATT_METHOD = "method";
-	static final String ATT_ACCESS = "access";
+    static final String ATT_METHOD = "method";
+    static final String ATT_ACCESS = "access";
     private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
 
     private Log logger = LogFactory.getLog(getClass());
@@ -57,40 +57,40 @@ class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractIntercepto
         String accessManagerId = interceptMethodsElt.getAttribute(ATT_ACCESS_MGR);
 
         if (!StringUtils.hasText(accessManagerId)) {
-            accessManagerId = BeanIds.ACCESS_MANAGER;
+            accessManagerId = BeanIds.METHOD_ACCESS_MANAGER;
         }
 
         interceptor.addPropertyValue("accessDecisionManager", new RuntimeBeanReference(accessManagerId));
         interceptor.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
 
         // Lookup parent bean information
-    	Element parent = (Element) node.getParentNode();
-    	String parentBeanClass = parent.getAttribute("class");
-    	String parentBeanId = parent.getAttribute("id");
+        Element parent = (Element) node.getParentNode();
+        String parentBeanClass = parent.getAttribute("class");
+        String parentBeanId = parent.getAttribute("id");
         parent = null;
-        
+
         // Parse the included methods
         List methods = DomUtils.getChildElementsByTagName(interceptMethodsElt, Elements.PROTECT);
 
         StringBuffer sb = new StringBuffer();
-        
+
         for (Iterator i = methods.iterator(); i.hasNext();) {
             Element protectmethodElt = (Element) i.next();
             String accessConfig = protectmethodElt.getAttribute(ATT_ACCESS);
 
             // Support inference of class names
             String methodName = protectmethodElt.getAttribute(ATT_METHOD);
-            
+
             if (methodName.lastIndexOf(".") == -1) {
-            	if (parentBeanClass != null && !"".equals(parentBeanClass)) {
-            		methodName = parentBeanClass + "." + methodName;
-            	}
+                if (parentBeanClass != null && !"".equals(parentBeanClass)) {
+                    methodName = parentBeanClass + "." + methodName;
+                }
             }
-            
+
             // Rely on the default property editor for MethodSecurityInterceptor.setObjectDefinitionSource to setup the MethodDefinitionSource
             sb.append(methodName + "=" + accessConfig).append("\r\n");
         }
-        
+
         interceptor.addPropertyValue("objectDefinitionSource", sb.toString());
 
         return interceptor.getBeanDefinition();

+ 67 - 0
core/src/main/java/org/springframework/security/expression/ExpressionUtils.java

@@ -0,0 +1,67 @@
+package org.springframework.security.expression;
+
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.springframework.expression.EvaluationException;
+import org.springframework.expression.Expression;
+import org.springframework.expression.spel.standard.StandardEvaluationContext;
+
+public class ExpressionUtils {
+    public static Object doFilter(Object filterTarget, Expression filterExpression, StandardEvaluationContext ctx) {
+        SecurityExpressionRoot rootObject = (SecurityExpressionRoot) ctx.getRootContextObject();
+        Set removeList = new HashSet();
+
+        if (filterTarget instanceof Collection) {
+            for (Object filterObject : (Collection)filterTarget) {
+                rootObject.setFilterObject(filterObject);
+
+                if (!evaluateAsBoolean(filterExpression, ctx)) {
+                    removeList.add(filterObject);
+                }
+            }
+
+            for(Object toRemove : removeList) {
+                ((Collection)filterTarget).remove(toRemove);
+            }
+
+            return filterTarget;
+        }
+
+        if (filterTarget.getClass().isArray()) {
+            Object[] array = (Object[])filterTarget;
+
+            for (int i = 0; i < array.length; i++) {
+                rootObject.setFilterObject(array[i]);
+
+                if (!evaluateAsBoolean(filterExpression, ctx)) {
+                    removeList.add(array[i]);
+                }
+            }
+
+            Object[] filtered = (Object[]) Array.newInstance(filterTarget.getClass().getComponentType(),
+                    array.length - removeList.size());
+            for (int i = 0, j = 0; i < array.length; i++) {
+                if (!removeList.contains(array[i])) {
+                    filtered[j++] = array[i];
+                }
+            }
+
+            return filtered;
+        }
+
+        throw new IllegalArgumentException("Filter target must be a collection or array type, but was " + filterTarget);
+    }
+
+    public static boolean evaluateAsBoolean(Expression expr, StandardEvaluationContext ctx) {
+        try {
+            return ((Boolean) expr.getValue(ctx, Boolean.class)).booleanValue();
+        } catch (EvaluationException e) {
+            throw new IllegalArgumentException("Failed to evaluate expression", e);
+        }
+    }
+
+
+}

+ 14 - 0
core/src/main/java/org/springframework/security/expression/MethodInvocationSecurityExpressionRoot.java

@@ -0,0 +1,14 @@
+package org.springframework.security.expression;
+
+import org.aopalliance.intercept.MethodInvocation;
+import org.springframework.security.Authentication;
+
+public class MethodInvocationSecurityExpressionRoot extends SecurityExpressionRoot {
+
+    MethodInvocationSecurityExpressionRoot(Authentication a, MethodInvocation mi) {
+        super(a);
+
+        mi.getArguments();
+    }
+
+}

+ 67 - 0
core/src/main/java/org/springframework/security/expression/SecurityExpressionRoot.java

@@ -0,0 +1,67 @@
+package org.springframework.security.expression;
+
+import java.util.Set;
+
+import org.springframework.security.Authentication;
+import org.springframework.security.AuthenticationTrustResolver;
+import org.springframework.security.AuthenticationTrustResolverImpl;
+import org.springframework.security.util.AuthorityUtils;
+
+public class SecurityExpressionRoot {
+    private Authentication authentication;
+    private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
+    private Object filterObject;
+    private Object returnObject;
+
+    public SecurityExpressionRoot(Authentication a) {
+        this.authentication = a;
+    }
+
+    public boolean hasRole(String role) {
+        return hasAnyRole(role);
+    }
+
+    public boolean hasAnyRole(String... roles) {
+        Set roleSet = AuthorityUtils.authorityArrayToSet(authentication.getAuthorities());
+
+        for (String role : roles) {
+            if (roleSet.contains(role)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public boolean isAnonymous() {
+        return trustResolver.isAnonymous(authentication);
+    }
+
+    public boolean isRememberMe() {
+        return trustResolver.isRememberMe(authentication);
+    }
+
+    public String getName() {
+        return authentication.getName();
+    }
+
+    public boolean isFullyAuthenticated() {
+        return !trustResolver.isAnonymous(authentication) && !trustResolver.isRememberMe(authentication);
+    }
+
+    public void setFilterObject(Object filterObject) {
+        this.filterObject = filterObject;
+    }
+
+    public Object getFilterObject() {
+        return filterObject;
+    }
+
+    public void setReturnObject(Object returnObject) {
+        this.returnObject = returnObject;
+    }
+
+    public Object getReturnObject() {
+        return returnObject;
+    }
+}

+ 26 - 0
core/src/main/java/org/springframework/security/expression/annotation/PostAuthorize.java

@@ -0,0 +1,26 @@
+package org.springframework.security.expression.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for specifying a method access-control expression which will be evaluated after a method has been invoked.
+ *
+ * @author Luke Taylor
+ * @version $Id$
+ * @since 2.5
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface PostAuthorize {
+    /**
+     * @return the Spring-EL expression to be evaluated after invoking the protected method
+     */
+    public String value();
+}

+ 26 - 0
core/src/main/java/org/springframework/security/expression/annotation/PostFilter.java

@@ -0,0 +1,26 @@
+package org.springframework.security.expression.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for specifying a method filtering expression which will be evaluated after a method has been invoked.
+ *
+ * @author Luke Taylor
+ * @version $Id$
+ * @since 2.5
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface PostFilter {
+    /**
+     * @return the Spring-EL expression to be evaluated after invoking the protected method
+     */
+    public String value();
+}

+ 27 - 0
core/src/main/java/org/springframework/security/expression/annotation/PreAuthorize.java

@@ -0,0 +1,27 @@
+package org.springframework.security.expression.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for specifying a method access-control expression which will be evaluated to decide whether a
+ * method invocation is allowed or not.
+ *
+ * @author Luke Taylor
+ * @version $Id$
+ * @since 2.5
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface PreAuthorize {
+    /**
+     * @return the Spring-EL expression to be evaluated before invoking the protected method
+     */
+    String value();
+}

+ 31 - 0
core/src/main/java/org/springframework/security/expression/annotation/PreFilter.java

@@ -0,0 +1,31 @@
+package org.springframework.security.expression.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for specifying a method filtering expression which will be evaluated after a method has been invoked.
+ *
+ * @author Luke Taylor
+ * @version $Id$
+ * @since 2.5
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface PreFilter {
+    /**
+     * @return the Spring-EL expression to be evaluated before invoking the protected method
+     */
+    public String value();
+
+    /**
+     * @return the name of the parameter which should be filtered (must be an array or collection)
+     */
+    public String filterTarget();
+}

+ 42 - 0
core/src/main/java/org/springframework/security/expression/support/AbstractExpressionBasedMethodConfigAttribute.java

@@ -0,0 +1,42 @@
+package org.springframework.security.expression.support;
+
+import org.springframework.expression.Expression;
+import org.springframework.expression.ParseException;
+import org.springframework.expression.spel.SpelExpressionParser;
+import org.springframework.security.ConfigAttribute;
+import org.springframework.util.Assert;
+
+/**
+ * Contains both filtering and authorization expression meta-data for Spring-EL based access control.
+ * <p>
+ * Base class for pre or post-invocation phases of a method invocation.
+ * <p>
+ * Either filter or authorization expressions may be null, but not both.
+ *
+ * @author Luke Taylor
+ * @version $Id$
+ * @since 2.5
+ */
+abstract class AbstractExpressionBasedMethodConfigAttribute implements ConfigAttribute {
+    private final Expression filterExpression;
+    private final Expression authorizeExpression;
+
+    AbstractExpressionBasedMethodConfigAttribute(String filterExpression, String authorizeExpression) throws ParseException {
+        Assert.isTrue(filterExpression != null || authorizeExpression != null, "Filter and authorization Expressions cannot both be null");
+        SpelExpressionParser parser = new SpelExpressionParser();
+        this.filterExpression = filterExpression == null ? null : parser.parseExpression(filterExpression);
+        this.authorizeExpression = authorizeExpression == null ? null : parser.parseExpression(authorizeExpression);
+    }
+
+    Expression getFilterExpression() {
+        return filterExpression;
+    }
+
+    Expression getAuthorizeExpression() {
+        return authorizeExpression;
+    }
+
+    public String getAttribute() {
+        return null;
+    }
+}

+ 111 - 0
core/src/main/java/org/springframework/security/expression/support/ExpressionAnnotationMethodDefinitionSource.java

@@ -0,0 +1,111 @@
+package org.springframework.security.expression.support;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.expression.ParseException;
+import org.springframework.security.ConfigAttribute;
+import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.security.config.SecurityConfigurationException;
+import org.springframework.security.expression.annotation.PostAuthorize;
+import org.springframework.security.expression.annotation.PostFilter;
+import org.springframework.security.expression.annotation.PreAuthorize;
+import org.springframework.security.expression.annotation.PreFilter;
+import org.springframework.security.intercept.method.AbstractFallbackMethodDefinitionSource;
+
+/**
+ * MethodDefinitionSource which extracts metadata from the @PreFilter and @PreAuthorize annotations
+ * placed on a method. The metadata is encapsulated in a {@link AbstractExpressionBasedMethodConfigAttribute} instance.
+ *
+ * @see MethodExpressionVoter
+ *
+ * @author Luke Taylor
+ * @since 2.5
+ * @version $Id$
+ */
+public class ExpressionAnnotationMethodDefinitionSource extends AbstractFallbackMethodDefinitionSource {
+
+    @Override
+    protected List<ConfigAttribute> findAttributes(Method method, Class targetClass) {
+        ConfigAttribute pre = processPreInvocationAnnotations(AnnotationUtils.findAnnotation(method, PreFilter.class),
+                AnnotationUtils.findAnnotation(method, PreAuthorize.class));
+        ConfigAttribute post = processPostInvocationAnnotations(AnnotationUtils.findAnnotation(method, PostFilter.class),
+                AnnotationUtils.findAnnotation(method, PostAuthorize.class));
+
+        if (pre == null && post == null) {
+            return null;
+        }
+
+        List<ConfigAttribute> attrs = new ArrayList<ConfigAttribute>(2);
+        if (pre != null) {
+            attrs.add(pre);
+        }
+
+        if (post != null) {
+            attrs.add(post);
+        }
+
+        return attrs;
+    }
+
+    @Override
+    protected List<ConfigAttribute> findAttributes(Class targetClass) {
+        ConfigAttribute pre = processPreInvocationAnnotations((PreFilter)targetClass.getAnnotation(PreFilter.class),
+                (PreAuthorize)targetClass.getAnnotation(PreAuthorize.class));
+        ConfigAttribute post = processPostInvocationAnnotations((PostFilter)targetClass.getAnnotation(PostFilter.class),
+                (PostAuthorize)targetClass.getAnnotation(PostAuthorize.class));
+
+        if (pre == null && post == null) {
+            return null;
+        }
+
+        List<ConfigAttribute> attrs = new ArrayList<ConfigAttribute>(2);
+        if (pre != null) {
+            attrs.add(pre);
+        }
+
+        if (post != null) {
+            attrs.add(post);
+        }
+
+        return attrs;
+    }
+
+    public Collection getConfigAttributeDefinitions() {
+        return null;
+    }
+
+    private ConfigAttribute processPreInvocationAnnotations(PreFilter preFilter, PreAuthorize preAuthz) {
+        if (preFilter == null && preAuthz == null) {
+            return null;
+        }
+
+        String preAuthorizeExpression = preAuthz == null ? null : preAuthz.value();
+        String preFilterExpression = preFilter == null ? null : preFilter.value();
+        String filterObject = preFilter == null ? null : preFilter.filterTarget();
+
+        try {
+            return new PreInvocationExpressionBasedMethodConfigAttribute(preFilterExpression, filterObject, preAuthorizeExpression);
+        } catch (ParseException e) {
+            throw new SecurityConfigurationException("Failed to parse expression '" + e.getExpressionString() + "'", e);
+        }
+    }
+
+    private ConfigAttribute processPostInvocationAnnotations(PostFilter postFilter, PostAuthorize postAuthz) {
+        if (postFilter == null && postAuthz == null) {
+            return null;
+        }
+
+        String postAuthorizeExpression = postAuthz == null ? null : postAuthz.value();
+        String postFilterExpression = postFilter == null ? null : postFilter.value();
+
+        try {
+            return new PostInvocationExpressionBasedMethodConfigAttribute(postFilterExpression, postAuthorizeExpression);
+        } catch (ParseException e) {
+            throw new SecurityConfigurationException("Failed to parse expression '" + e.getExpressionString() + "'", e);
+        }
+    }
+}

+ 110 - 0
core/src/main/java/org/springframework/security/expression/support/MethodExpressionAfterInvocationProvider.java

@@ -0,0 +1,110 @@
+package org.springframework.security.expression.support;
+
+import java.lang.reflect.Method;
+
+import org.aopalliance.intercept.MethodInvocation;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
+import org.springframework.core.ParameterNameDiscoverer;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.Expression;
+import org.springframework.expression.spel.standard.StandardEvaluationContext;
+import org.springframework.security.AccessDeniedException;
+import org.springframework.security.Authentication;
+import org.springframework.security.ConfigAttribute;
+import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.security.afterinvocation.AfterInvocationProvider;
+import org.springframework.security.expression.ExpressionUtils;
+import org.springframework.security.expression.SecurityExpressionRoot;
+import org.springframework.util.ClassUtils;
+
+/**
+ * AfterInvocationProvider which handles the @PostAuthorize and @PostFilter annotation expressions.
+ *
+ * @author Luke Taylor
+ * @verson $Id$
+ * @since 2.5
+ */
+public class MethodExpressionAfterInvocationProvider implements AfterInvocationProvider {
+
+    protected final Log logger = LogFactory.getLog(getClass());
+
+    private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
+
+    public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config, Object returnedObject)
+            throws AccessDeniedException {
+
+        PostInvocationExpressionBasedMethodConfigAttribute mca = findMethodAccessControlExpression(config);
+
+        if (mca == null) {
+            return returnedObject;
+        }
+
+        StandardEvaluationContext ctx = new StandardEvaluationContext();
+        populateContextVariables(ctx, (MethodInvocation) object);
+        SecurityExpressionRoot expressionRoot = new SecurityExpressionRoot(authentication);
+        ctx.setRootObject(expressionRoot);
+
+        Expression postFilter = mca.getFilterExpression();
+        Expression postAuthorize = mca.getAuthorizeExpression();
+
+        if (postFilter != null) {
+            if (logger.isDebugEnabled()) {
+                logger.debug("Applying PostFilter expression " + postFilter);
+            }
+
+            if (returnedObject != null) {
+                returnedObject = ExpressionUtils.doFilter(returnedObject, postFilter, ctx);
+            } else {
+                if (logger.isDebugEnabled()) {
+                    logger.debug("Return object is null, filtering will be skipped");
+                }
+            }
+        }
+
+        expressionRoot.setReturnObject(returnedObject);
+
+        if (postAuthorize != null && !ExpressionUtils.evaluateAsBoolean(postAuthorize, ctx)) {
+            if (logger.isDebugEnabled()) {
+                logger.debug("PostAuthorize expression rejected access");
+            }
+            throw new AccessDeniedException("Access is denied");
+        }
+
+        return returnedObject;
+    }
+
+    private void populateContextVariables(EvaluationContext ctx, MethodInvocation mi) {
+        Object[] args = mi.getArguments();
+        Object targetObject = mi.getThis();
+        Method method = ClassUtils.getMostSpecificMethod(mi.getMethod(), targetObject.getClass());
+        String[] paramNames = parameterNameDiscoverer.getParameterNames(method);
+
+        for(int i=0; i < args.length; i++) {
+            ctx.setVariable(paramNames[i], args[i]);
+        }
+    }
+
+    private PostInvocationExpressionBasedMethodConfigAttribute findMethodAccessControlExpression(ConfigAttributeDefinition config) {
+        // Find the MethodAccessControlExpression attribute
+        for (ConfigAttribute attribute : config.getConfigAttributes()) {
+            if (attribute instanceof PostInvocationExpressionBasedMethodConfigAttribute) {
+                return (PostInvocationExpressionBasedMethodConfigAttribute)attribute;
+            }
+        }
+
+        return null;
+    }
+
+    public boolean supports(ConfigAttribute attribute) {
+        return attribute instanceof PostInvocationExpressionBasedMethodConfigAttribute;
+    }
+
+    public boolean supports(Class clazz) {
+        return clazz.isAssignableFrom(MethodInvocation.class);
+    }
+
+
+
+}

+ 109 - 0
core/src/main/java/org/springframework/security/expression/support/MethodExpressionVoter.java

@@ -0,0 +1,109 @@
+package org.springframework.security.expression.support;
+
+import java.lang.reflect.Method;
+
+import org.aopalliance.intercept.MethodInvocation;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
+import org.springframework.core.ParameterNameDiscoverer;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.Expression;
+import org.springframework.expression.spel.standard.StandardEvaluationContext;
+import org.springframework.security.Authentication;
+import org.springframework.security.ConfigAttribute;
+import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.security.expression.ExpressionUtils;
+import org.springframework.security.expression.SecurityExpressionRoot;
+import org.springframework.security.vote.AccessDecisionVoter;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Voter which performs the actions for @PreFilter and @PostAuthorize annotations.
+ * <p>
+ * If only a @PreFilter condition is specified, it will vote to grant access, otherwise it will vote
+ * to grant or deny access depending on whether the @PostAuthorize expression evaluates to 'true' or 'false',
+ * respectively.
+ *
+ * @author Luke Taylor
+ * @version $Id$
+ * @since 2.5
+ */
+public class MethodExpressionVoter implements AccessDecisionVoter {
+    protected final Log logger = LogFactory.getLog(getClass());
+
+    // TODO: Share this between classes
+    private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
+
+    public boolean supports(ConfigAttribute attribute) {
+        return attribute instanceof AbstractExpressionBasedMethodConfigAttribute;
+    }
+
+    public boolean supports(Class clazz) {
+        return clazz.isAssignableFrom(MethodInvocation.class);
+    }
+
+    public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {
+        PreInvocationExpressionBasedMethodConfigAttribute mace = findMethodAccessControlExpression(config);
+
+        if (mace == null) {
+            // No expression based metadata, so abstain
+            return ACCESS_ABSTAIN;
+        }
+
+        StandardEvaluationContext ctx = new StandardEvaluationContext();
+        Object filterTarget =
+            populateContextVariablesAndFindFilterTarget(ctx, (MethodInvocation)object, mace.getFilterTarget());
+
+        ctx.setRootObject(new SecurityExpressionRoot(authentication));
+
+        Expression preFilter = mace.getFilterExpression();
+        Expression preAuthorize = mace.getAuthorizeExpression();
+
+        if (preFilter != null) {
+            // TODO: Allow null target if only single parameter, or single collection/array?
+            Object filtered = ExpressionUtils.doFilter(filterTarget, preFilter, ctx);
+        }
+
+        if (preAuthorize == null) {
+            return ACCESS_GRANTED;
+        }
+
+        return ExpressionUtils.evaluateAsBoolean(preAuthorize, ctx) ? ACCESS_GRANTED : ACCESS_DENIED;
+    }
+
+    private Object populateContextVariablesAndFindFilterTarget(EvaluationContext ctx, MethodInvocation mi,
+            String filterTargetName) {
+
+        Object[] args = mi.getArguments();
+        Object targetObject = mi.getThis();
+        Method method = ClassUtils.getMostSpecificMethod(mi.getMethod(), targetObject.getClass());
+        Object filterTarget = null;
+        String[] paramNames = parameterNameDiscoverer.getParameterNames(method);
+
+        for(int i=0; i < args.length; i++) {
+            ctx.setVariable(paramNames[i], args[i]);
+            if (filterTargetName != null && paramNames[i].equals(filterTargetName)) {
+                filterTarget = args[i];
+            }
+        }
+
+        if (filterTargetName != null && filterTarget == null) {
+            throw new IllegalArgumentException("No filter target argument with name " + filterTargetName +
+                    " found in method: " + method.getName());
+        }
+
+        return filterTarget;
+    }
+
+    private PreInvocationExpressionBasedMethodConfigAttribute findMethodAccessControlExpression(ConfigAttributeDefinition config) {
+        // Find the MethodAccessControlExpression attribute
+        for (ConfigAttribute attribute : config.getConfigAttributes()) {
+            if (attribute instanceof AbstractExpressionBasedMethodConfigAttribute) {
+                return (PreInvocationExpressionBasedMethodConfigAttribute)attribute;
+            }
+        }
+
+        return null;
+    }
+}

+ 12 - 0
core/src/main/java/org/springframework/security/expression/support/PostInvocationExpressionBasedMethodConfigAttribute.java

@@ -0,0 +1,12 @@
+package org.springframework.security.expression.support;
+
+import org.springframework.expression.ParseException;
+
+class PostInvocationExpressionBasedMethodConfigAttribute extends AbstractExpressionBasedMethodConfigAttribute {
+
+    PostInvocationExpressionBasedMethodConfigAttribute(String filterExpression, String authorizeExpression)
+            throws ParseException {
+        super(filterExpression, authorizeExpression);
+    }
+
+}

+ 18 - 0
core/src/main/java/org/springframework/security/expression/support/PreInvocationExpressionBasedMethodConfigAttribute.java

@@ -0,0 +1,18 @@
+package org.springframework.security.expression.support;
+
+import org.springframework.expression.ParseException;
+
+class PreInvocationExpressionBasedMethodConfigAttribute extends AbstractExpressionBasedMethodConfigAttribute {
+    private final String filterTarget;
+
+    PreInvocationExpressionBasedMethodConfigAttribute(String filterExpression, String filterTarget,
+            String authorizeExpression) throws ParseException {
+        super(filterExpression, authorizeExpression);
+
+        this.filterTarget = filterTarget;
+    }
+
+    String getFilterTarget() {
+        return filterTarget;
+    }
+}

+ 12 - 8
core/src/main/java/org/springframework/security/intercept/method/AbstractFallbackMethodDefinitionSource.java

@@ -2,6 +2,7 @@ package org.springframework.security.intercept.method;
 
 import java.lang.reflect.Method;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.aopalliance.intercept.MethodInvocation;
@@ -9,6 +10,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.reflect.CodeSignature;
+import org.springframework.security.ConfigAttribute;
 import org.springframework.security.ConfigAttributeDefinition;
 import org.springframework.util.Assert;
 import org.springframework.util.ClassUtils;
@@ -88,12 +90,14 @@ public abstract class AbstractFallbackMethodDefinitionSource implements MethodDe
             }
             else {
                 // We need to work it out.
-                ConfigAttributeDefinition cfgAtt = computeAttributes(method, targetClass);
+                List<ConfigAttribute> attributes = computeAttributes(method, targetClass);
+                ConfigAttributeDefinition cfgAtt = null;
                 // Put it in the cache.
-                if (cfgAtt == null) {
+                if (attributes == null) {
                     this.attributeCache.put(cacheKey, NULL_CONFIG_ATTRIBUTE);
-                }
-                else {
+                } else {
+                    cfgAtt = new ConfigAttributeDefinition(attributes);
+
                     if (logger.isDebugEnabled()) {
                         logger.debug("Adding security method [" + cacheKey + "] with attribute [" + cfgAtt + "]");
                     }
@@ -110,12 +114,12 @@ public abstract class AbstractFallbackMethodDefinitionSource implements MethodDe
      * @param targetClass the target class for this invocation (may be <code>null</code>)
      * @return
      */
-    private ConfigAttributeDefinition computeAttributes(Method method, Class targetClass) {
+    private List<ConfigAttribute> computeAttributes(Method method, Class targetClass) {
         // The method may be on an interface, but we need attributes from the target class.
         // If the target class is null, the method will be unchanged.
         Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
         // First try is the method in the target class.
-        ConfigAttributeDefinition attr = findAttributes(specificMethod, targetClass);
+        List<ConfigAttribute> attr = findAttributes(specificMethod, targetClass);
         if (attr != null) {
             return attr;
         }
@@ -152,7 +156,7 @@ public abstract class AbstractFallbackMethodDefinitionSource implements MethodDe
      * @param targetClass the target class for the invocation (may be <code>null</code>)
      * @return the security metadata (or null if no metadata applies)
      */
-    protected abstract ConfigAttributeDefinition findAttributes(Method method, Class targetClass);
+    protected abstract List<ConfigAttribute> findAttributes(Method method, Class targetClass);
 
     /**
      * Obtains the security metadata registered against the specified class.
@@ -166,7 +170,7 @@ public abstract class AbstractFallbackMethodDefinitionSource implements MethodDe
      * @param clazz the target class for the invocation (never <code>null</code>)
      * @return the security metadata (or null if no metadata applies)
      */
-    protected abstract ConfigAttributeDefinition findAttributes(Class clazz);
+    protected abstract List<ConfigAttribute> findAttributes(Class clazz);
 
     private static class DefaultCacheKey {
 

+ 19 - 12
core/src/main/java/org/springframework/security/intercept/method/MapBasedMethodDefinitionSource.java

@@ -27,6 +27,7 @@ import java.util.Map;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.security.ConfigAttribute;
 import org.springframework.security.ConfigAttributeDefinition;
 import org.springframework.util.Assert;
 import org.springframework.util.ClassUtils;
@@ -54,10 +55,10 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
     private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
 
     /** Map from RegisteredMethod to ConfigAttributeDefinition */
-    protected Map methodMap = new HashMap();
+    protected Map<RegisteredMethod, List<? extends ConfigAttribute>> methodMap = new HashMap();
 
     /** Map from RegisteredMethod to name pattern used for registration */
-    private Map nameMap = new HashMap();
+    private Map<RegisteredMethod, String> nameMap = new HashMap();
 
     //~ Methods ========================================================================================================
 
@@ -73,21 +74,21 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
 
         while (iterator.hasNext()) {
             Map.Entry entry = (Map.Entry) iterator.next();
-            addSecureMethod((String)entry.getKey(), (ConfigAttributeDefinition)entry.getValue());
+            addSecureMethod((String)entry.getKey(), (List<ConfigAttribute>)entry.getValue());
         }
     }
 
     /**
      * Implementation does not support class-level attributes.
      */
-    protected ConfigAttributeDefinition findAttributes(Class clazz) {
+    protected List<ConfigAttribute> findAttributes(Class clazz) {
         return null;
     }
 
     /**
      * Will walk the method inheritance tree to find the most specific declaration applicable.
      */
-    protected ConfigAttributeDefinition findAttributes(Method method, Class targetClass) {
+    protected List<ConfigAttribute> findAttributes(Method method, Class targetClass) {
         if (targetClass == null) {
             return null;
         }
@@ -95,10 +96,10 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
         return findAttributesSpecifiedAgainst(method, targetClass);
     }
 
-    private ConfigAttributeDefinition findAttributesSpecifiedAgainst(Method method, Class clazz) {
+    private List<ConfigAttribute> findAttributesSpecifiedAgainst(Method method, Class clazz) {
         RegisteredMethod registeredMethod = new RegisteredMethod(method, clazz);
         if (methodMap.containsKey(registeredMethod)) {
-            return (ConfigAttributeDefinition) methodMap.get(registeredMethod);
+            return (List<ConfigAttribute>) methodMap.get(registeredMethod);
         }
         // Search superclass
         if (clazz.getSuperclass() != null) {
@@ -114,7 +115,7 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
      * @param name type and method name, separated by a dot
      * @param attr required authorities associated with the method
      */
-    public void addSecureMethod(String name, ConfigAttributeDefinition attr) {
+    public void addSecureMethod(String name, List<? extends ConfigAttribute> attr) {
         int lastDotIndex = name.lastIndexOf(".");
 
         if (lastDotIndex == -1) {
@@ -138,7 +139,7 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
      * @param mappedName mapped method name, which the javaType has declared or inherited
      * @param attr required authorities associated with the method
      */
-    public void addSecureMethod(Class javaType, String mappedName, ConfigAttributeDefinition attr) {
+    public void addSecureMethod(Class javaType, String mappedName, List<? extends ConfigAttribute> attr) {
         String name = javaType.getName() + '.' + mappedName;
 
         if (logger.isDebugEnabled()) {
@@ -187,7 +188,7 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
      * the existing match will be retained, so that if this method is called for a more general pointcut
      * it will not override a more specific one which has already been added. This
      */
-    public void addSecureMethod(Class javaType, Method method, ConfigAttributeDefinition attr) {
+    public void addSecureMethod(Class javaType, Method method, List<? extends ConfigAttribute> attr) {
         RegisteredMethod key = new RegisteredMethod(method, javaType);
 
         if (methodMap.containsKey(key)) {
@@ -204,7 +205,7 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
      * @param method the method to be secured
      * @param attr required authorities associated with the method
      */
-    private void addSecureMethod(RegisteredMethod method, ConfigAttributeDefinition attr) {
+    private void addSecureMethod(RegisteredMethod method, List<? extends ConfigAttribute> attr) {
         Assert.notNull(method, "RegisteredMethod required");
         Assert.notNull(attr, "Configuration attribute required");
         if (logger.isInfoEnabled()) {
@@ -219,7 +220,13 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
      * @return the attributes explicitly defined against this bean
      */
     public Collection getConfigAttributeDefinitions() {
-        return Collections.unmodifiableCollection(methodMap.values());
+        List<ConfigAttributeDefinition> configAttrs = new ArrayList<ConfigAttributeDefinition>(methodMap.values().size());
+
+        for(List<? extends ConfigAttribute> attrList : methodMap.values()) {
+            configAttrs.add(new ConfigAttributeDefinition(attrList));
+        }
+
+        return configAttrs;
     }
 
     /**

+ 0 - 71
core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionAttributes.java

@@ -1,71 +0,0 @@
-/* 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.springframework.security.intercept.method;
-
-import java.lang.reflect.Method;
-import java.util.Collection;
-
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.metadata.Attributes;
-import org.springframework.security.ConfigAttribute;
-import org.springframework.security.ConfigAttributeDefinition;
-import org.springframework.util.Assert;
-
-
-/**
- * Provides {@link ConfigAttributeDefinition}s for a method signature (via the <tt>lookupAttributes</tt> method)
- * by delegating to a configured {@link Attributes} object. The latter may use Commons attributes
- * or some other approach to determine the <tt>ConfigAttribute</tt>s which apply. 
- *
- * <p>
- * Note that attributes defined against parent classes (either for their methods or interfaces) are not
- * detected. The attributes must be defined against an explicit method or interface on the intercepted class.
- * <p>
- * 
- * Attributes detected that do not implement {@link ConfigAttribute} will be ignored.
- *
- * @author Cameron Braid
- * @author Ben Alex
- * @version $Id$
- */
-public class MethodDefinitionAttributes extends AbstractFallbackMethodDefinitionSource implements InitializingBean {
-    //~ Instance fields ================================================================================================
-
-    private Attributes attributes;
-
-    //~ Methods ========================================================================================================
-
-    public void afterPropertiesSet() throws Exception {
-    	Assert.notNull(attributes, "attributes required");
-	}
-
-    public Collection getConfigAttributeDefinitions() {
-        return null;
-    }
-    
-	protected ConfigAttributeDefinition findAttributes(Class clazz) {
-        return ConfigAttributeDefinition.createFiltered(attributes.getAttributes(clazz));
-	}
-
-	protected ConfigAttributeDefinition findAttributes(Method method, Class targetClass) {
-        return ConfigAttributeDefinition.createFiltered(attributes.getAttributes(method));
-	}
-
-    public void setAttributes(Attributes attributes) {
-    	Assert.notNull(attributes, "Attributes required");
-        this.attributes = attributes;
-    }
-}

+ 10 - 2
core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionSourceEditor.java

@@ -15,7 +15,8 @@
 
 package org.springframework.security.intercept.method;
 
-import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.security.ConfigAttribute;
+import org.springframework.security.SecurityConfig;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -25,7 +26,9 @@ import org.springframework.util.StringUtils;
 
 import java.beans.PropertyEditorSupport;
 
+import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Properties;
 import java.util.Map;
 import java.util.LinkedHashMap;
@@ -65,8 +68,13 @@ public class MethodDefinitionSourceEditor extends PropertyEditorSupport {
             String value = props.getProperty(name);
 
             String[] tokens = StringUtils.commaDelimitedListToStringArray(value);
+            List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>(tokens.length);
 
-            mappings.put(name, new ConfigAttributeDefinition(tokens));
+            for(String token : tokens) {
+                attributes.add(new SecurityConfig(token));
+            }
+
+            mappings.put(name, attributes);
         }
 
         setValue(new MapBasedMethodDefinitionSource(mappings));

+ 8 - 7
core/src/main/java/org/springframework/security/intercept/method/ProtectPointcutPostProcessor.java

@@ -4,6 +4,7 @@ import java.lang.reflect.Method;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -14,6 +15,7 @@ import org.aspectj.weaver.tools.PointcutParser;
 import org.aspectj.weaver.tools.PointcutPrimitive;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.security.ConfigAttribute;
 import org.springframework.security.ConfigAttributeDefinition;
 import org.springframework.security.intercept.method.aopalliance.MethodDefinitionSourceAdvisor;
 import org.springframework.util.Assert;
@@ -57,7 +59,7 @@ public final class ProtectPointcutPostProcessor implements BeanPostProcessor {
 
     private static final Log logger = LogFactory.getLog(ProtectPointcutPostProcessor.class);
 
-    private Map pointcutMap = new LinkedHashMap(); /** Key: string-based pointcut, value: ConfigAttributeDefinition */
+    private Map<String,List<ConfigAttribute>> pointcutMap = new LinkedHashMap();
     private MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource;
     private PointcutParser parser;
 
@@ -119,7 +121,7 @@ public final class ProtectPointcutPostProcessor implements BeanPostProcessor {
 
         // Handle accordingly
         if (matches) {
-            ConfigAttributeDefinition attr = (ConfigAttributeDefinition) pointcutMap.get(expression.getPointcutExpression());
+            List<ConfigAttribute> attr = pointcutMap.get(expression.getPointcutExpression());
 
             if (logger.isDebugEnabled()) {
                 logger.debug("AspectJ pointcut expression '" + expression.getPointcutExpression() + "' matches target class '" + targetClass.getName() + "' (bean ID '" + beanName + "') for method '" + method + "'; registering security configuration attribute '" + attr + "'");
@@ -131,18 +133,17 @@ public final class ProtectPointcutPostProcessor implements BeanPostProcessor {
         return matches;
     }
 
-    public void setPointcutMap(Map map) {
+    public void setPointcutMap(Map<String, List<ConfigAttribute>> map) {
         Assert.notEmpty(map);
         Iterator i = map.keySet().iterator();
         while (i.hasNext()) {
             String expression = i.next().toString();
-            Object value = map.get(expression);
-            Assert.isInstanceOf(ConfigAttributeDefinition.class, value, "Map keys must be instances of ConfigAttributeDefinition");
-            addPointcut(expression, (ConfigAttributeDefinition) value);
+            List<ConfigAttribute> value = map.get(expression);
+            addPointcut(expression, value);
         }
     }
 
-    private void addPointcut(String pointcutExpression, ConfigAttributeDefinition definition) {
+    private void addPointcut(String pointcutExpression, List<ConfigAttribute> definition) {
         Assert.hasText(pointcutExpression, "An AspectJ pointcut expression is required");
         Assert.notNull(definition, "ConfigAttributeDefinition required");
         pointcutExpression = replaceBooleanOperators(pointcutExpression);

+ 3 - 3
core/src/main/java/org/springframework/security/util/InMemoryXmlApplicationContext.java

@@ -13,9 +13,9 @@ public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext
                     "    xmlns:b='http://www.springframework.org/schema/beans'\n" +
                     "    xmlns:aop='http://www.springframework.org/schema/aop'\n" +
                     "    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n" +
-                    "    xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n" +
-                    "http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n" +
-                    "http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.2.xsd'>\n";
+                    "    xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\n" +
+                    "http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd\n" +
+                    "http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.5.xsd'>\n";
     private static final String BEANS_CLOSE = "</b:beans>\n";
 
     Resource inMemoryXml;

+ 2 - 1
core/src/main/resources/META-INF/spring.schemas

@@ -1,5 +1,6 @@
-http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
+http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-2.5.xsd
 http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/springframework/security/config/spring-security-2.0.xsd
 http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
 http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
 http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
+http\://www.springframework.org/schema/security/spring-security-2.5.xsd=org/springframework/security/config/spring-security-2.5.xsd

+ 12 - 0
core/src/test/java/org/springframework/security/annotation/BusinessService.java

@@ -15,9 +15,13 @@
 
 package org.springframework.security.annotation;
 
+import java.util.List;
+
 import javax.annotation.security.RolesAllowed;
 import javax.annotation.security.PermitAll;
 
+import org.springframework.security.expression.annotation.PreAuthorize;
+
 /**
  * @version $Id$
  */
@@ -28,6 +32,7 @@ public interface BusinessService {
 
     @Secured({"ROLE_ADMIN"})
     @RolesAllowed({"ROLE_ADMIN"})
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
     public void someAdminMethod();
 
     @Secured({"ROLE_USER", "ROLE_ADMIN"})
@@ -45,4 +50,11 @@ public interface BusinessService {
     public int someOther(String s);
 
     public int someOther(int input);
+
+    public List methodReturningAList(List someList);
+
+    public Object[] methodReturningAnArray(Object[] someArray);
+
+    public List methodReturningAList(String userName, String extraParam);
+
 }

+ 16 - 0
core/src/test/java/org/springframework/security/annotation/BusinessServiceImpl.java

@@ -1,5 +1,8 @@
 package org.springframework.security.annotation;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  *
  * @author Joe Scalise
@@ -33,4 +36,17 @@ public class BusinessServiceImpl<E extends Entity> implements BusinessService {
     public int someOther(int input) {
         return input;
     }
+
+    public List methodReturningAList(List someList) {
+        return someList;
+    }
+
+    public List methodReturningAList(String userName, String arg2) {
+        return new ArrayList();
+    }
+
+    public Object[] methodReturningAnArray(Object[] someArray) {
+        return null;
+    }
+
 }

+ 16 - 0
core/src/test/java/org/springframework/security/annotation/Jsr250BusinessServiceImpl.java

@@ -1,5 +1,8 @@
 package org.springframework.security.annotation;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import javax.annotation.security.RolesAllowed;
 import javax.annotation.security.PermitAll;
 
@@ -34,4 +37,17 @@ public class Jsr250BusinessServiceImpl implements BusinessService {
     public int someOther(int input) {
         return input;
     }
+
+    public List methodReturningAList(List someList) {
+        return someList;
+    }
+
+    public List methodReturningAList(String userName, String arg2) {
+        return new ArrayList();
+    }
+
+    public Object[] methodReturningAnArray(Object[] someArray) {
+        return null;
+    }
+
 }

+ 24 - 21
core/src/test/java/org/springframework/security/annotation/Jsr250MethodDefinitionSourceTests.java

@@ -2,6 +2,8 @@ package org.springframework.security.annotation;
 
 import static org.junit.Assert.assertEquals;
 
+import java.util.List;
+
 import javax.annotation.security.DenyAll;
 import javax.annotation.security.PermitAll;
 import javax.annotation.security.RolesAllowed;
@@ -9,6 +11,7 @@ import javax.annotation.security.RolesAllowed;
 import junit.framework.Assert;
 
 import org.junit.Test;
+import org.springframework.security.ConfigAttribute;
 import org.springframework.security.ConfigAttributeDefinition;
 
 /**
@@ -17,56 +20,56 @@ import org.springframework.security.ConfigAttributeDefinition;
  * @version $Id$
  */
 public class Jsr250MethodDefinitionSourceTests {
-	Jsr250MethodDefinitionSource mds = new Jsr250MethodDefinitionSource();
+    Jsr250MethodDefinitionSource mds = new Jsr250MethodDefinitionSource();
     A a = new A();
     UserAllowedClass userAllowed = new UserAllowedClass();
     DenyAllClass denyAll = new DenyAllClass();
 
     @Test
     public void methodWithRolesAllowedHasCorrectAttribute() throws Exception {
-        ConfigAttributeDefinition accessAttributes = mds.findAttributes(a.getClass().getMethod("adminMethod"), null);
-        assertEquals(1, accessAttributes.getConfigAttributes().size());
-        assertEquals("ADMIN", accessAttributes.getConfigAttributes().iterator().next().toString());
+        List<ConfigAttribute> accessAttributes = mds.findAttributes(a.getClass().getMethod("adminMethod"), null);
+        assertEquals(1, accessAttributes.size());
+        assertEquals("ADMIN", accessAttributes.get(0).toString());
     }
 
     @Test
     public void permitAllMethodHasPermitAllAttribute() throws Exception {
-        ConfigAttributeDefinition accessAttributes = mds.findAttributes(a.getClass().getMethod("permitAllMethod"), null);
-        assertEquals(1, accessAttributes.getConfigAttributes().size());
-        assertEquals("javax.annotation.security.PermitAll", accessAttributes.getConfigAttributes().iterator().next().toString());
+        List<ConfigAttribute> accessAttributes = mds.findAttributes(a.getClass().getMethod("permitAllMethod"), null);
+        assertEquals(1, accessAttributes.size());
+        assertEquals("javax.annotation.security.PermitAll", accessAttributes.get(0).toString());
     }
 
     @Test
     public void noRoleMethodHasDenyAllAttributeWithDenyAllClass() throws Exception {
-        ConfigAttributeDefinition accessAttributes = mds.findAttributes(denyAll.getClass());
-        assertEquals(1, accessAttributes.getConfigAttributes().size());
-        assertEquals("javax.annotation.security.DenyAll", accessAttributes.getConfigAttributes().iterator().next().toString());
+        List<ConfigAttribute> accessAttributes = mds.findAttributes(denyAll.getClass());
+        assertEquals(1, accessAttributes.size());
+        assertEquals("javax.annotation.security.DenyAll", accessAttributes.get(0).toString());
     }
 
     @Test
     public void adminMethodHasAdminAttributeWithDenyAllClass() throws Exception {
-        ConfigAttributeDefinition accessAttributes = mds.findAttributes(denyAll.getClass().getMethod("adminMethod"), null);
-        assertEquals(1, accessAttributes.getConfigAttributes().size());
-        assertEquals("ADMIN", accessAttributes.getConfigAttributes().iterator().next().toString());
+        List<ConfigAttribute> accessAttributes = mds.findAttributes(denyAll.getClass().getMethod("adminMethod"), null);
+        assertEquals(1, accessAttributes.size());
+        assertEquals("ADMIN", accessAttributes.get(0).toString());
     }
 
     @Test
     public void noRoleMethodHasNoAttributes() throws Exception {
-        ConfigAttributeDefinition accessAttributes = mds.findAttributes(a.getClass().getMethod("noRoleMethod"), null);
+        List<ConfigAttribute> accessAttributes = mds.findAttributes(a.getClass().getMethod("noRoleMethod"), null);
         Assert.assertNull(accessAttributes);
     }
-    
+
     @Test
     public void classRoleIsAppliedToNoRoleMethod() throws Exception {
-        ConfigAttributeDefinition accessAttributes = mds.findAttributes(userAllowed.getClass().getMethod("noRoleMethod"), null);
+        List<ConfigAttribute> accessAttributes = mds.findAttributes(userAllowed.getClass().getMethod("noRoleMethod"), null);
         Assert.assertNull(accessAttributes);
     }
 
     @Test
     public void methodRoleOverridesClassRole() throws Exception {
-        ConfigAttributeDefinition accessAttributes = mds.findAttributes(userAllowed.getClass().getMethod("adminMethod"), null);
-        assertEquals(1, accessAttributes.getConfigAttributes().size());
-        assertEquals("ADMIN", accessAttributes.getConfigAttributes().iterator().next().toString());
+        List<ConfigAttribute> accessAttributes = mds.findAttributes(userAllowed.getClass().getMethod("adminMethod"), null);
+        assertEquals(1, accessAttributes.size());
+        assertEquals("ADMIN", accessAttributes.get(0).toString());
     }
 
 //~ Inner Classes ======================================================================================================
@@ -87,7 +90,7 @@ public class Jsr250MethodDefinitionSourceTests {
         public void noRoleMethod() {}
 
         @RolesAllowed("ADMIN")
-        public void adminMethod() {}        
+        public void adminMethod() {}
     }
 
     @DenyAll
@@ -96,7 +99,7 @@ public class Jsr250MethodDefinitionSourceTests {
         public void noRoleMethod()  {}
 
         @RolesAllowed("ADMIN")
-        public void adminMethod() {}        
+        public void adminMethod() {}
     }
 
 

+ 19 - 24
core/src/test/java/org/springframework/security/annotation/SecuredMethodDefinitionSourceTests.java

@@ -15,11 +15,13 @@
 package org.springframework.security.annotation;
 
 import java.lang.reflect.Method;
+import java.util.List;
 
 import junit.framework.TestCase;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.springframework.security.ConfigAttribute;
 import org.springframework.security.ConfigAttributeDefinition;
 import org.springframework.security.SecurityConfig;
 import org.springframework.util.StringUtils;
@@ -50,22 +52,19 @@ public class SecuredMethodDefinitionSourceTests extends TestCase {
             fail("Should be a superMethod called 'someUserMethod3' on class!");
         }
 
-        ConfigAttributeDefinition attrs = this.mds.findAttributes(method, DepartmentServiceImpl.class);
+        List<ConfigAttribute> attrs = mds.findAttributes(method, DepartmentServiceImpl.class);
 
         assertNotNull(attrs);
 
         if (logger.isDebugEnabled()) {
-            logger.debug("attrs: " + StringUtils.collectionToCommaDelimitedString(attrs.getConfigAttributes()));
+            logger.debug("attrs: " + StringUtils.collectionToCommaDelimitedString(attrs));
         }
 
         // expect 1 attribute
-        assertTrue("Did not find 1 attribute", attrs.getConfigAttributes().size() == 1);
+        assertTrue("Did not find 1 attribute", attrs.size() == 1);
 
         // should have 1 SecurityConfig
-        for (Object obj : attrs.getConfigAttributes()) {
-            assertTrue(obj instanceof SecurityConfig);
-
-            SecurityConfig sc = (SecurityConfig) obj;
+        for (ConfigAttribute sc : attrs) {
             assertEquals("Found an incorrect role", "ROLE_ADMIN", sc.getAttribute());
         }
 
@@ -77,37 +76,35 @@ public class SecuredMethodDefinitionSourceTests extends TestCase {
             fail("Should be a superMethod called 'someUserMethod3' on class!");
         }
 
-        ConfigAttributeDefinition superAttrs = this.mds.findAttributes(superMethod, DepartmentServiceImpl.class);
+        List<ConfigAttribute> superAttrs = this.mds.findAttributes(superMethod, DepartmentServiceImpl.class);
 
         assertNotNull(superAttrs);
 
         if (logger.isDebugEnabled()) {
-            logger.debug("superAttrs: " + StringUtils.collectionToCommaDelimitedString(superAttrs.getConfigAttributes()));
+            logger.debug("superAttrs: " + StringUtils.collectionToCommaDelimitedString(superAttrs));
         }
 
         // This part of the test relates to SEC-274
         // expect 1 attribute
-        assertTrue("Did not find 1 attribute", superAttrs.getConfigAttributes().size() == 1);
+        assertEquals("Did not find 1 attribute", 1, superAttrs.size());
         // should have 1 SecurityConfig
-        for (Object obj : superAttrs.getConfigAttributes()) {
-        	assertTrue(obj instanceof SecurityConfig);
-            SecurityConfig sc = (SecurityConfig) obj;
+        for (ConfigAttribute sc : superAttrs) {
             assertEquals("Found an incorrect role", "ROLE_ADMIN", sc.getAttribute());
         }
     }
 
     public void testGetAttributesClass() {
-    	ConfigAttributeDefinition attrs = this.mds.findAttributes(BusinessService.class);
+        List<ConfigAttribute> attrs = this.mds.findAttributes(BusinessService.class);
 
         assertNotNull(attrs);
 
         // expect 1 annotation
-        assertTrue(attrs.getConfigAttributes().size() == 1);
+        assertEquals(1, attrs.size());
 
         // should have 1 SecurityConfig
-        SecurityConfig sc = (SecurityConfig) attrs.getConfigAttributes().iterator().next();
+        SecurityConfig sc = ((SecurityConfig) attrs.get(0));
 
-        assertTrue(sc.getAttribute().equals("ROLE_USER"));
+        assertEquals("ROLE_USER", sc.getAttribute());
     }
 
     public void testGetAttributesMethod() {
@@ -119,21 +116,19 @@ public class SecuredMethodDefinitionSourceTests extends TestCase {
             fail("Should be a method called 'someUserAndAdminMethod' on class!");
         }
 
-        ConfigAttributeDefinition attrs = this.mds.findAttributes(method, BusinessService.class);
+        List<ConfigAttribute> attrs = this.mds.findAttributes(method, BusinessService.class);
 
         assertNotNull(attrs);
 
         // expect 2 attributes
-        assertTrue(attrs.getConfigAttributes().size() == 2);
+        assertEquals(2, attrs.size());
 
         boolean user = false;
         boolean admin = false;
 
         // should have 2 SecurityConfigs
-        for (Object obj : attrs.getConfigAttributes()) {
-            assertTrue(obj instanceof SecurityConfig);
-
-            SecurityConfig sc = (SecurityConfig) obj;
+        for (ConfigAttribute sc : attrs) {
+            assertTrue(sc instanceof SecurityConfig);
 
             if (sc.getAttribute().equals("ROLE_USER")) {
                 user = true;
@@ -145,5 +140,5 @@ public class SecuredMethodDefinitionSourceTests extends TestCase {
         // expect to have ROLE_USER and ROLE_ADMIN
         assertTrue(user && admin);
     }
-    
+
 }

+ 2 - 2
core/src/test/java/org/springframework/security/config/CustomAfterInvocationProviderBeanDefinitionDecoratorTests.java

@@ -33,8 +33,8 @@ public class CustomAfterInvocationProviderBeanDefinitionDecoratorTests {
         MethodSecurityInterceptor msi = (MethodSecurityInterceptor) appContext.getBean(BeanIds.METHOD_SECURITY_INTERCEPTOR);
         AfterInvocationProviderManager apm = (AfterInvocationProviderManager) msi.getAfterInvocationManager();
         assertNotNull(apm);
-        assertEquals(1, apm.getProviders().size());
-        assertTrue(apm.getProviders().get(0) instanceof MockAfterInvocationProvider);
+        assertEquals(2, apm.getProviders().size());
+        assertTrue(apm.getProviders().get(1) instanceof MockAfterInvocationProvider);
     }
 
     private void setContext(String context) {

+ 47 - 0
core/src/test/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParserTests.java

@@ -3,6 +3,9 @@ package org.springframework.security.config;
 import static org.junit.Assert.*;
 import static org.springframework.security.config.ConfigTestUtils.*;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.junit.After;
 import org.junit.Test;
 import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
@@ -180,6 +183,50 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
         target.someUserMethod1();
     }
 
+    @Test(expected=AccessDeniedException.class)
+    public void accessIsDeniedForHasRoleExpression() {
+        setContext(
+                "<global-method-security spel-annotations='enabled'/>" +
+                "<b:bean id='target' class='org.springframework.security.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
+                AUTH_PROVIDER_XML);
+        SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
+        target = (BusinessService) appContext.getBean("target");
+        target.someAdminMethod();
+    }
+
+    @Test
+    public void preAndPostFilterAnnotationsWorkWithLists() {
+        setContext(
+                "<global-method-security spel-annotations='enabled'/>" +
+                "<b:bean id='target' class='org.springframework.security.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
+                AUTH_PROVIDER_XML);
+        SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
+        target = (BusinessService) appContext.getBean("target");
+        List arg = new ArrayList();
+        arg.add("joe");
+        arg.add("bob");
+        arg.add("sam");
+        List result = target.methodReturningAList(arg);
+        // Expression is (filterObject == name or filterObject == 'sam'), so "joe" should be gone after pre-filter
+        // PostFilter should remove sam from the return object
+        assertEquals(1, result.size());
+        assertEquals("bob", result.get(0));
+    }
+
+    @Test
+    public void preAndPostFilterAnnotationsWorkWithArrays() {
+        setContext(
+                "<global-method-security spel-annotations='enabled'/>" +
+                "<b:bean id='target' class='org.springframework.security.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
+                AUTH_PROVIDER_XML);
+        SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
+        target = (BusinessService) appContext.getBean("target");
+        Object[] arg = new String[] {"joe", "bob", "sam"};
+        Object[] result = target.methodReturningAnArray(arg);
+        assertEquals(1, result.length);
+        assertEquals("bob", result[0]);
+    }
+
     private void setContext(String context) {
         appContext = new InMemoryXmlApplicationContext(context);
     }

+ 71 - 0
core/src/test/java/org/springframework/security/expression/support/MethodExpressionVoterTests.java

@@ -0,0 +1,71 @@
+package org.springframework.security.expression.support;
+
+import static org.junit.Assert.assertEquals;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.aopalliance.intercept.MethodInvocation;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.security.annotation.ExpressionProtectedBusinessServiceImpl;
+import org.springframework.security.expression.support.AbstractExpressionBasedMethodConfigAttribute;
+import org.springframework.security.expression.support.MethodExpressionVoter;
+import org.springframework.security.providers.TestingAuthenticationToken;
+import org.springframework.security.util.SimpleMethodInvocation;
+import org.springframework.security.vote.AccessDecisionVoter;
+
+public class MethodExpressionVoterTests {
+    private TestingAuthenticationToken joe = new TestingAuthenticationToken("joe", "joespass", "blah");
+    private MethodInvocation miStringArgs;
+    private MethodInvocation miListArg;
+    private List listArg;
+
+    @Before
+    public void setUp() throws Exception {
+        Method m = ExpressionProtectedBusinessServiceImpl.class.getMethod("methodReturningAList",
+                String.class, String.class);
+        miStringArgs = new SimpleMethodInvocation(new Object(), m, new String[] {"joe", "arg2Value"});
+        m = ExpressionProtectedBusinessServiceImpl.class.getMethod("methodReturningAList", List.class);
+        listArg = new ArrayList(Arrays.asList("joe", "bob"));
+        miListArg = new SimpleMethodInvocation(new Object(), m, new Object[] {listArg});
+    }
+
+    @Test
+    public void hasRoleExpressionAllowsUserWithRole() throws Exception {
+        MethodExpressionVoter am = new MethodExpressionVoter();
+        ConfigAttributeDefinition cad = new ConfigAttributeDefinition(new PreInvocationExpressionBasedMethodConfigAttribute(null, null, "hasRole('blah')"));
+
+        assertEquals(AccessDecisionVoter.ACCESS_GRANTED, am.vote(joe, miStringArgs, cad));
+    }
+
+    @Test
+    public void hasRoleExpressionDeniesUserWithoutRole() throws Exception {
+        MethodExpressionVoter am = new MethodExpressionVoter();
+        ConfigAttributeDefinition cad = new ConfigAttributeDefinition(new PreInvocationExpressionBasedMethodConfigAttribute(null, null, "hasRole('joedoesnt')"));
+
+        assertEquals(AccessDecisionVoter.ACCESS_DENIED, am.vote(joe, miStringArgs, cad));
+    }
+
+    @Test
+    public void matchingArgAgainstAuthenticationNameIsSuccessful() throws Exception {
+        MethodExpressionVoter am = new MethodExpressionVoter();
+        ConfigAttributeDefinition cad = new ConfigAttributeDefinition(new PreInvocationExpressionBasedMethodConfigAttribute(null, null, "(#userName == name) and (name == 'joe')"));
+
+        assertEquals(AccessDecisionVoter.ACCESS_GRANTED, am.vote(joe, miStringArgs, cad));
+    }
+
+    @Test
+    public void accessIsGrantedIfNoPreAuthorizeAttributeIsUsed() throws Exception {
+        MethodExpressionVoter am = new MethodExpressionVoter();
+        ConfigAttributeDefinition cad = new ConfigAttributeDefinition(new PreInvocationExpressionBasedMethodConfigAttribute("(name == 'jim')", "someList", null));
+
+        assertEquals(AccessDecisionVoter.ACCESS_GRANTED, am.vote(joe, miListArg, cad));
+        // All objects should have been removed, because the expression is always false
+        assertEquals(0, listArg.size());
+    }
+
+}

+ 0 - 94
core/src/test/java/org/springframework/security/intercept/method/AbstractMethodDefinitionSourceTests.java

@@ -1,94 +0,0 @@
-/* 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.springframework.security.intercept.method;
-
-import junit.framework.TestCase;
-
-import org.springframework.security.util.SimpleMethodInvocation;
-
-import org.aopalliance.intercept.MethodInvocation;
-
-
-/**
- * Tests {@link AbstractMethodDefinitionSource} and associated {@link ConfigAttributeDefinition}.
- *
- * @author Ben Alex
- * @version $Id$
- */
-public class AbstractMethodDefinitionSourceTests extends TestCase {
-    //~ Constructors ===================================================================================================
-
-    public AbstractMethodDefinitionSourceTests() {
-        super();
-    }
-
-    public AbstractMethodDefinitionSourceTests(String arg0) {
-        super(arg0);
-    }
-
-    //~ Methods ========================================================================================================
-
-    public static void main(String[] args) {
-        junit.textui.TestRunner.run(AbstractMethodDefinitionSourceTests.class);
-    }
-
-    public final void setUp() throws Exception {
-        super.setUp();
-    }
-
-    public void testDoesNotSupportAnotherObject() {
-        MockMethodDefinitionSource mds = new MockMethodDefinitionSource(false, true);
-        assertFalse(mds.supports(String.class));
-    }
-
-    public void testGetAttributesForANonMethodInvocation() {
-        MockMethodDefinitionSource mds = new MockMethodDefinitionSource(false, true);
-
-        try {
-            mds.getAttributes(new String());
-            fail("Should have thrown IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {
-            assertTrue(true);
-        }
-    }
-
-    public void testGetAttributesForANullObject() {
-        MockMethodDefinitionSource mds = new MockMethodDefinitionSource(false, true);
-
-        try {
-            mds.getAttributes(null);
-            fail("Should have thrown IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {
-            assertTrue(true);
-        }
-    }
-
-    public void testGetAttributesForMethodInvocation() {
-        MockMethodDefinitionSource mds = new MockMethodDefinitionSource(false, true);
-
-        try {
-            mds.getAttributes(new SimpleMethodInvocation());
-            fail("Should have thrown UnsupportedOperationException");
-        } catch (UnsupportedOperationException expected) {
-            assertTrue(true);
-        }
-    }
-
-    public void testSupportsMethodInvocation() {
-        MockMethodDefinitionSource mds = new MockMethodDefinitionSource(false, true);
-        assertTrue(mds.supports(MethodInvocation.class));
-    }
-}

+ 9 - 6
core/src/test/java/org/springframework/security/intercept/method/MapBasedMethodDefinitionSourceTests.java

@@ -3,10 +3,13 @@ package org.springframework.security.intercept.method;
 import static org.junit.Assert.*;
 
 import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.security.ConfigAttribute;
+import org.springframework.security.SecurityConfig;
 
 /**
  * Tests for {@link MapBasedMethodDefinitionSource}.
@@ -15,8 +18,8 @@ import org.springframework.security.ConfigAttributeDefinition;
  * @since 2.0.4
  */
 public class MapBasedMethodDefinitionSourceTests {
-    private final ConfigAttributeDefinition ROLE_A = new ConfigAttributeDefinition("ROLE_A");
-    private final ConfigAttributeDefinition ROLE_B = new ConfigAttributeDefinition("ROLE_B");
+    private final List<? extends ConfigAttribute> ROLE_A = Arrays.asList(new SecurityConfig("ROLE_A"));
+    private final List<? extends ConfigAttribute> ROLE_B = Arrays.asList(new SecurityConfig("ROLE_B"));
     private MapBasedMethodDefinitionSource mds;
     private Method someMethodString;
     private Method someMethodInteger;
@@ -32,7 +35,7 @@ public class MapBasedMethodDefinitionSourceTests {
     public void wildcardedMatchIsOverwrittenByMoreSpecificMatch() {
         mds.addSecureMethod(MockService.class, "some*", ROLE_A);
         mds.addSecureMethod(MockService.class, "someMethod*", ROLE_B);
-        assertEquals(ROLE_B, mds.getAttributes(someMethodInteger, MockService.class));
+        assertEquals(ROLE_B, mds.getAttributes(someMethodInteger, MockService.class).getConfigAttributes());
     }
 
     @Test
@@ -40,8 +43,8 @@ public class MapBasedMethodDefinitionSourceTests {
         mds.addSecureMethod(MockService.class, someMethodInteger, ROLE_A);
         mds.addSecureMethod(MockService.class, someMethodString, ROLE_B);
 
-        assertEquals(ROLE_A, mds.getAttributes(someMethodInteger, MockService.class));
-        assertEquals(ROLE_B, mds.getAttributes(someMethodString, MockService.class));
+        assertEquals(ROLE_A, mds.getAttributes(someMethodInteger, MockService.class).getConfigAttributes());
+        assertEquals(ROLE_B, mds.getAttributes(someMethodString, MockService.class).getConfigAttributes());
     }
 
     private class MockService {

+ 0 - 57
core/src/test/java/org/springframework/security/intercept/method/MethodDefinitionAttributesTests.java

@@ -1,57 +0,0 @@
-/* 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.springframework.security.intercept.method;
-
-import java.lang.reflect.Method;
-
-import junit.framework.Assert;
-
-import org.junit.Test;
-import org.springframework.security.ConfigAttributeDefinition;
-import org.springframework.security.ITargetObject;
-
-
-/**
- * Tests {@link MethodDefinitionAttributes}.
- *
- * @author Cameron Braid
- * @author Ben Alex
- * @version $Id$
- */
-public class MethodDefinitionAttributesTests {
-
-	private MethodDefinitionAttributes build() {
-    	MethodDefinitionAttributes mda = new MethodDefinitionAttributes();
-    	mda.setAttributes(new MockAttributes());
-    	return mda;
-    }
-    
-    @Test
-    public void testMethodsReturned() throws Exception {
-        Class clazz = ITargetObject.class;
-        Method method = clazz.getMethod("countLength", new Class[] {String.class});
-    	ConfigAttributeDefinition result = build().findAttributes(method, ITargetObject.class);
-    	Assert.assertEquals(1, result.getConfigAttributes().size());
-    }
-
-    @Test
-    public void testClassesReturned() throws Exception {
-        Class clazz = ITargetObject.class;
-    	ConfigAttributeDefinition result = build().findAttributes(ITargetObject.class);
-    	Assert.assertEquals(1, result.getConfigAttributes().size());
-    }
-
-}

+ 12 - 5
core/src/test/java/org/springframework/security/intercept/method/MockMethodDefinitionSource.java

@@ -15,6 +15,8 @@
 
 package org.springframework.security.intercept.method;
 
+import org.aopalliance.intercept.MethodInvocation;
+import org.aspectj.lang.JoinPoint;
 import org.springframework.security.ConfigAttributeDefinition;
 
 import java.lang.reflect.Method;
@@ -29,7 +31,7 @@ import java.util.Collection;
  * @author Ben Alex
  * @version $Id$
  */
-public class MockMethodDefinitionSource extends AbstractMethodDefinitionSource {
+public class MockMethodDefinitionSource implements MethodDefinitionSource {
     //~ Instance fields ================================================================================================
 
     private List list;
@@ -65,14 +67,19 @@ public class MockMethodDefinitionSource extends AbstractMethodDefinitionSource {
             return list;
         } else {
             return null;
-        }
+        }	
     }
 
-    protected ConfigAttributeDefinition lookupAttributes(Method method) {
+    public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
         throw new UnsupportedOperationException("mock method not implemented");
     }
 
-	public ConfigAttributeDefinition getAttributes(Method method, Class targetClass) {
+    public ConfigAttributeDefinition getAttributes(Method method, Class targetClass) {
         throw new UnsupportedOperationException("mock method not implemented");
-	}
+    }
+
+    public boolean supports(Class clazz) {
+        return (MethodInvocation.class.isAssignableFrom(clazz) || JoinPoint.class.isAssignableFrom(clazz));
+    }
+
 }

+ 15 - 10
pom.xml

@@ -17,6 +17,7 @@
         <module>acl</module>
         <module>taglibs</module>
         <module>itest</module>
+        <module>spring-el</module>
   </modules>
 
     <description>Spring Security</description>
@@ -76,11 +77,16 @@
     </distributionManagement>
 
     <repositories>
-		<repository>
-			<id>spring-external</id>
-			<name>Spring Portfolio Release Repository</name>
-			<url>http://s3.amazonaws.com/maven.springframework.org/external</url>
-		</repository>
+        <repository>
+            <id>com.springsource.repository.bundles.release</id>
+            <name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</name>
+            <url>http://repository.springsource.com/maven/bundles/release</url>
+        </repository>
+        <repository>
+            <id>com.springsource.repository.bundles.external</id>
+            <name>SpringSource Enterprise Bundle Repository - External Bundle Releases</name>
+            <url>http://repository.springsource.com/maven/bundles/external</url>
+        </repository>         
     </repositories>
 
     <mailingLists>
@@ -634,14 +640,13 @@
             </dependency>
             <dependency>
                 <groupId>org.aspectj</groupId>
-                <artifactId>aspectjweaver</artifactId>
-                <optional>true</optional>
-                <version>1.5.4</version>
+                <artifactId>com.springsource.org.aspectj.runtime</artifactId>
+                <version>1.6.2.RELEASE</version>
             </dependency>	    
             <dependency>
                 <groupId>org.aspectj</groupId>
-                <artifactId>aspectjrt</artifactId>
-                <version>1.5.4</version>
+                <artifactId>com.springsource.org.aspectj.weaver</artifactId>
+                <version>1.6.2.RELEASE</version>
             </dependency>
             <dependency>
                 <groupId>org.springframework</groupId>

+ 0 - 9
samples/pom.xml

@@ -24,15 +24,6 @@
             <groupId>javax.servlet</groupId>
             <artifactId>servlet-api</artifactId>
         </dependency>        
-	<dependency>
-	    <groupId>org.aspectj</groupId>
-	    <artifactId>aspectjrt</artifactId>
-	</dependency>
-        <dependency>
-            <groupId>org.aspectj</groupId>
-            <artifactId>aspectjweaver</artifactId>
-            <optional>true</optional>
-        </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>jstl</artifactId>