diff --git a/config/src/test/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParserTests.java index 5b4c39c0d7..834838619c 100644 --- a/config/src/test/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParserTests.java @@ -24,6 +24,7 @@ import org.springframework.security.access.intercept.RunAsManagerImpl; import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor; import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor; import org.springframework.security.access.prepost.PostInvocationAdviceProvider; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter; import org.springframework.security.access.vote.AffirmativeBased; import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; @@ -43,6 +44,8 @@ import org.springframework.security.util.FieldUtils; * @author Luke Taylor */ public class GlobalMethodSecurityBeanDefinitionParserTests { + private final UsernamePasswordAuthenticationToken bob = new UsernamePasswordAuthenticationToken("bob","bobspassword"); + private AbstractXmlApplicationContext appContext; private BusinessService target; @@ -234,7 +237,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests { "" + "" + AUTH_PROVIDER_XML); - SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword")); + SecurityContextHolder.getContext().setAuthentication(bob); target = (BusinessService) appContext.getBean("target"); target.someAdminMethod(); } @@ -245,7 +248,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests { "" + "" + AUTH_PROVIDER_XML); - SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword")); + SecurityContextHolder.getContext().setAuthentication(bob); target = (BusinessService) appContext.getBean("target"); List arg = new ArrayList(); arg.add("joe"); @@ -264,7 +267,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests { "" + "" + AUTH_PROVIDER_XML); - SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword")); + SecurityContextHolder.getContext().setAuthentication(bob); target = (BusinessService) appContext.getBean("target"); Object[] arg = new String[] {"joe", "bob", "sam"}; Object[] result = target.methodReturningAnArray(arg); @@ -300,6 +303,19 @@ public class GlobalMethodSecurityBeanDefinitionParserTests { foo.foo(new SecurityConfig("A")); } + // SEC-1448 + @Test + @SuppressWarnings("unchecked") + public void genericsMethodArgumentNamesAreResolved() throws Exception { + setContext( + "" + + "" + AUTH_PROVIDER_XML + ); + SecurityContextHolder.getContext().setAuthentication(bob); + Foo foo = (Foo) appContext.getBean("target"); + foo.foo(new SecurityConfig("A")); + } + @Test public void runAsManagerIsSetCorrectly() throws Exception { StaticApplicationContext parent = new StaticApplicationContext(); @@ -328,6 +344,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests { } public static class ConcreteFoo implements Foo { + @PreAuthorize("#action.attribute == 'A'") public void foo(SecurityConfig action) { } } diff --git a/core/src/main/java/org/springframework/security/access/expression/method/MethodSecurityEvaluationContext.java b/core/src/main/java/org/springframework/security/access/expression/method/MethodSecurityEvaluationContext.java index f5fce6b14a..30cfab4be1 100644 --- a/core/src/main/java/org/springframework/security/access/expression/method/MethodSecurityEvaluationContext.java +++ b/core/src/main/java/org/springframework/security/access/expression/method/MethodSecurityEvaluationContext.java @@ -3,11 +3,13 @@ package org.springframework.security.access.expression.method; import java.lang.reflect.Method; import org.aopalliance.intercept.MethodInvocation; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.aop.support.AopUtils; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.security.core.Authentication; -import org.springframework.util.ClassUtils; /** * Internal security-specific EvaluationContext implementation which lazily adds the @@ -18,6 +20,8 @@ import org.springframework.util.ClassUtils; * @since 3.0 */ class MethodSecurityEvaluationContext extends StandardEvaluationContext { + private static Log logger = LogFactory.getLog(MethodSecurityEvaluationContext.class); + private ParameterNameDiscoverer parameterNameDiscoverer; private boolean argumentsAdded; private MethodInvocation mi; @@ -58,10 +62,21 @@ class MethodSecurityEvaluationContext extends StandardEvaluationContext { private void addArgumentsAsVariables() { Object[] args = mi.getArguments(); + + if (args.length == 0) { + return; + } + Object targetObject = mi.getThis(); - Method method = ClassUtils.getMostSpecificMethod(mi.getMethod(), targetObject.getClass()); + Method method = AopUtils.getMostSpecificMethod(mi.getMethod(), targetObject.getClass()); String[] paramNames = parameterNameDiscoverer.getParameterNames(method); + if (paramNames == null) { + logger.warn("Unable to resolve method parameter names for method: " + method + + ". Debug symbol information is required if you are using parameter names in expressions."); + return; + } + for(int i=0; i < args.length; i++) { super.setVariable(paramNames[i], args[i]); }