diff --git a/config/src/main/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParser.java index ecc774ef23..c9d091c409 100644 --- a/config/src/main/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParser.java @@ -75,8 +75,9 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP private static final String ATT_USE_SECURED = "secured-annotations"; private static final String ATT_USE_PREPOST = "pre-post-annotations"; private static final String ATT_REF = "ref"; + private static final String ATT_ADVICE_ORDER = "order"; - @SuppressWarnings("unchecked") + // @SuppressWarnings("unchecked") public BeanDefinition parse(Element element, ParserContext pc) { CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element)); @@ -84,7 +85,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP Object source = pc.extractSource(element); // The list of method metadata delegates - ManagedList delegates = new ManagedList(); + ManagedList delegates = new ManagedList(); boolean jsr250Enabled = "enabled".equals(element.getAttribute(ATT_USE_JSR250)); boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED)); @@ -165,9 +166,12 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP if (pointcutMap.size() > 0) { // Only add it if there are actually any pointcuts defined. - MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource = new MapBasedMethodSecurityMetadataSource(); - delegates.add(mapBasedMethodSecurityMetadataSource); - registerProtectPointcutPostProcessor(pc, pointcutMap, mapBasedMethodSecurityMetadataSource, source); + BeanDefinition mapBasedMetadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class); + BeanReference ref = new RuntimeBeanReference(pc.getReaderContext().registerWithGeneratedName(mapBasedMetadataSource)); + + delegates.add(ref); + pc.registerBeanComponent(new BeanComponentDefinition(mapBasedMetadataSource, ref.getBeanName())); + registerProtectPointcutPostProcessor(pc, pointcutMap, ref, source); } BeanReference metadataSource = registerDelegatingMethodSecurityMetadataSource(pc, delegates, source); @@ -190,10 +194,11 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP BeanReference interceptor = registerMethodSecurityInterceptor(pc, accessManagerId, runAsManagerId, metadataSource, afterInvocationProviders, source); - registerAdvisor(pc, interceptor, metadataSource, source); + registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER)); AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element); pc.popAndRegisterContainingComponent(); + return null; } @@ -241,7 +246,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP private void registerProtectPointcutPostProcessor(ParserContext parserContext, Map> pointcutMap, - MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource, Object source) { + BeanReference mapBasedMethodSecurityMetadataSource, Object source) { RootBeanDefinition ppbp = new RootBeanDefinition(ProtectPointcutPostProcessor.class); ppbp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); ppbp.setSource(source); @@ -304,11 +309,16 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP return new RuntimeBeanReference(id); } - private void registerAdvisor(ParserContext parserContext, BeanReference interceptor, BeanReference metadataSource, Object source) { + private void registerAdvisor(ParserContext parserContext, BeanReference interceptor, BeanReference metadataSource, Object source, String adviceOrder) { if (parserContext.getRegistry().containsBeanDefinition(BeanIds.METHOD_SECURITY_METADATA_SOURCE_ADVISOR)) { parserContext.getReaderContext().error("Duplicate detected.", source); } RootBeanDefinition advisor = new RootBeanDefinition(MethodSecurityMetadataSourceAdvisor.class); + + if (StringUtils.hasText(adviceOrder)) { + advisor.getPropertyValues().addPropertyValue("order", adviceOrder); + } + // advisor must be an infrastructure bean as Spring's InfrastructureAdvisorAutoProxyCreator will ignore it // otherwise advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc index 92e8b611f9..2443d4d791 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc @@ -203,6 +203,9 @@ global-method-security.attlist &= global-method-security.attlist &= ## Optional RunAsmanager implementation which will be used by the configured MethodSecurityInterceptor attribute run-as-manager-ref {xsd:token}? +global-method-security.attlist &= + ## Allows the advice "order" to be set for the method security interceptor. + attribute order {xsd:token}? after-invocation-provider = ## Allows addition of extra AfterInvocationProvider beans which should be called by the MethodSecurityInterceptor created by global-method-security. diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd index 6ec44cbcbb..0f7a9bbea1 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd @@ -672,6 +672,12 @@ configured MethodSecurityInterceptor + + + Allows the advice "order" to be set for the method security + interceptor. + + 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 07784e3b04..cc4b205f05 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 @@ -8,6 +8,8 @@ import java.util.List; import org.junit.After; import org.junit.Test; +import org.springframework.aop.Advisor; +import org.springframework.aop.framework.Advised; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.context.ApplicationContext; @@ -46,7 +48,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests { public void loadContext() { setContext( "" + - "" + + "" + " " + " " + "" + ConfigTestUtils.AUTH_PROVIDER_XML @@ -67,6 +69,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests { @Test(expected=AuthenticationCredentialsNotFoundException.class) public void targetShouldPreventProtectedMethodInvocationWithNoContext() { loadContext(); + target.someUserMethod1(); } @@ -77,6 +80,11 @@ public class GlobalMethodSecurityBeanDefinitionParserTests { SecurityContextHolder.getContext().setAuthentication(token); target.someUserMethod1(); + + // SEC-1213. Check the order + Advisor[] advisors = ((Advised)target).getAdvisors(); + assertEquals(1, advisors.length); + assertEquals(1001, ((MethodSecurityMetadataSourceAdvisor)advisors[0]).getOrder()); } @Test(expected=AccessDeniedException.class)