diff --git a/core-tiger/src/main/java/org/springframework/security/annotation/Jsr250MethodDefinitionSource.java b/core-tiger/src/main/java/org/springframework/security/annotation/Jsr250MethodDefinitionSource.java new file mode 100644 index 0000000000..745632998c --- /dev/null +++ b/core-tiger/src/main/java/org/springframework/security/annotation/Jsr250MethodDefinitionSource.java @@ -0,0 +1,75 @@ +/* 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.annotation; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.annotation.security.DenyAll; +import javax.annotation.security.PermitAll; +import javax.annotation.security.RolesAllowed; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.security.ConfigAttributeDefinition; +import org.springframework.security.intercept.method.AbstractFallbackMethodDefinitionSource; + + +/** + * Sources method security metadata from major JSR 250 security annotations. + * + * @author Ben Alex + * @version $Id$ + */ +public class Jsr250MethodDefinitionSource extends AbstractFallbackMethodDefinitionSource { + + protected ConfigAttributeDefinition findAttributes(Class clazz) { + return processAnnotations(clazz.getAnnotations()); + } + + 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; + } +} diff --git a/core-tiger/src/main/java/org/springframework/security/annotation/Jsr250SecurityAnnotationAttributes.java b/core-tiger/src/main/java/org/springframework/security/annotation/Jsr250SecurityAnnotationAttributes.java deleted file mode 100644 index 96f843846e..0000000000 --- a/core-tiger/src/main/java/org/springframework/security/annotation/Jsr250SecurityAnnotationAttributes.java +++ /dev/null @@ -1,140 +0,0 @@ -package org.springframework.security.annotation; - -import org.springframework.security.SecurityConfig; -import org.springframework.metadata.Attributes; -import org.springframework.core.annotation.AnnotationUtils; - -import javax.annotation.security.PermitAll; -import javax.annotation.security.RolesAllowed; -import javax.annotation.security.DenyAll; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; -import java.util.ArrayList; -import java.lang.reflect.Method; -import java.lang.reflect.Field; -import java.lang.annotation.Annotation; - -/** - * Java 5 Annotation {@link Attributes} metadata implementation used for secure method interception using - * the security anotations defined in JSR-250. - *
- * This Attributes
implementation will return security configuration for classes described using the
- * Java JEE 5 annotations (DenyAll, PermitAll and RolesAllowed).
- *
- *
- * @author Mark St.Godard
- * @author Usama Rashwan
- * @author Luke Taylor
- * @since 2.0
- *
- * @see javax.annotation.security.RolesAllowed
- */
-
-public class Jsr250SecurityAnnotationAttributes implements Attributes {
-
- //~ Methods ========================================================================================================
-
- /**
- * Get the This
- *
- * The
- * For example:
- *
- * These security annotations are similiar to the Commons Attributes approach, however they are using Java 5
- * language-level metadata support.
- *
- * @author Mark St.Godard
- * @version $Id$
- *
- * @see org.springframework.security.annotation.Secured
- */
-public class SecurityAnnotationAttributes implements Attributes {
- //~ Methods ========================================================================================================
-
- /**
- * Get the
+ * This class mimics the behaviour of Spring's AbstractFallbackTransactionAttributeSource class.
+ *
+ * Note that this class cannot extract security metadata where that metadata is expressed by way of
+ * a target method/class (ie #1 and #2 above) AND the target method/class is encapsulated in another
+ * proxy object. Spring Security does not walk a proxy chain to locate the concrete/final target object.
+ * Consider making Spring Security your final advisor (so it advises the final target, as opposed to
+ * another proxy), move the metadata to declared methods or interfaces the proxy implements, or provide
+ * your own replacement MethodDefinitionSource.
+ *
+ * Note that the {@link Method#getDeclaringClass()} may not equal the
+ * Subclasses should only return metadata expressed at a class level. Subclasses should NOT
+ * aggregate metadata for each method registered against a class, as the abstract superclass
+ * will separate invoke {@link #findAttributes(Method, Class)} for individual methods as
+ * appropriate.
+ *
+ * @param clazz the target class for the invocation (never For
- * consistency with {@link MethodDefinitionAttributes} as well as support for
- * In general you should therefore define the interface methods of your secure objects, not the
- * implementations. For example, define
+ * This class is the preferred implementation of {@link MethodDefinitionSource} for XML-based
+ * definition of method security metadata. To assist in XML-based definition, wildcard support
+ * is provided.
+ *
- * This class will only detect those attributes which are defined for:
- *
* 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.
*
+ *
* Attributes detected that do not implement {@link ConfigAttribute} will be ignored.
*
* @author Cameron Braid
* @author Ben Alex
* @version $Id$
*/
-public class MethodDefinitionAttributes extends AbstractMethodDefinitionSource {
+public class MethodDefinitionAttributes extends AbstractFallbackMethodDefinitionSource implements InitializingBean {
//~ Instance fields ================================================================================================
private Attributes attributes;
//~ Methods ========================================================================================================
- private void add(List definition, Collection attribs) {
- for (Iterator iter = attribs.iterator(); iter.hasNext();) {
- Object o = iter.next();
-
- if (o instanceof ConfigAttribute) {
- definition.add(o);
- }
- }
- }
-
- private void addClassAttributes(List definition, Class[] clazz) {
- for (int i = 0; i < clazz.length; i++) {
- Collection classAttributes = attributes.getAttributes(clazz[i]);
-
- if (classAttributes != null) {
- add(definition, classAttributes);
- }
- }
- }
-
- private void addInterfaceMethodAttributes(List definition, Method method) {
- Class[] interfaces = method.getDeclaringClass().getInterfaces();
-
- for (int i = 0; i < interfaces.length; i++) {
- Class clazz = interfaces[i];
-
- try {
- Method m = clazz.getDeclaredMethod(method.getName(), (Class[]) method.getParameterTypes());
- addMethodAttributes(definition, m);
- } catch (Exception e) {
- // this won't happen since we are getting a method from an interface that
- // the declaring class implements
- }
- }
- }
-
- private void addMethodAttributes(List definition, Method method) {
- // add the method level attributes
- Collection methodAttributes = attributes.getAttributes(method);
-
- if (methodAttributes != null) {
- add(definition, methodAttributes);
- }
- }
+ 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 lookupAttributes(Method method) {
- Class interceptedClass = method.getDeclaringClass();
- List attributes = new ArrayList();
-
- // add the class level attributes for the implementing class
- addClassAttributes(attributes, new Class[] {interceptedClass});
-
- // add the class level attributes for the implemented interfaces
- addClassAttributes(attributes, interceptedClass.getInterfaces());
-
- // add the method level attributes for the implemented method
- addMethodAttributes(attributes, method);
-
- // add the method level attributes for the implemented intreface methods
- addInterfaceMethodAttributes(attributes, method);
-
- if (attributes.size() == 0) {
- return null;
- }
-
- return new ConfigAttributeDefinition(attributes);
- }
+ 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;
}
}
diff --git a/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionSource.java b/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionSource.java
index ff3e9f8289..fd97377067 100644
--- a/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionSource.java
+++ b/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionSource.java
@@ -15,14 +15,19 @@
package org.springframework.security.intercept.method;
+import java.lang.reflect.Method;
+
+import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.intercept.ObjectDefinitionSource;
/**
- * Marker interface for The class creates and populates a {@link MethodDefinitionMap}. The class creates and populates a {@link MapBasedMethodDefinitionSource}.RolesAllowed
attributes for a given target class.
- * This method will return an empty Collection because the call to getAttributes(method) will override the class
- * annotation.
- *
- * @param target The target Object
- * @return Empty Collection of SecurityConfig
- *
- * @see Attributes#getAttributes
- */
- public CollectionSecurityConfig
- * @see Attributes#getAttributes
- */
- public CollectionAttributes
metadata implementation used for secure method interception.Attributes
implementation will return security configuration for classes described using the
- * Secured
Java 5 annotation.
- * SecurityAnnotationAttributes
implementation can be used to configure a
- * MethodDefinitionAttributes
and MethodSecurityInterceptor
bean definition (see below).
- *
- * <bean id="attributes" class="org.springframework.security.annotation.SecurityAnnotationAttributes"/>
- * <bean id="objectDefinitionSource"
- * class="org.springframework.security.intercept.method.MethodDefinitionAttributes">
- * <property name="attributes"><ref local="attributes"/></property>
- * </bean>
- * <bean id="securityInterceptor"
- * class="org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor">
- * . . .
- * <property name="objectDefinitionSource"><ref local="objectDefinitionSource"/></property>
- * </bean>
- *
- * Secured
attributes for a given target class.
- *
- * @param target The target method
- *
- * @return Collection of SecurityConfig
- *
- * @see Attributes#getAttributes
- */
- public Collection getAttributes(Class target) {
- SetSecured
attributes for a given target method.
- *
- * @param method The target method
- *
- * @return Collection of SecurityConfig
- *
- * @see Attributes#getAttributes
- */
- public Collection getAttributes(Method method) {
- SetMethodDefinitionMap
.
+ * Extra tests to demonstrate generics behaviour with MapBasedMethodDefinitionSource
.
*
* @author Ben Alex
* @version $Id$
@@ -41,58 +38,53 @@ import org.aopalliance.intercept.MethodInvocation;
public class MethodDefinitionSourceEditorTigerTests extends TestCase {
//~ Methods ========================================================================================================
- public void testConcreteClassInvocationsAlsoReturnDefinitionsAgainstInterface() throws Exception {
+ public void testConcreteClassInvocations() throws Exception {
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
editor.setAsText(
- "org.springframework.security.annotation.test.Service.makeLower*=ROLE_FROM_INTERFACE\r\norg.springframework.security.annotation.test.Service.makeUpper*=ROLE_FROM_INTERFACE\r\norg.springframework.security.annotation.test.ServiceImpl.makeUpper*=ROLE_FROM_IMPLEMENTATION");
+ "org.springframework.security.annotation.test.Service.makeLower*=ROLE_FROM_INTERFACE\r\n" +
+ "org.springframework.security.annotation.test.Service.makeUpper*=ROLE_FROM_INTERFACE\r\n" +
+ "org.springframework.security.annotation.test.ServiceImpl.makeUpper*=ROLE_FROM_IMPLEMENTATION");
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
assertEquals(3, map.getMethodMapSize());
ConfigAttributeDefinition returnedMakeLower = map.getAttributes(new MockMethodInvocation(Service.class,
- "makeLowerCase", new Class[]{Entity.class}));
+ "makeLowerCase", new Class[]{Entity.class}, new PersonServiceImpl()));
ConfigAttributeDefinition expectedMakeLower = new ConfigAttributeDefinition("ROLE_FROM_INTERFACE");
assertEquals(expectedMakeLower, returnedMakeLower);
- ConfigAttributeDefinition returnedMakeUpper = map.getAttributes(new MockMethodInvocation(ServiceImpl.class,
- "makeUpperCase", new Class[]{Entity.class}));
- ConfigAttributeDefinition expectedMakeUpper = new ConfigAttributeDefinition(new String[]{"ROLE_FROM_IMPLEMENTATION", "ROLE_FROM_INTERFACE"});
+ ConfigAttributeDefinition returnedMakeUpper = map.getAttributes(new MockMethodInvocation(Service.class,
+ "makeUpperCase", new Class[]{Entity.class}, new PersonServiceImpl()));
+ ConfigAttributeDefinition expectedMakeUpper = new ConfigAttributeDefinition(new String[]{"ROLE_FROM_IMPLEMENTATION"});
assertEquals(expectedMakeUpper, returnedMakeUpper);
}
- public void testGenericsSuperclassDeclarationsAreIncludedWhenSubclassesOverride() throws Exception {
+ public void testBridgeMethodResolution() throws Exception {
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
editor.setAsText(
- "org.springframework.security.annotation.test.Service.makeLower*=ROLE_FROM_INTERFACE\r\norg.springframework.security.annotation.test.Service.makeUpper*=ROLE_FROM_INTERFACE\r\norg.springframework.security.annotation.test.ServiceImpl.makeUpper*=ROLE_FROM_IMPLEMENTATION");
+ "org.springframework.security.annotation.test.PersonService.makeUpper*=ROLE_FROM_INTERFACE\r\n" +
+ "org.springframework.security.annotation.test.ServiceImpl.makeUpper*=ROLE_FROM_ABSTRACT\r\n" +
+ "org.springframework.security.annotation.test.PersonServiceImpl.makeUpper*=ROLE_FROM_PSI");
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
assertEquals(3, map.getMethodMapSize());
- ConfigAttributeDefinition returnedMakeLower = map.getAttributes(new MockMethodInvocation(PersonService.class,
- "makeLowerCase", new Class[]{Entity.class}));
- ConfigAttributeDefinition expectedMakeLower = new ConfigAttributeDefinition("ROLE_FROM_INTERFACE");
- assertEquals(expectedMakeLower, returnedMakeLower);
-
- ConfigAttributeDefinition returnedMakeLower2 = map.getAttributes(new MockMethodInvocation(
- OrganisationService.class, "makeLowerCase", new Class[]{Entity.class}));
- ConfigAttributeDefinition expectedMakeLower2 = new ConfigAttributeDefinition("ROLE_FROM_INTERFACE");
- assertEquals(expectedMakeLower2, returnedMakeLower2);
-
- ConfigAttributeDefinition returnedMakeUpper = map.getAttributes(new MockMethodInvocation(
- PersonServiceImpl.class, "makeUpperCase", new Class[]{Entity.class}));
- ConfigAttributeDefinition expectedMakeUpper = new ConfigAttributeDefinition(new String[]{"ROLE_FROM_IMPLEMENTATION", "ROLE_FROM_INTERFACE"});
+ ConfigAttributeDefinition returnedMakeUpper = map.getAttributes(new MockMethodInvocation(Service.class,
+ "makeUpperCase", new Class[]{Entity.class}, new PersonServiceImpl()));
+ ConfigAttributeDefinition expectedMakeUpper = new ConfigAttributeDefinition(new String[]{"ROLE_FROM_PSI"});
assertEquals(expectedMakeUpper, returnedMakeUpper);
}
//~ Inner Classes ==================================================================================================
private class MockMethodInvocation implements MethodInvocation {
- Method method;
+ private Method method;
+ private Object targetObject;
- public MockMethodInvocation(Class clazz, String methodName, Class[] parameterTypes)
+ public MockMethodInvocation(Class clazz, String methodName, Class[] parameterTypes, Object targetObject)
throws NoSuchMethodException {
- System.out.println(clazz + " " + methodName + " " + parameterTypes[0]);
- method = clazz.getMethod(methodName, parameterTypes);
+ this.method = clazz.getMethod(methodName, parameterTypes);
+ this.targetObject = targetObject;
}
public Object[] getArguments() {
@@ -108,11 +100,12 @@ public class MethodDefinitionSourceEditorTigerTests extends TestCase {
}
public Object getThis() {
- return null;
+ return targetObject;
}
public Object proceed() throws Throwable {
return null;
}
}
+
}
diff --git a/core-tiger/src/test/java/org/springframework/security/annotation/SecurityAnnotationAttributesTests.java b/core-tiger/src/test/java/org/springframework/security/annotation/SecuredMethodDefinitionSourceTests.java
similarity index 52%
rename from core-tiger/src/test/java/org/springframework/security/annotation/SecurityAnnotationAttributesTests.java
rename to core-tiger/src/test/java/org/springframework/security/annotation/SecuredMethodDefinitionSourceTests.java
index e29ac34301..1bb761ea6f 100644
--- a/core-tiger/src/test/java/org/springframework/security/annotation/SecurityAnnotationAttributesTests.java
+++ b/core-tiger/src/test/java/org/springframework/security/annotation/SecuredMethodDefinitionSourceTests.java
@@ -14,41 +14,33 @@
*/
package org.springframework.security.annotation;
-import junit.framework.TestCase;
+import java.lang.reflect.Method;
-import org.springframework.security.SecurityConfig;
+import junit.framework.TestCase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-
-import org.springframework.metadata.Attributes;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-import java.util.Collection;
+import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.security.SecurityConfig;
+import org.springframework.util.StringUtils;
/**
- * Tests for {@link org.springframework.security.annotation.SecurityAnnotationAttributes}
+ * Tests for {@link org.springframework.security.annotation.SecuredMethodDefinitionSource}
*
* @author Mark St.Godard
* @author Joe Scalise
+ * @author Ben Alex
* @version $Id$
*/
-public class SecurityAnnotationAttributesTests extends TestCase {
+public class SecuredMethodDefinitionSourceTests extends TestCase {
//~ Instance fields ================================================================================================
- private Attributes attributes;
- private Log logger = LogFactory.getLog(SecurityAnnotationAttributesTests.class);
+ private SecuredMethodDefinitionSource mds = new SecuredMethodDefinitionSource();;
+ private Log logger = LogFactory.getLog(SecuredMethodDefinitionSourceTests.class);
//~ Methods ========================================================================================================
- protected void setUp() throws Exception {
- // create the Annotations impl
- this.attributes = new SecurityAnnotationAttributes();
- }
-
public void testGenericsSuperclassDeclarationsAreIncludedWhenSubclassesOverride() {
Method method = null;
@@ -58,20 +50,19 @@ public class SecurityAnnotationAttributesTests extends TestCase {
fail("Should be a superMethod called 'someUserMethod3' on class!");
}
- Collection attrs = this.attributes.getAttributes(method);
-
- if (logger.isDebugEnabled()) {
- logger.debug("attrs: ");
- logger.debug(attrs);
- }
+ ConfigAttributeDefinition attrs = this.mds.findAttributes(method, DepartmentServiceImpl.class);
assertNotNull(attrs);
+ if (logger.isDebugEnabled()) {
+ logger.debug("attrs: " + StringUtils.collectionToCommaDelimitedString(attrs.getConfigAttributes()));
+ }
+
// expect 1 attribute
- assertTrue("Did not find 1 attribute", attrs.size() == 1);
+ assertTrue("Did not find 1 attribute", attrs.getConfigAttributes().size() == 1);
// should have 1 SecurityConfig
- for (Object obj : attrs) {
+ for (Object obj : attrs.getConfigAttributes()) {
assertTrue(obj instanceof SecurityConfig);
SecurityConfig sc = (SecurityConfig) obj;
@@ -86,67 +77,39 @@ public class SecurityAnnotationAttributesTests extends TestCase {
fail("Should be a superMethod called 'someUserMethod3' on class!");
}
- System.out.println(superMethod);
-
- Collection superAttrs = this.attributes.getAttributes(superMethod);
-
- if (logger.isDebugEnabled()) {
- logger.debug("superAttrs: ");
- logger.debug(superAttrs);
- }
+ ConfigAttributeDefinition superAttrs = this.mds.findAttributes(superMethod, DepartmentServiceImpl.class);
assertNotNull(superAttrs);
- // TODO: Enable this part of the test once we can build against Spring 2.0+ and above only (SEC-274)
- /*
- // expect 1 attribute
- assertTrue("Did not find 1 attribute", superAttrs.size() == 1);
- // should have 1 SecurityConfig
- for (Object obj : superAttrs) {
- assertTrue(obj instanceof SecurityConfig);
- SecurityConfig sc = (SecurityConfig) obj;
- assertEquals("Found an incorrect role", "ROLE_ADMIN", sc.getAttribute());
- }
- */
+ if (logger.isDebugEnabled()) {
+ logger.debug("superAttrs: " + StringUtils.collectionToCommaDelimitedString(superAttrs.getConfigAttributes()));
+ }
+
+ // This part of the test relates to SEC-274
+ // expect 1 attribute
+ assertTrue("Did not find 1 attribute", superAttrs.getConfigAttributes().size() == 1);
+ // should have 1 SecurityConfig
+ for (Object obj : superAttrs.getConfigAttributes()) {
+ assertTrue(obj instanceof SecurityConfig);
+ SecurityConfig sc = (SecurityConfig) obj;
+ assertEquals("Found an incorrect role", "ROLE_ADMIN", sc.getAttribute());
+ }
}
public void testGetAttributesClass() {
- Collection attrs = this.attributes.getAttributes(BusinessService.class);
+ ConfigAttributeDefinition attrs = this.mds.findAttributes(BusinessService.class);
assertNotNull(attrs);
// expect 1 annotation
- assertTrue(attrs.size() == 1);
+ assertTrue(attrs.getConfigAttributes().size() == 1);
// should have 1 SecurityConfig
- SecurityConfig sc = (SecurityConfig) attrs.iterator().next();
+ SecurityConfig sc = (SecurityConfig) attrs.getConfigAttributes().iterator().next();
assertTrue(sc.getAttribute().equals("ROLE_USER"));
}
- public void testGetAttributesClassClass() {
- try {
- this.attributes.getAttributes(BusinessService.class, null);
- fail("Unsupported method should have thrown an exception!");
- } catch (UnsupportedOperationException expected) {}
- }
-
- public void testGetAttributesField() {
- try {
- Field field = null;
- this.attributes.getAttributes(field);
- fail("Unsupported method should have thrown an exception!");
- } catch (UnsupportedOperationException expected) {}
- }
-
- public void testGetAttributesFieldClass() {
- try {
- Field field = null;
- this.attributes.getAttributes(field, null);
- fail("Unsupported method should have thrown an exception!");
- } catch (UnsupportedOperationException expected) {}
- }
-
public void testGetAttributesMethod() {
Method method = null;
@@ -156,18 +119,18 @@ public class SecurityAnnotationAttributesTests extends TestCase {
fail("Should be a method called 'someUserAndAdminMethod' on class!");
}
- Collection attrs = this.attributes.getAttributes(method);
+ ConfigAttributeDefinition attrs = this.mds.findAttributes(method, BusinessService.class);
assertNotNull(attrs);
// expect 2 attributes
- assertTrue(attrs.size() == 2);
+ assertTrue(attrs.getConfigAttributes().size() == 2);
boolean user = false;
boolean admin = false;
// should have 2 SecurityConfigs
- for (Object obj : attrs) {
+ for (Object obj : attrs.getConfigAttributes()) {
assertTrue(obj instanceof SecurityConfig);
SecurityConfig sc = (SecurityConfig) obj;
@@ -182,19 +145,5 @@ public class SecurityAnnotationAttributesTests extends TestCase {
// expect to have ROLE_USER and ROLE_ADMIN
assertTrue(user && admin);
}
-
- public void testGetAttributesMethodClass() {
- Method method = null;
-
- try {
- method = BusinessService.class.getMethod("someUserAndAdminMethod", new Class[] {});
- } catch (NoSuchMethodException unexpected) {
- fail("Should be a method called 'someUserAndAdminMethod' on class!");
- }
-
- try {
- this.attributes.getAttributes(method, null);
- fail("Unsupported method should have thrown an exception!");
- } catch (UnsupportedOperationException expected) {}
- }
+
}
diff --git a/core/src/main/java/org/springframework/security/ConfigAttributeDefinition.java b/core/src/main/java/org/springframework/security/ConfigAttributeDefinition.java
index e3b4673301..087b6ebbf3 100644
--- a/core/src/main/java/org/springframework/security/ConfigAttributeDefinition.java
+++ b/core/src/main/java/org/springframework/security/ConfigAttributeDefinition.java
@@ -15,15 +15,14 @@
package org.springframework.security;
-import org.springframework.util.Assert;
-
import java.io.Serializable;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.Collections;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.springframework.util.Assert;
/**
@@ -99,6 +98,33 @@ public class ConfigAttributeDefinition implements Serializable {
this.configAttributes = Collections.unmodifiableList(new ArrayList(configAttributes));
}
+
+ /**
+ * Creates a ConfigAttributeDefinition by including only those attributes which implement ConfigAttribute.
+ *
+ * @param unfilteredInput a collection of various elements, zero or more which implement ConfigAttribute (can also be null)
+ * @return a ConfigAttributeDefinition if at least one ConfigAttribute was present, or null 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 ========================================================================================================
diff --git a/core/src/main/java/org/springframework/security/config/AnnotationDrivenBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/AnnotationDrivenBeanDefinitionParser.java
index d3bfa66d47..43631764eb 100644
--- a/core/src/main/java/org/springframework/security/config/AnnotationDrivenBeanDefinitionParser.java
+++ b/core/src/main/java/org/springframework/security/config/AnnotationDrivenBeanDefinitionParser.java
@@ -23,8 +23,8 @@ import org.w3c.dom.Element;
* @version $Id$
*/
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
- public static final String SECURITY_ANNOTATION_ATTRIBUTES_CLASS = "org.springframework.security.annotation.SecurityAnnotationAttributes";
- public static final String JSR_250_SECURITY_ANNOTATION_ATTRIBUTES_CLASS = "org.springframework.security.annotation.Jsr250SecurityAnnotationAttributes";
+ public static final String SECURED_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.annotation.SecuredMethodDefinitionSource";
+ 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_MGR = "access-decision-manager-ref";
private static final String ATT_USE_JSR250 = "jsr250";
@@ -32,10 +32,12 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
boolean useJsr250 = "true".equals(element.getAttribute(ATT_USE_JSR250));
String className = useJsr250 ?
- JSR_250_SECURITY_ANNOTATION_ATTRIBUTES_CLASS : SECURITY_ANNOTATION_ATTRIBUTES_CLASS;
+ JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS : SECURED_METHOD_DEFINITION_SOURCE_CLASS;
+ String beanId = useJsr250 ? BeanIds.JSR_250_METHOD_DEFINITION_SOURCE : BeanIds.SECURED_METHOD_DEFINITION_SOURCE;
+
// Reflectively obtain the Annotation-based ObjectDefinitionSource.
- // Reflection is used to avoid a compile-time dependency on SECURITY_ANNOTATION_ATTRIBUTES_CLASS, as this parser is in the Java 4 project whereas the dependency is in the Tiger project.
+ // Reflection is used to avoid a compile-time dependency on SECURED_METHOD_DEFINITION_SOURCE_CLASS, as this parser is in the Java 4 project whereas the dependency is in the Tiger project.
Assert.isTrue(ClassUtils.isPresent(className), "Could not locate class '" + className + "' - please ensure the spring-security-tiger-xxx.jar is in your classpath and you are running Java 5 or above.");
Class clazz = null;
@@ -47,15 +49,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
RootBeanDefinition securityAnnotations = new RootBeanDefinition(clazz);
securityAnnotations.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
- parserContext.getRegistry().registerBeanDefinition(BeanIds.SECURITY_ANNOTATION_ATTRIBUTES, securityAnnotations);
-
- RootBeanDefinition methodDefinitionAttributes = new RootBeanDefinition(MethodDefinitionAttributes.class);
- methodDefinitionAttributes.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
- methodDefinitionAttributes.getPropertyValues().addPropertyValue("attributes", new RuntimeBeanReference(BeanIds.SECURITY_ANNOTATION_ATTRIBUTES));
- parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_ATTRIBUTES, methodDefinitionAttributes);
-
- RootBeanDefinition interceptor = new RootBeanDefinition(MethodSecurityInterceptor.class);
- interceptor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+ parserContext.getRegistry().registerBeanDefinition(beanId, securityAnnotations);
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
@@ -69,15 +63,22 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
accessManagerId = BeanIds.ACCESS_MANAGER;
}
+ // MethodSecurityInterceptor
+
+ RootBeanDefinition interceptor = new RootBeanDefinition(MethodSecurityInterceptor.class);
+ interceptor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+
interceptor.getPropertyValues().addPropertyValue("accessDecisionManager",
new RuntimeBeanReference(accessManagerId));
interceptor.getPropertyValues().addPropertyValue("authenticationManager",
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
- interceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", new RuntimeBeanReference(BeanIds.METHOD_DEFINITION_ATTRIBUTES));
+ interceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", new RuntimeBeanReference(beanId));
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR, interceptor);
+ // MethodDefinitionSourceAdvisor
+
RootBeanDefinition advisor = new RootBeanDefinition(MethodDefinitionSourceAdvisor.class);
advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
advisor.getConstructorArgumentValues().addGenericArgumentValue(interceptor);
diff --git a/core/src/main/java/org/springframework/security/config/BeanIds.java b/core/src/main/java/org/springframework/security/config/BeanIds.java
index e6613d5f6f..a4c45860e4 100644
--- a/core/src/main/java/org/springframework/security/config/BeanIds.java
+++ b/core/src/main/java/org/springframework/security/config/BeanIds.java
@@ -48,8 +48,8 @@ public abstract class BeanIds {
public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
public static final String METHOD_SECURITY_INTERCEPTOR = "_methodSecurityInterceptor";
public static final String METHOD_DEFINITION_SOURCE_ADVISOR = "_methodDefinitionSourceAdvisor";
- public static final String SECURITY_ANNOTATION_ATTRIBUTES = "_securityAnnotationAttributes";
- public static final String METHOD_DEFINITION_ATTRIBUTES = "_methodDefinitionAttributes";
+ 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";
diff --git a/core/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java b/core/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java
index 9d23230358..97e5907cfe 100644
--- a/core/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java
+++ b/core/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java
@@ -1,28 +1,24 @@
package org.springframework.security.config;
+import java.util.Iterator;
+import java.util.List;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.config.AbstractInterceptorDrivenBeanDefinitionDecorator;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
-import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
import org.springframework.beans.factory.xml.ParserContext;
-import org.springframework.security.ConfigAttributeDefinition;
-import org.springframework.security.ConfigAttributeEditor;
-import org.springframework.security.intercept.method.MethodDefinitionMap;
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
-import org.springframework.util.xml.DomUtils;
import org.springframework.util.StringUtils;
-
+import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
-import java.util.Iterator;
-import java.util.List;
-
/**
* @author Luke Taylor
* @author Ben Alex
@@ -35,17 +31,16 @@ public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDe
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
-
+
return delegate.decorate(node, definition, parserContext);
}
}
/**
- * This is the real class which does the work. We need acccess to the ParserContext in order to do bean
+ * This is the real class which does the work. We need access to the ParserContext in order to do bean
* registration.
*/
class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractInterceptorDrivenBeanDefinitionDecorator {
- static final String ATT_CLASS = "class";
static final String ATT_METHOD = "method";
static final String ATT_ACCESS = "access";
private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
@@ -68,24 +63,35 @@ class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractIntercepto
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");
+ parent = null;
+
// Parse the included methods
List methods = DomUtils.getChildElementsByTagName(interceptMethodsElt, Elements.PROTECT);
- MethodDefinitionMap methodMap = new MethodDefinitionMap();
- ConfigAttributeEditor attributeEditor = new ConfigAttributeEditor();
+ StringBuffer sb = new StringBuffer();
+
for (Iterator i = methods.iterator(); i.hasNext();) {
Element protectmethodElt = (Element) i.next();
String accessConfig = protectmethodElt.getAttribute(ATT_ACCESS);
- attributeEditor.setAsText(accessConfig);
-// TODO: We want to use just the method names, but MethodDefinitionMap won't work that way.
-// methodMap.addSecureMethod(targetClass, protectmethodElt.getAttribute("method"),
-// (ConfigAttributeDefinition) attributeEditor.getValue());
- methodMap.addSecureMethod(protectmethodElt.getAttribute(ATT_METHOD),
- (ConfigAttributeDefinition) attributeEditor.getValue());
+ // Support inference of class names
+ String methodName = protectmethodElt.getAttribute(ATT_METHOD);
+
+ if (methodName.lastIndexOf(".") == -1) {
+ 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", methodMap);
+
+ interceptor.addPropertyValue("objectDefinitionSource", sb.toString());
return interceptor.getBeanDefinition();
}
diff --git a/core/src/main/java/org/springframework/security/intercept/method/AbstractFallbackMethodDefinitionSource.java b/core/src/main/java/org/springframework/security/intercept/method/AbstractFallbackMethodDefinitionSource.java
new file mode 100644
index 0000000000..4997c2c451
--- /dev/null
+++ b/core/src/main/java/org/springframework/security/intercept/method/AbstractFallbackMethodDefinitionSource.java
@@ -0,0 +1,200 @@
+package org.springframework.security.intercept.method;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.aopalliance.intercept.MethodInvocation;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.reflect.CodeSignature;
+import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * Abstract implementation of {@link MethodDefinitionSource} that supports both Spring AOP and AspectJ and
+ * caches configuration attribute resolution from: 1. specific target method; 2. target class; 3. declaring method;
+ * 4. declaring class/interface.
+ *
+ * null
)
+ * @param targetClass the target class for this invocation (may be null
)
+ * @return
+ */
+ private ConfigAttributeDefinition 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);
+ if (attr != null) {
+ return attr;
+ }
+
+ // Second try is the config attribute on the target class.
+ attr = findAttributes(specificMethod.getDeclaringClass());
+ if (attr != null) {
+ return attr;
+ }
+
+ if (specificMethod != method) {
+ // Fallback is to look at the original method.
+ attr = findAttributes(method, method.getDeclaringClass());
+ if (attr != null) {
+ return attr;
+ }
+ // Last fallback is the class of the original method.
+ return findAttributes(method.getDeclaringClass());
+ }
+ return null;
+
+ }
+
+ /**
+ * Obtains the security metadata applicable to the specified method invocation.
+ *
+ * targetClass
.
+ * Both parameters are provided to assist subclasses which may wish to provide advanced
+ * capabilities related to method metadata being "registered" against a method even if the
+ * target class does not declare the method (ie the subclass may only inherit the method).
+ *
+ * @param method the method for the current invocation (never null
)
+ * @param targetClass the target class for the invocation (may be null
)
+ * @return the security metadata (or null if no metadata applies)
+ */
+ protected abstract ConfigAttributeDefinition findAttributes(Method method, Class targetClass);
+
+ /**
+ * Obtains the security metadata registered against the specified class.
+ *
+ * null
)
+ * @return the security metadata (or null if no metadata applies)
+ */
+ protected abstract ConfigAttributeDefinition findAttributes(Class clazz);
+
+ private static class DefaultCacheKey {
+
+ private final Method method;
+ private final Class targetClass;
+
+ public DefaultCacheKey(Method method, Class targetClass) {
+ this.method = method;
+ this.targetClass = targetClass;
+ }
+
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof DefaultCacheKey)) {
+ return false;
+ }
+ DefaultCacheKey otherKey = (DefaultCacheKey) other;
+ return (this.method.equals(otherKey.method) &&
+ ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
+ }
+
+ public int hashCode() {
+ return this.method.hashCode() * 21 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
+ }
+
+ public String toString() {
+ return "CacheKey[" + (targetClass == null ? "-" : targetClass.getName()) + "; " + method + "]";
+ }
+}
+
+}
diff --git a/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionMap.java b/core/src/main/java/org/springframework/security/intercept/method/MapBasedMethodDefinitionSource.java
similarity index 54%
rename from core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionMap.java
rename to core/src/main/java/org/springframework/security/intercept/method/MapBasedMethodDefinitionSource.java
index 2ae835843d..d9bda9ff7f 100644
--- a/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionMap.java
+++ b/core/src/main/java/org/springframework/security/intercept/method/MapBasedMethodDefinitionSource.java
@@ -15,63 +15,59 @@
package org.springframework.security.intercept.method;
-import org.springframework.security.ConfigAttributeDefinition;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
import java.lang.reflect.Method;
-
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Collection;
-import java.util.Collections;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
/**
- * Stores a {@link ConfigAttributeDefinition} for each method signature defined in a bean context.MethodDefinitionSourceAdvisor
, this implementation will return a
- * ConfigAttributeDefinition
containing all configuration attributes defined against:
- *
- *
- * com.company.Foo.findAll=ROLE_TEST
but not
- * com.company.FooImpl.findAll=ROLE_TEST
.*
- * for matching multiple methods.
+ * Add configuration attributes for a secure method.
*
* @param method the method to be secured
* @param attr required authorities associated with the method
*/
- public void addSecureMethod(Method method, ConfigAttributeDefinition attr) {
- logger.info("Adding secure method [" + method + "] with attributes [" + attr + "]");
+ private void addSecureMethod(RegisteredMethod method, ConfigAttributeDefinition attr) {
+ Assert.notNull(method, "RegisteredMethod required");
+ Assert.notNull(attr, "Configuration attribute required");
+ if (logger.isInfoEnabled()) {
+ logger.info("Adding secure method [" + method + "] with attributes [" + attr + "]");
+ }
this.methodMap.put(method, attr);
}
@@ -96,47 +121,41 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
* Add configuration attributes for a secure method. Method names can end or start with *
* for matching multiple methods.
*
- * @param name class and method name, separated by a dot
+ * @param name type and method name, separated by a dot
* @param attr required authorities associated with the method
- *
- * @throws IllegalArgumentException DOCUMENT ME!
*/
public void addSecureMethod(String name, ConfigAttributeDefinition attr) {
- int lastDotIndex = name.lastIndexOf(".");
+ int lastDotIndex = name.lastIndexOf(".");
if (lastDotIndex == -1) {
throw new IllegalArgumentException("'" + name + "' is not a valid method name: format is FQN.methodName");
}
- String className = name.substring(0, lastDotIndex);
String methodName = name.substring(lastDotIndex + 1);
-
- try {
- Class clazz = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
- addSecureMethod(clazz, methodName, attr);
- } catch (ClassNotFoundException ex) {
- throw new IllegalArgumentException("Class '" + className + "' not found");
- }
+ Assert.hasText(methodName, "Method not found for '" + name + "'");
+
+ String typeName = name.substring(0, lastDotIndex);
+ Class type = ClassUtils.resolveClassName(typeName, this.beanClassLoader);
+
+ addSecureMethod(type, methodName, attr);
}
/**
- * Add configuration attributes for a secure method. Method names can end or start with *
+ * Add configuration attributes for a secure method. Mapped method names can end or start with *
* for matching multiple methods.
- *
- * @param clazz target interface or class
- * @param mappedName mapped method name
+ *
+ * @param javaType target interface or class the security configuration attribute applies to
+ * @param mappedName mapped method name, which the javaType has declared or inherited
* @param attr required authorities associated with the method
- *
- * @throws IllegalArgumentException DOCUMENT ME!
*/
- public void addSecureMethod(Class clazz, String mappedName, ConfigAttributeDefinition attr) {
- String name = clazz.getName() + '.' + mappedName;
+ public void addSecureMethod(Class javaType, String mappedName, ConfigAttributeDefinition attr) {
+ String name = javaType.getName() + '.' + mappedName;
if (logger.isDebugEnabled()) {
- logger.debug("Adding secure method [" + name + "] with attributes [" + attr + "]");
+ logger.debug("Request to add secure method [" + name + "] with attributes [" + attr + "]");
}
- Method[] methods = clazz.getDeclaredMethods();
+ Method[] methods = javaType.getMethods();
List matchingMethods = new ArrayList();
for (int i = 0; i < methods.length; i++) {
@@ -146,13 +165,14 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
}
if (matchingMethods.isEmpty()) {
- throw new IllegalArgumentException("Couldn't find method '" + mappedName + "' on " + clazz);
+ throw new IllegalArgumentException("Couldn't find method '" + mappedName + "' on '" + javaType + "'");
}
// register all matching methods
for (Iterator it = matchingMethods.iterator(); it.hasNext();) {
Method method = (Method) it.next();
- String regMethodName = (String) this.nameMap.get(method);
+ RegisteredMethod registeredMethod = new RegisteredMethod(method, javaType);
+ String regMethodName = (String) this.nameMap.get(registeredMethod);
if ((regMethodName == null) || (!regMethodName.equals(name) && (regMethodName.length() <= name.length()))) {
// no already registered method name, or more specific
@@ -162,8 +182,8 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
+ "] is more specific than [" + regMethodName + "]");
}
- this.nameMap.put(method, name);
- addSecureMethod(method, attr);
+ this.nameMap.put(registeredMethod, name);
+ addSecureMethod(registeredMethod, attr);
} else {
logger.debug("Keeping attributes for secure method [" + method + "]: current name [" + name
+ "] is not more specific than [" + regMethodName + "]");
@@ -172,9 +192,7 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
}
/**
- * Obtains the configuration attributes explicitly defined against this bean. This method will not return
- * implicit configuration attributes that may be returned by {@link #lookupAttributes(Method)} as it does not have
- * access to a method invocation at this time.
+ * Obtains the configuration attributes explicitly defined against this bean.
*
* @return the attributes explicitly defined against this bean
*/
@@ -182,17 +200,6 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
return Collections.unmodifiableCollection(methodMap.values());
}
- /**
- * Obtains the number of configuration attributes explicitly defined against this bean. This method will
- * not return implicit configuration attributes that may be returned by {@link #lookupAttributes(Method)} as it
- * does not have access to a method invocation at this time.
- *
- * @return the number of configuration attributes explicitly defined against this bean
- */
- public int getMethodMapSize() {
- return this.methodMap.size();
- }
-
/**
* Return if the given method name matches the mapped name. The default implementation checks for "xxx" and
* "xxx" matches.
@@ -245,4 +252,55 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
attributes.addAll(toMerge.getConfigAttributes());
}
+
+ public void setBeanClassLoader(ClassLoader beanClassLoader) {
+ Assert.notNull(beanClassLoader, "Bean class loader required");
+ this.beanClassLoader = beanClassLoader;
+ }
+
+ /**
+ * @return map size (for unit tests and diagnostics)
+ */
+ public int getMethodMapSize() {
+ return methodMap.size();
+ }
+
+ /**
+ * Stores both the Java Method as well as the Class we obtained the Method from. This is necessary because Method only
+ * provides us access to the declaring class. It doesn't provide a way for us to introspect which Class the Method
+ * was registered against. If a given Class inherits and redeclares a method (ie calls super();) the registered Class
+ * and delcaring Class are the same. If a given class merely inherits but does not redeclare a method, the registered
+ * Class will be the Class we're invoking against and the Method will provide details of the declared class.
+ */
+ private class RegisteredMethod {
+ private Method method;
+ private Class registeredJavaType;
+
+ public RegisteredMethod(Method method, Class registeredJavaType) {
+ Assert.notNull(method, "Method required");
+ Assert.notNull(registeredJavaType, "Registered Java Type required");
+ this.method = method;
+ this.registeredJavaType = registeredJavaType;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj != null && obj instanceof RegisteredMethod) {
+ RegisteredMethod rhs = (RegisteredMethod) obj;
+ return method.equals(rhs.method) && registeredJavaType.equals(rhs.registeredJavaType);
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ return method.hashCode() * registeredJavaType.hashCode();
+ }
+
+ public String toString() {
+ return "RegisteredMethod[" + registeredJavaType.getName() + "; " + method + "]";
+ }
+ }
+
}
diff --git a/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionAttributes.java b/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionAttributes.java
index a01dcc6926..cddfae5298 100644
--- a/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionAttributes.java
+++ b/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionAttributes.java
@@ -15,122 +15,57 @@
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.metadata.Attributes;
-
-import java.lang.reflect.Method;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ArrayList;
+import org.springframework.util.Assert;
/**
* Provides {@link ConfigAttributeDefinition}s for a method signature (via the lookupAttributes method)
- * by delegating to a configured {@link Attributes} object. The latter may use Java 5 annotations, Commons attributes
+ * by delegating to a configured {@link Attributes} object. The latter may use Commons attributes
* or some other approach to determine the ConfigAttributes which apply.
- *
- *
+ *
* ObjectDefinitionSource
implementations
+ * Interface for ObjectDefinitionSource
implementations
* that are designed to perform lookups keyed on Method
s.
*
* @author Ben Alex
* @version $Id$
*/
-public interface MethodDefinitionSource extends ObjectDefinitionSource {}
+public interface MethodDefinitionSource extends ObjectDefinitionSource {
+ public ConfigAttributeDefinition getAttributes(Method method, Class targetClass);
+}
diff --git a/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionSourceEditor.java b/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionSourceEditor.java
index 2c52a357bd..296d99b97c 100644
--- a/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionSourceEditor.java
+++ b/core/src/main/java/org/springframework/security/intercept/method/MethodDefinitionSourceEditor.java
@@ -33,7 +33,7 @@ import java.util.LinkedHashMap;
/**
* Property editor to assist with the setup of a {@link MethodDefinitionSource}.
- * MethodInvocation
s usable within Spring Security.
@@ -76,8 +76,25 @@ public final class MethodInvocationUtils {
classArgs = (Class[]) list.toArray(new Class[] {});
}
+
+ // Determine the type that declares the requested method, taking into account proxies
+ Class target = AopUtils.getTargetClass(object);
+ if (object instanceof Advised) {
+ Advised a = (Advised) object;
+ if (!a.isProxyTargetClass()) {
+ Class[] possibleInterfaces = a.getProxiedInterfaces();
+ for (int i = 0; i < possibleInterfaces.length; i++) {
+ try {
+ possibleInterfaces[i].getMethod(methodName, classArgs);
+ // to get here means no exception happened
+ target = possibleInterfaces[i];
+ break;
+ } catch (Exception tryTheNextOne) {}
+ }
+ }
+ }
- return createFromClass(object.getClass(), methodName, classArgs, args);
+ return createFromClass(object, target, methodName, classArgs, args);
}
/**
@@ -89,21 +106,22 @@ public final class MethodInvocationUtils {
* @return a MethodInvocation
, or null
if there was a problem
*/
public static MethodInvocation createFromClass(Class clazz, String methodName) {
- return createFromClass(clazz, methodName, null, null);
+ return createFromClass(null, clazz, methodName, null, null);
}
/**
* Generates a MethodInvocation
for specified methodName
on the passed class,
* using the args
to locate the method.
*
+ * @param targetObject the object being invoked
* @param clazz the class of object that will be used to find the relevant Method
* @param methodName the name of the method to find
* @param classArgs arguments that are required to locate the relevant method signature
* @param args the actual arguments that should be passed to SimpleMethodInvocation
* @return a MethodInvocation
, or null
if there was a problem
*/
- public static MethodInvocation createFromClass(Class clazz, String methodName, Class[] classArgs, Object[] args) {
- Assert.notNull(clazz, "Class required");
+ public static MethodInvocation createFromClass(Object targetObject, Class clazz, String methodName, Class[] classArgs, Object[] args) {
+ Assert.notNull(clazz, "Class required");
Assert.hasText(methodName, "MethodName required");
Method method;
@@ -114,6 +132,6 @@ public final class MethodInvocationUtils {
return null;
}
- return new SimpleMethodInvocation(method, args);
+ return new SimpleMethodInvocation(targetObject, method, args);
}
}
diff --git a/core/src/main/java/org/springframework/security/util/SimpleMethodInvocation.java b/core/src/main/java/org/springframework/security/util/SimpleMethodInvocation.java
index 9e31767fc9..234e270317 100644
--- a/core/src/main/java/org/springframework/security/util/SimpleMethodInvocation.java
+++ b/core/src/main/java/org/springframework/security/util/SimpleMethodInvocation.java
@@ -32,11 +32,13 @@ public class SimpleMethodInvocation implements MethodInvocation {
private Method method;
private Object[] arguments;
+ private Object targetObject;
//~ Constructors ===================================================================================================
- public SimpleMethodInvocation(Method method, Object[] arguments) {
- this.method = method;
+ public SimpleMethodInvocation(Object targetObject, Method method, Object[] arguments) {
+ this.targetObject = targetObject;
+ this.method = method;
this.arguments = arguments;
}
@@ -57,7 +59,7 @@ public class SimpleMethodInvocation implements MethodInvocation {
}
public Object getThis() {
- throw new UnsupportedOperationException("mock method not implemented");
+ return targetObject;
}
public Object proceed() throws Throwable {
diff --git a/core/src/test/java/org/springframework/security/MockJoinPoint.java b/core/src/test/java/org/springframework/security/MockJoinPoint.java
index e21cad6263..2b587ee171 100644
--- a/core/src/test/java/org/springframework/security/MockJoinPoint.java
+++ b/core/src/test/java/org/springframework/security/MockJoinPoint.java
@@ -34,12 +34,14 @@ public class MockJoinPoint implements JoinPoint {
private Method beingInvoked;
private Object object;
+ private Class declaringType;
//~ Constructors ===================================================================================================
public MockJoinPoint(Object object, Method beingInvoked) {
this.object = object;
this.beingInvoked = beingInvoked;
+ this.declaringType = object.getClass();
}
//~ Methods ========================================================================================================
@@ -61,7 +63,7 @@ public class MockJoinPoint implements JoinPoint {
}
public StaticPart getStaticPart() {
- return new MockStaticPart(beingInvoked);
+ return new MockStaticPart(beingInvoked, declaringType);
}
public Object getTarget() {
@@ -84,13 +86,15 @@ public class MockJoinPoint implements JoinPoint {
private class MockCodeSignature implements CodeSignature {
private Method beingInvoked;
+ private Class declaringType;
- public MockCodeSignature(Method beingInvoked) {
+ public MockCodeSignature(Method beingInvoked, Class declaringType) {
this.beingInvoked = beingInvoked;
+ this.declaringType = declaringType;
}
public Class getDeclaringType() {
- throw new UnsupportedOperationException("mock not implemented");
+ return this.declaringType;
}
public String getDeclaringTypeName() {
@@ -128,9 +132,11 @@ public class MockJoinPoint implements JoinPoint {
private class MockStaticPart implements StaticPart {
private Method beingInvoked;
-
- public MockStaticPart(Method beingInvoked) {
+ private Class declaringType;
+
+ public MockStaticPart(Method beingInvoked, Class declaringType) {
this.beingInvoked = beingInvoked;
+ this.declaringType = declaringType;
}
public String getKind() {
@@ -138,7 +144,7 @@ public class MockJoinPoint implements JoinPoint {
}
public Signature getSignature() {
- return new MockCodeSignature(beingInvoked);
+ return new MockCodeSignature(beingInvoked, declaringType);
}
public SourceLocation getSourceLocation() {
diff --git a/core/src/test/java/org/springframework/security/OtherTargetObject.java b/core/src/test/java/org/springframework/security/OtherTargetObject.java
index c003698fe4..5d57ca56f7 100644
--- a/core/src/test/java/org/springframework/security/OtherTargetObject.java
+++ b/core/src/test/java/org/springframework/security/OtherTargetObject.java
@@ -29,10 +29,6 @@ package org.springframework.security;
public class OtherTargetObject extends TargetObject implements ITargetObject {
//~ Methods ========================================================================================================
- public int countLength(String input) {
- return super.countLength(input);
- }
-
public String makeLowerCase(String input) {
return super.makeLowerCase(input);
}
diff --git a/core/src/test/java/org/springframework/security/context/rmi/ContextPropagatingRemoteInvocationTests.java b/core/src/test/java/org/springframework/security/context/rmi/ContextPropagatingRemoteInvocationTests.java
index 4cf8f4e2a8..47c9821575 100644
--- a/core/src/test/java/org/springframework/security/context/rmi/ContextPropagatingRemoteInvocationTests.java
+++ b/core/src/test/java/org/springframework/security/context/rmi/ContextPropagatingRemoteInvocationTests.java
@@ -59,7 +59,7 @@ public class ContextPropagatingRemoteInvocationTests extends TestCase {
throws Exception {
Class clazz = TargetObject.class;
Method method = clazz.getMethod("makeLowerCase", new Class[] {String.class});
- MethodInvocation mi = new SimpleMethodInvocation(method, new Object[] {"SOME_STRING"});
+ MethodInvocation mi = new SimpleMethodInvocation(new TargetObject(), method, new Object[] {"SOME_STRING"});
ContextPropagatingRemoteInvocationFactory factory = new ContextPropagatingRemoteInvocationFactory();
diff --git a/core/src/test/java/org/springframework/security/intercept/method/MethodDefinitionAttributesTests.java b/core/src/test/java/org/springframework/security/intercept/method/MethodDefinitionAttributesTests.java
index fabc913315..e693c20ebd 100644
--- a/core/src/test/java/org/springframework/security/intercept/method/MethodDefinitionAttributesTests.java
+++ b/core/src/test/java/org/springframework/security/intercept/method/MethodDefinitionAttributesTests.java
@@ -15,33 +15,13 @@
package org.springframework.security.intercept.method;
-import junit.framework.TestCase;
-
-import org.springframework.security.ConfigAttribute;
-import org.springframework.security.ConfigAttributeDefinition;
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.GrantedAuthorityImpl;
-import org.springframework.security.ITargetObject;
-import org.springframework.security.OtherTargetObject;
-import org.springframework.security.SecurityConfig;
-import org.springframework.security.TargetObject;
-
-import org.springframework.security.acl.basic.SomeDomain;
-
-import org.springframework.security.context.SecurityContextHolder;
-
-import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
-
-import org.springframework.security.util.SimpleMethodInvocation;
-
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
import java.lang.reflect.Method;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.security.ITargetObject;
/**
@@ -51,180 +31,27 @@ import java.util.Set;
* @author Ben Alex
* @version $Id$
*/
-public class MethodDefinitionAttributesTests extends TestCase {
- //~ Instance fields ================================================================================================
+public class MethodDefinitionAttributesTests {
- ClassPathXmlApplicationContext applicationContext;
-
- //~ Constructors ===================================================================================================
-
- public MethodDefinitionAttributesTests(String a) {
- super(a);
+ 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());
}
- //~ Methods ========================================================================================================
-
-
- protected void tearDown() throws Exception {
- super.tearDown();
- SecurityContextHolder.clearContext();
+ @Test
+ public void testClassesReturned() throws Exception {
+ Class clazz = ITargetObject.class;
+ ConfigAttributeDefinition result = build().findAttributes(ITargetObject.class);
+ Assert.assertEquals(1, result.getConfigAttributes().size());
}
- private ConfigAttributeDefinition getConfigAttributeDefinition(Class clazz, String methodName, Class[] args)
- throws Exception {
-
- final Method method = clazz.getMethod(methodName, args);
- MethodDefinitionAttributes source = new MethodDefinitionAttributes();
- source.setAttributes(new MockAttributes());
-
- ConfigAttributeDefinition config = source.getAttributes(new SimpleMethodInvocation() {
- public Method getMethod() {
- return method;
- }
- });
-
- return config;
- }
-
- private ITargetObject makeInterceptedTarget() {
- ApplicationContext context = new ClassPathXmlApplicationContext(
- "org/springframework/security/intercept/method/applicationContext.xml");
-
- return (ITargetObject) context.getBean("target");
- }
-
- public final void setUp() throws Exception {
- super.setUp();
- }
-
- public void testAttributesForInterfaceTargetObject() throws Exception {
- ConfigAttributeDefinition def1 = getConfigAttributeDefinition(ITargetObject.class, "countLength",
- new Class[] {String.class});
- Set set1 = toSet(def1);
- assertTrue(set1.contains(new SecurityConfig("MOCK_INTERFACE")));
- assertTrue(set1.contains(new SecurityConfig("MOCK_INTERFACE_METHOD_COUNT_LENGTH")));
-
- ConfigAttributeDefinition def2 = getConfigAttributeDefinition(ITargetObject.class, "makeLowerCase",
- new Class[] {String.class});
- Set set2 = toSet(def2);
- assertTrue(set2.contains(new SecurityConfig("MOCK_INTERFACE")));
- assertTrue(set2.contains(new SecurityConfig("MOCK_INTERFACE_METHOD_MAKE_LOWER_CASE")));
-
- ConfigAttributeDefinition def3 = getConfigAttributeDefinition(ITargetObject.class, "makeUpperCase",
- new Class[] {String.class});
- Set set3 = toSet(def3);
- assertTrue(set3.contains(new SecurityConfig("MOCK_INTERFACE")));
- assertTrue(set3.contains(new SecurityConfig("MOCK_INTERFACE_METHOD_MAKE_UPPER_CASE")));
- }
-
- public void testAttributesForOtherTargetObject() throws Exception {
- ConfigAttributeDefinition def1 = getConfigAttributeDefinition(OtherTargetObject.class, "countLength",
- new Class[] {String.class});
- Set set1 = toSet(def1);
- assertTrue(set1.contains(new SecurityConfig("MOCK_INTERFACE")));
- assertTrue(set1.contains(new SecurityConfig("MOCK_INTERFACE_METHOD_COUNT_LENGTH")));
-
- // Confirm MOCK_CLASS_METHOD_COUNT_LENGTH not added, as it's a String (not a ConfigAttribute)
- // Confirm also MOCK_CLASS not added, as we return null for class
- assertEquals(2, set1.size());
-
- ConfigAttributeDefinition def2 = getConfigAttributeDefinition(OtherTargetObject.class, "makeLowerCase",
- new Class[] {String.class});
- Set set2 = toSet(def2);
- assertTrue(set2.contains(new SecurityConfig("MOCK_INTERFACE")));
- assertTrue(set2.contains(new SecurityConfig("MOCK_INTERFACE_METHOD_MAKE_LOWER_CASE")));
- assertTrue(set2.contains(new SecurityConfig("MOCK_CLASS_METHOD_MAKE_LOWER_CASE")));
-
- // Confirm MOCK_CLASS not added, as we return null for class
- assertEquals(3, set2.size());
-
- ConfigAttributeDefinition def3 = getConfigAttributeDefinition(OtherTargetObject.class, "makeUpperCase",
- new Class[] {String.class});
- Set set3 = toSet(def3);
- assertTrue(set3.contains(new SecurityConfig("MOCK_INTERFACE")));
- assertTrue(set3.contains(new SecurityConfig("MOCK_INTERFACE_METHOD_MAKE_UPPER_CASE")));
- assertTrue(set3.contains(new SecurityConfig("RUN_AS"))); // defined against interface
-
- assertEquals(3, set3.size());
- }
-
- public void testAttributesForTargetObject() throws Exception {
- ConfigAttributeDefinition def1 = getConfigAttributeDefinition(TargetObject.class, "countLength",
- new Class[] {String.class});
- Set set1 = toSet(def1);
- assertTrue(set1.contains(new SecurityConfig("MOCK_INTERFACE")));
- assertTrue(set1.contains(new SecurityConfig("MOCK_INTERFACE_METHOD_COUNT_LENGTH")));
-
- assertTrue(set1.contains(new SecurityConfig("MOCK_CLASS")));
-
- // Confirm the MOCK_CLASS_METHOD_COUNT_LENGTH was not added, as it's not a ConfigAttribute
- assertEquals(3, set1.size());
-
- ConfigAttributeDefinition def2 = getConfigAttributeDefinition(TargetObject.class, "makeLowerCase",
- new Class[] {String.class});
- Set set2 = toSet(def2);
- assertTrue(set2.contains(new SecurityConfig("MOCK_INTERFACE")));
- assertTrue(set2.contains(new SecurityConfig("MOCK_INTERFACE_METHOD_MAKE_LOWER_CASE")));
- assertTrue(set2.contains(new SecurityConfig("MOCK_CLASS")));
- assertTrue(set2.contains(new SecurityConfig("MOCK_CLASS_METHOD_MAKE_LOWER_CASE")));
- assertEquals(4, set2.size());
-
- ConfigAttributeDefinition def3 = getConfigAttributeDefinition(TargetObject.class, "makeUpperCase",
- new Class[] {String.class});
- Set set3 = toSet(def3);
- assertTrue(set3.contains(new SecurityConfig("MOCK_INTERFACE")));
- assertTrue(set3.contains(new SecurityConfig("MOCK_INTERFACE_METHOD_MAKE_UPPER_CASE")));
- assertTrue(set3.contains(new SecurityConfig("MOCK_CLASS")));
- assertTrue(set3.contains(new SecurityConfig("MOCK_CLASS_METHOD_MAKE_UPPER_CASE")));
- assertTrue(set3.contains(new SecurityConfig("RUN_AS")));
- assertEquals(5, set3.size());
- }
-
- public void testMethodCallWithRunAsReplacement() throws Exception {
- UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
- new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_INTERFACE_METHOD_MAKE_UPPER_CASE")});
- SecurityContextHolder.getContext().setAuthentication(token);
-
- ITargetObject target = makeInterceptedTarget();
- String result = target.makeUpperCase("hello");
- assertEquals("HELLO org.springframework.security.MockRunAsAuthenticationToken true", result);
- }
-
- public void testMethodCallWithoutRunAsReplacement() throws Exception {
- UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
- new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_INTERFACE_METHOD_MAKE_LOWER_CASE")});
- SecurityContextHolder.getContext().setAuthentication(token);
-
- ITargetObject target = makeInterceptedTarget();
- String result = target.makeLowerCase("HELLO");
-
- assertEquals("hello org.springframework.security.providers.UsernamePasswordAuthenticationToken true", result);
- }
-
- public void testNullReturnedIfZeroAttributesDefinedForMethodInvocation()
- throws Exception {
- // SomeDomain is not defined in the MockAttributes()
- // (which getConfigAttributeDefinition refers to)
- ConfigAttributeDefinition def = getConfigAttributeDefinition(SomeDomain.class, "getId", null);
- assertNull(def);
- }
-
- /**
- * convert a ConfigAttributeDefinition
into a set of ConfigAttribute
(s)
- *
- * @param def the ConfigAttributeDefinition
to cover
- *
- * @return a Set of ConfigAttributes
- */
- private Set toSet(ConfigAttributeDefinition def) {
- Set set = new HashSet();
- Iterator i = def.getConfigAttributes().iterator();
-
- while (i.hasNext()) {
- ConfigAttribute a = (ConfigAttribute) i.next();
- set.add(a);
- }
-
- return set;
- }
}
diff --git a/core/src/test/java/org/springframework/security/intercept/method/MethodDefinitionSourceEditorTests.java b/core/src/test/java/org/springframework/security/intercept/method/MethodDefinitionSourceEditorTests.java
index ca81a788ec..c29e125d9e 100644
--- a/core/src/test/java/org/springframework/security/intercept/method/MethodDefinitionSourceEditorTests.java
+++ b/core/src/test/java/org/springframework/security/intercept/method/MethodDefinitionSourceEditorTests.java
@@ -18,7 +18,9 @@ package org.springframework.security.intercept.method;
import junit.framework.TestCase;
import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.security.ITargetObject;
import org.springframework.security.MockJoinPoint;
+import org.springframework.security.OtherTargetObject;
import org.springframework.security.TargetObject;
import org.aopalliance.intercept.MethodInvocation;
@@ -30,7 +32,7 @@ import java.util.Iterator;
/**
- * Tests {@link MethodDefinitionSourceEditor} and its associated {@link MethodDefinitionMap}.
+ * Tests {@link MethodDefinitionSourceEditor} and its associated {@link MapBasedMethodDefinitionSource}.
*
* @author Ben Alex
* @version $Id$
@@ -55,7 +57,7 @@ public class MethodDefinitionSourceEditorTests extends TestCase {
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
editor.setAsText("org.springframework.security.TargetObject.countLength=ROLE_ONE,ROLE_TWO,RUN_AS_ENTRY");
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
Class clazz = TargetObject.class;
Method method = clazz.getMethod("countLength", new Class[] {String.class});
@@ -101,32 +103,41 @@ public class MethodDefinitionSourceEditorTests extends TestCase {
}
}
- public void testConcreteClassInvocationsAlsoReturnDefinitionsAgainstInterface()
- throws Exception {
+ public void testConcreteClassInvocationsAlsoReturnDefinitionsAgainstInterface() throws Exception {
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
editor.setAsText(
- "org.springframework.security.ITargetObject.makeLower*=ROLE_FROM_INTERFACE\r\norg.springframework.security.ITargetObject.makeUpper*=ROLE_FROM_INTERFACE\r\norg.springframework.security.TargetObject.makeUpper*=ROLE_FROM_IMPLEMENTATION");
+ "org.springframework.security.ITargetObject.computeHashCode*=ROLE_FROM_INTERFACE\r\n" +
+ "org.springframework.security.ITargetObject.makeLower*=ROLE_FROM_INTERFACE\r\n" +
+ "org.springframework.security.ITargetObject.makeUpper*=ROLE_FROM_INTERFACE\r\n" +
+ "org.springframework.security.TargetObject.computeHashCode*=ROLE_FROM_TO\r\n" +
+ "org.springframework.security.OtherTargetObject.computeHashCode*=ROLE_FROM_OTO\r\n" +
+ "org.springframework.security.OtherTargetObject.makeUpper*=ROLE_FROM_IMPLEMENTATION");
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
- assertEquals(3, map.getMethodMapSize());
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
+ assertEquals(6, map.getMethodMapSize());
- ConfigAttributeDefinition returnedMakeLower = map.getAttributes(new MockMethodInvocation(TargetObject.class,
- "makeLowerCase", new Class[] {String.class}));
+ ConfigAttributeDefinition returnedMakeLower = map.getAttributes(new MockMethodInvocation(ITargetObject.class, "makeLowerCase", new Class[] {String.class}, new OtherTargetObject()));
ConfigAttributeDefinition expectedMakeLower = new ConfigAttributeDefinition("ROLE_FROM_INTERFACE");
assertEquals(expectedMakeLower, returnedMakeLower);
- ConfigAttributeDefinition returnedMakeUpper = map.getAttributes(new MockMethodInvocation(TargetObject.class,
- "makeUpperCase", new Class[] {String.class}));
- ConfigAttributeDefinition expectedMakeUpper = new ConfigAttributeDefinition(
- new String[]{"ROLE_FROM_IMPLEMENTATION","ROLE_FROM_INTERFACE"});
+ ConfigAttributeDefinition returnedMakeUpper = map.getAttributes(new MockMethodInvocation(ITargetObject.class, "makeUpperCase", new Class[] {String.class}, new OtherTargetObject()));
+ ConfigAttributeDefinition expectedMakeUpper = new ConfigAttributeDefinition(new String[]{"ROLE_FROM_IMPLEMENTATION"});
assertEquals(expectedMakeUpper, returnedMakeUpper);
+
+ ConfigAttributeDefinition returnedComputeHashCode = map.getAttributes(new MockMethodInvocation(ITargetObject.class, "computeHashCode", new Class[] {String.class}, new OtherTargetObject()));
+ ConfigAttributeDefinition expectedComputeHashCode = new ConfigAttributeDefinition(new String[]{"ROLE_FROM_OTO"});
+ assertEquals(expectedComputeHashCode, returnedComputeHashCode);
+
+ returnedComputeHashCode = map.getAttributes(new MockMethodInvocation(ITargetObject.class, "computeHashCode", new Class[] {String.class}, new TargetObject()));
+ expectedComputeHashCode = new ConfigAttributeDefinition(new String[]{"ROLE_FROM_TO"});
+ assertEquals(expectedComputeHashCode, returnedComputeHashCode);
}
public void testEmptyStringReturnsEmptyMap() {
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
editor.setAsText("");
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
assertEquals(0, map.getMethodMapSize());
}
@@ -135,7 +146,7 @@ public class MethodDefinitionSourceEditorTests extends TestCase {
editor.setAsText(
"org.springframework.security.TargetObject.countLength=ROLE_ONE,ROLE_TWO,RUN_AS_ENTRY\r\norg.springframework.security.TargetObject.make*=ROLE_NINE,ROLE_SUPERVISOR");
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
Iterator iter = map.getConfigAttributeDefinitions().iterator();
int counter = 0;
@@ -152,7 +163,7 @@ public class MethodDefinitionSourceEditorTests extends TestCase {
editor.setAsText(
"org.springframework.security.TargetObject.countLength=ROLE_ONE,ROLE_TWO,RUN_AS_ENTRY\r\norg.springframework.security.TargetObject.make*=ROLE_NINE,ROLE_SUPERVISOR");
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
assertEquals(3, map.getMethodMapSize());
}
@@ -161,21 +172,21 @@ public class MethodDefinitionSourceEditorTests extends TestCase {
editor.setAsText(
"org.springframework.security.TargetObject.*=ROLE_GENERAL\r\norg.springframework.security.TargetObject.makeLower*=ROLE_LOWER\r\norg.springframework.security.TargetObject.make*=ROLE_MAKE\r\norg.springframework.security.TargetObject.makeUpper*=ROLE_UPPER");
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
- assertEquals(5, map.getMethodMapSize());
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
+ assertEquals(14, map.getMethodMapSize());
- ConfigAttributeDefinition returnedMakeLower = map.getAttributes(new MockMethodInvocation(TargetObject.class,
- "makeLowerCase", new Class[] {String.class}));
+ ConfigAttributeDefinition returnedMakeLower = map.getAttributes(new MockMethodInvocation(ITargetObject.class,
+ "makeLowerCase", new Class[] {String.class}, new TargetObject()));
ConfigAttributeDefinition expectedMakeLower = new ConfigAttributeDefinition("ROLE_LOWER");
assertEquals(expectedMakeLower, returnedMakeLower);
- ConfigAttributeDefinition returnedMakeUpper = map.getAttributes(new MockMethodInvocation(TargetObject.class,
- "makeUpperCase", new Class[] {String.class}));
+ ConfigAttributeDefinition returnedMakeUpper = map.getAttributes(new MockMethodInvocation(ITargetObject.class,
+ "makeUpperCase", new Class[] {String.class}, new TargetObject()));
ConfigAttributeDefinition expectedMakeUpper = new ConfigAttributeDefinition("ROLE_UPPER");
assertEquals(expectedMakeUpper, returnedMakeUpper);
- ConfigAttributeDefinition returnedCountLength = map.getAttributes(new MockMethodInvocation(TargetObject.class,
- "countLength", new Class[] {String.class}));
+ ConfigAttributeDefinition returnedCountLength = map.getAttributes(new MockMethodInvocation(ITargetObject.class,
+ "countLength", new Class[] {String.class}, new TargetObject()));
ConfigAttributeDefinition expectedCountLength = new ConfigAttributeDefinition("ROLE_GENERAL");
assertEquals(expectedCountLength, returnedCountLength);
}
@@ -184,10 +195,10 @@ public class MethodDefinitionSourceEditorTests extends TestCase {
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
editor.setAsText("org.springframework.security.TargetObject.countLength=ROLE_ONE,ROLE_TWO,RUN_AS_ENTRY");
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
ConfigAttributeDefinition configAttributeDefinition = map.getAttributes(new MockMethodInvocation(
- TargetObject.class, "makeLowerCase", new Class[] {String.class}));
+ ITargetObject.class, "makeLowerCase", new Class[] {String.class}, new TargetObject()));
assertNull(configAttributeDefinition);
}
@@ -195,7 +206,7 @@ public class MethodDefinitionSourceEditorTests extends TestCase {
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
editor.setAsText(null);
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
assertEquals(0, map.getMethodMapSize());
}
@@ -203,10 +214,10 @@ public class MethodDefinitionSourceEditorTests extends TestCase {
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
editor.setAsText("org.springframework.security.TargetObject.countLength=ROLE_ONE,ROLE_TWO,RUN_AS_ENTRY");
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
- ConfigAttributeDefinition returnedCountLength = map.getAttributes(new MockMethodInvocation(TargetObject.class,
- "countLength", new Class[] {String.class}));
+ ConfigAttributeDefinition returnedCountLength = map.getAttributes(new MockMethodInvocation(ITargetObject.class,
+ "countLength", new Class[] {String.class}, new TargetObject()));
ConfigAttributeDefinition expectedCountLength = new ConfigAttributeDefinition(
new String[] {"ROLE_ONE", "ROLE_TWO", "RUN_AS_ENTRY"});
assertEquals(expectedCountLength, returnedCountLength);
@@ -215,11 +226,13 @@ public class MethodDefinitionSourceEditorTests extends TestCase {
//~ Inner Classes ==================================================================================================
private class MockMethodInvocation implements MethodInvocation {
- Method method;
+ private Method method;
+ private Object targetObject;
- public MockMethodInvocation(Class clazz, String methodName, Class[] parameterTypes)
+ public MockMethodInvocation(Class clazz, String methodName, Class[] parameterTypes, Object targetObject)
throws NoSuchMethodException {
- method = clazz.getMethod(methodName, parameterTypes);
+ this.method = clazz.getMethod(methodName, parameterTypes);
+ this.targetObject = targetObject;
}
public Object[] getArguments() {
@@ -235,7 +248,7 @@ public class MethodDefinitionSourceEditorTests extends TestCase {
}
public Object getThis() {
- return null;
+ return targetObject;
}
public Object proceed() throws Throwable {
diff --git a/core/src/test/java/org/springframework/security/intercept/method/MethodInvocationPrivilegeEvaluatorTests.java b/core/src/test/java/org/springframework/security/intercept/method/MethodInvocationPrivilegeEvaluatorTests.java
index a9ee9fdd12..d7a3fafb75 100644
--- a/core/src/test/java/org/springframework/security/intercept/method/MethodInvocationPrivilegeEvaluatorTests.java
+++ b/core/src/test/java/org/springframework/security/intercept/method/MethodInvocationPrivilegeEvaluatorTests.java
@@ -20,6 +20,7 @@ import junit.framework.TestCase;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.ITargetObject;
+import org.springframework.security.OtherTargetObject;
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
@@ -88,7 +89,7 @@ public class MethodInvocationPrivilegeEvaluatorTests extends TestCase {
throws Exception {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_LOWER")});
- MethodInvocation mi = MethodInvocationUtils.createFromClass(ITargetObject.class, "makeLowerCase",
+ MethodInvocation mi = MethodInvocationUtils.createFromClass(new OtherTargetObject(), ITargetObject.class, "makeLowerCase",
new Class[] {String.class}, new Object[] {"Hello world"});
MethodSecurityInterceptor interceptor = makeSecurityInterceptor();
@@ -117,7 +118,7 @@ public class MethodInvocationPrivilegeEvaluatorTests extends TestCase {
throws Exception {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_NOT_HELD")});
- MethodInvocation mi = MethodInvocationUtils.createFromClass(ITargetObject.class, "makeLowerCase",
+ MethodInvocation mi = MethodInvocationUtils.createFromClass(new OtherTargetObject(), ITargetObject.class, "makeLowerCase",
new Class[] {String.class}, new Object[] {"helloWorld"});
MethodSecurityInterceptor interceptor = makeSecurityInterceptor();
diff --git a/core/src/test/java/org/springframework/security/intercept/method/MockMethodDefinitionSource.java b/core/src/test/java/org/springframework/security/intercept/method/MockMethodDefinitionSource.java
index 21491b8e0f..232dabc42a 100644
--- a/core/src/test/java/org/springframework/security/intercept/method/MockMethodDefinitionSource.java
+++ b/core/src/test/java/org/springframework/security/intercept/method/MockMethodDefinitionSource.java
@@ -71,4 +71,8 @@ public class MockMethodDefinitionSource extends AbstractMethodDefinitionSource {
protected ConfigAttributeDefinition lookupAttributes(Method method) {
throw new UnsupportedOperationException("mock method not implemented");
}
+
+ public ConfigAttributeDefinition getAttributes(Method method, Class targetClass) {
+ throw new UnsupportedOperationException("mock method not implemented");
+ }
}
diff --git a/core/src/test/java/org/springframework/security/intercept/method/aopalliance/MethodDefinitionSourceAdvisorTests.java b/core/src/test/java/org/springframework/security/intercept/method/aopalliance/MethodDefinitionSourceAdvisorTests.java
index 3170d79e84..335bc055d8 100644
--- a/core/src/test/java/org/springframework/security/intercept/method/aopalliance/MethodDefinitionSourceAdvisorTests.java
+++ b/core/src/test/java/org/springframework/security/intercept/method/aopalliance/MethodDefinitionSourceAdvisorTests.java
@@ -15,17 +15,14 @@
package org.springframework.security.intercept.method.aopalliance;
+import java.lang.reflect.Method;
+
import junit.framework.TestCase;
import org.springframework.security.TargetObject;
-
-import org.springframework.security.intercept.method.MethodDefinitionMap;
+import org.springframework.security.intercept.method.MapBasedMethodDefinitionSource;
import org.springframework.security.intercept.method.MethodDefinitionSourceEditor;
-import org.springframework.aop.framework.AopConfigException;
-
-import java.lang.reflect.Method;
-
/**
* Tests {@link MethodDefinitionSourceAdvisor}.
@@ -50,7 +47,7 @@ public class MethodDefinitionSourceAdvisorTests extends TestCase {
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
editor.setAsText("org.springframework.security.TargetObject.countLength=ROLE_NOT_USED");
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
MethodSecurityInterceptor msi = new MethodSecurityInterceptor();
msi.setObjectDefinitionSource(map);
@@ -90,7 +87,7 @@ public class MethodDefinitionSourceAdvisorTests extends TestCase {
try {
new MethodDefinitionSourceAdvisor(msi);
fail("Should have detected null ObjectDefinitionSource and thrown AopConfigException");
- } catch (AopConfigException expected) {
+ } catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
@@ -99,7 +96,7 @@ public class MethodDefinitionSourceAdvisorTests extends TestCase {
Class clazz = TargetObject.class;
Method method = clazz.getMethod("countLength", new Class[] {String.class});
- MethodDefinitionSourceAdvisor.InternalMethodInvocation imi = new MethodDefinitionSourceAdvisor(getInterceptor()).new InternalMethodInvocation(method);
+ MethodDefinitionSourceAdvisor.InternalMethodInvocation imi = new MethodDefinitionSourceAdvisor(getInterceptor()).new InternalMethodInvocation(method, clazz);
try {
imi.getArguments();
@@ -115,13 +112,6 @@ public class MethodDefinitionSourceAdvisorTests extends TestCase {
assertTrue(true);
}
- try {
- imi.getThis();
- fail("Should have thrown UnsupportedOperationException");
- } catch (UnsupportedOperationException expected) {
- assertTrue(true);
- }
-
try {
imi.proceed();
fail("Should have thrown UnsupportedOperationException");
diff --git a/core/src/test/java/org/springframework/security/intercept/method/aopalliance/MethodSecurityInterceptorTests.java b/core/src/test/java/org/springframework/security/intercept/method/aopalliance/MethodSecurityInterceptorTests.java
index 287596ee3a..638fca73a2 100644
--- a/core/src/test/java/org/springframework/security/intercept/method/aopalliance/MethodSecurityInterceptorTests.java
+++ b/core/src/test/java/org/springframework/security/intercept/method/aopalliance/MethodSecurityInterceptorTests.java
@@ -455,7 +455,11 @@ public class MethodSecurityInterceptorTests extends TestCase {
throw new UnsupportedOperationException("mock method not implemented");
}
- public boolean supports(Class clazz) {
+ public ConfigAttributeDefinition getAttributes(Method method, Class targetClass) {
+ throw new UnsupportedOperationException("mock method not implemented");
+ }
+
+ public boolean supports(Class clazz) {
if (String.class.isAssignableFrom(clazz)) {
return true;
} else {
diff --git a/core/src/test/java/org/springframework/security/intercept/method/aspectj/AspectJSecurityInterceptorTests.java b/core/src/test/java/org/springframework/security/intercept/method/aspectj/AspectJSecurityInterceptorTests.java
index ade24bed97..41c9318a26 100644
--- a/core/src/test/java/org/springframework/security/intercept/method/aspectj/AspectJSecurityInterceptorTests.java
+++ b/core/src/test/java/org/springframework/security/intercept/method/aspectj/AspectJSecurityInterceptorTests.java
@@ -15,27 +15,24 @@
package org.springframework.security.intercept.method.aspectj;
+import java.lang.reflect.Method;
+
import junit.framework.TestCase;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.MockAccessDecisionManager;
+import org.springframework.security.MockApplicationEventPublisher;
import org.springframework.security.MockAuthenticationManager;
import org.springframework.security.MockJoinPoint;
import org.springframework.security.MockRunAsManager;
import org.springframework.security.TargetObject;
-import org.springframework.security.MockApplicationEventPublisher;
-
import org.springframework.security.context.SecurityContextHolder;
-
-import org.springframework.security.intercept.method.MethodDefinitionMap;
+import org.springframework.security.intercept.method.MapBasedMethodDefinitionSource;
import org.springframework.security.intercept.method.MethodDefinitionSourceEditor;
-
import org.springframework.security.providers.TestingAuthenticationToken;
-import java.lang.reflect.Method;
-
/**
* Tests {@link AspectJSecurityInterceptor}.
@@ -74,7 +71,7 @@ public class AspectJSecurityInterceptorTests extends TestCase {
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
editor.setAsText("org.springframework.security.TargetObject.countLength=MOCK_ONE,MOCK_TWO");
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
si.setObjectDefinitionSource(map);
assertEquals(map, si.getObjectDefinitionSource());
@@ -105,7 +102,7 @@ public class AspectJSecurityInterceptorTests extends TestCase {
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
editor.setAsText("org.springframework.security.TargetObject.countLength=MOCK_ONE,MOCK_TWO");
- MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+ MapBasedMethodDefinitionSource map = (MapBasedMethodDefinitionSource) editor.getValue();
si.setObjectDefinitionSource(map);
si.afterPropertiesSet();
diff --git a/core/src/test/java/org/springframework/security/vote/BasicAclEntryVoterTests.java b/core/src/test/java/org/springframework/security/vote/BasicAclEntryVoterTests.java
index f726025de6..581234f63e 100644
--- a/core/src/test/java/org/springframework/security/vote/BasicAclEntryVoterTests.java
+++ b/core/src/test/java/org/springframework/security/vote/BasicAclEntryVoterTests.java
@@ -56,7 +56,7 @@ public class BasicAclEntryVoterTests extends TestCase {
Class clazz = SomeDomainObjectManager.class;
Method method = clazz.getMethod("someServiceMethod", new Class[] {SomeDomainObject.class});
- return new SimpleMethodInvocation(method, new Object[] {domainObject});
+ return new SimpleMethodInvocation(new SomeDomainObjectManager(), method, new Object[] {domainObject});
}
public static void main(String[] args) {
@@ -419,7 +419,7 @@ public class BasicAclEntryVoterTests extends TestCase {
Class clazz = String.class;
Method method = clazz.getMethod("toString", new Class[]{});
- MethodInvocation mi = new SimpleMethodInvocation(method, new Object[]{domainObject});
+ MethodInvocation mi = new SimpleMethodInvocation(new String(), method, new Object[]{domainObject});
try {
voter.vote(new UsernamePasswordAuthenticationToken("rod", null), mi, attr);
diff --git a/core/src/test/resources/org/springframework/security/config/method-security.xml b/core/src/test/resources/org/springframework/security/config/method-security.xml
index d34240fce4..5dfa743af2 100644
--- a/core/src/test/resources/org/springframework/security/config/method-security.xml
+++ b/core/src/test/resources/org/springframework/security/config/method-security.xml
@@ -11,8 +11,8 @@ http://www.springframework.org/schema/security http://www.springframework.org/sc