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 7c04988414..b2f614c2ec 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 @@ -37,6 +37,7 @@ import org.springframework.security.access.expression.method.ExpressionBasedPreI import org.springframework.security.access.intercept.AfterInvocationProviderManager; import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor; import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor; +import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor; import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource; import org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource; import org.springframework.security.access.prepost.PostInvocationAdviceProvider; @@ -76,6 +77,7 @@ 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_MODE = "mode"; private static final String ATT_ADVICE_ORDER = "order"; public BeanDefinition parse(Element element, ParserContext pc) { @@ -90,6 +92,8 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP boolean jsr250Enabled = "enabled".equals(element.getAttribute(ATT_USE_JSR250)); boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED)); boolean prePostAnnotationsEnabled = "enabled".equals(element.getAttribute(ATT_USE_PREPOST)); + boolean useAspectJ = "aspectj".equals(element.getAttribute(ATT_MODE)); + BeanDefinition preInvocationVoter = null; ManagedList afterInvocationProviders = new ManagedList(); @@ -165,6 +169,9 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP DomUtils.getChildElementsByTagName(element, PROTECT_POINTCUT)); if (pointcutMap.size() > 0) { + if (useAspectJ) { + pc.getReaderContext().error("You can't use AspectJ mode with protect-pointcut definitions", source); + } // Only add it if there are actually any pointcuts defined. BeanDefinition mapBasedMetadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class); BeanReference ref = new RuntimeBeanReference(pc.getReaderContext().generateBeanName(mapBasedMetadataSource)); @@ -190,13 +197,22 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP } String runAsManagerId = element.getAttribute(ATT_RUN_AS_MGR); - BeanReference interceptor = registerMethodSecurityInterceptor(pc, accessManagerId, runAsManagerId, - metadataSource, afterInvocationProviders, source); + metadataSource, afterInvocationProviders, source, useAspectJ); - registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER)); + if (useAspectJ) { + BeanDefinitionBuilder aspect = + BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect"); + aspect.setFactoryMethod("aspectOf"); + aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + aspect.addPropertyValue("securityInterceptor", interceptor); + String id = pc.getReaderContext().registerWithGeneratedName(aspect.getBeanDefinition()); + pc.registerBeanComponent(new BeanComponentDefinition(aspect.getBeanDefinition(), id)); + } else { + registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER)); + AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element); + } - AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element); pc.popAndRegisterContainingComponent(); return null; @@ -284,12 +300,16 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP } private BeanReference registerMethodSecurityInterceptor(ParserContext pc, String accessManagerId, - String runAsManagerId, BeanReference metadataSource, List afterInvocationProviders, Object source) { - BeanDefinitionBuilder bldr = BeanDefinitionBuilder.rootBeanDefinition(MethodSecurityInterceptor.class); + String runAsManagerId, BeanReference metadataSource, + List afterInvocationProviders, Object source, boolean useAspectJ) { + BeanDefinitionBuilder bldr = + BeanDefinitionBuilder.rootBeanDefinition(useAspectJ ? + AspectJMethodSecurityInterceptor.class : MethodSecurityInterceptor.class); bldr.getRawBeanDefinition().setSource(source); bldr.addPropertyReference("accessDecisionManager", accessManagerId); bldr.addPropertyValue("authenticationManager", new RootBeanDefinition(AuthenticationManagerDelegator.class)); bldr.addPropertyValue("securityMetadataSource", metadataSource); + if (StringUtils.hasText(runAsManagerId)) { bldr.addPropertyReference("runAsManager", runAsManagerId); } diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc index 111abd40eb..5c62b548e0 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc @@ -216,6 +216,9 @@ global-method-security.attlist &= attribute order {xsd:token}? global-method-security.attlist &= attribute proxy-target-class {boolean}? +global-method-security.attlist &= + ## Can be used to specify that AspectJ should be used instead of the default Spring AOP. If set, secured classes must be woven with the AnnotationSecurityAspect from the spring-security-aspects module. + attribute mode {"aspectj"}? 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.1.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd index f717a91731..7de02c414a 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd @@ -574,6 +574,16 @@ + + + Can be used to specify that AspectJ should be used instead of the default Spring AOP. If set, secured classes must be woven with the AnnotationSecurityAspect from the spring-security-aspects module. + + + + + + + diff --git a/samples/aspectj/aspectj.gradle b/samples/aspectj/aspectj.gradle new file mode 100644 index 0000000000..2f098dd31c --- /dev/null +++ b/samples/aspectj/aspectj.gradle @@ -0,0 +1,9 @@ + +dependencies { + compile project(':spring-security-core') + + aspectpath project(':spring-security-aspects') + + runtime project(':spring-security-config'), + project(':spring-security-aspects') +} \ No newline at end of file diff --git a/samples/aspectj/src/main/resources/aspectj-context.xml b/samples/aspectj/src/main/resources/aspectj-context.xml index ef48497453..000a95b3af 100644 --- a/samples/aspectj/src/main/resources/aspectj-context.xml +++ b/samples/aspectj/src/main/resources/aspectj-context.xml @@ -1,8 +1,12 @@ + xmlns:sec="http://www.springframework.org/schema/security" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> + + diff --git a/settings.gradle b/settings.gradle index 15bb91d095..2ee654a3f5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -13,7 +13,8 @@ def String[] modules = [ def String[] samples = [ 'tutorial', 'contacts', - 'openid' + 'openid', + 'aspectj' ] def String[] docs = [