Răsfoiți Sursa

SEC-1491: Add support for an external priority SecurityMetadataSource to be referenced from global-method-security.

Luke Taylor 14 ani în urmă
părinte
comite
8d99918798

+ 8 - 0
config/src/main/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParser.java

@@ -79,6 +79,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
     private static final String ATT_REF = "ref";
     private static final String ATT_MODE = "mode";
     private static final String ATT_ADVICE_ORDER = "order";
+    private static final String ATT_META_DATA_SOURCE_REF = "metadata-source-ref";
 
     public BeanDefinition parse(Element element, ParserContext pc) {
         CompositeComponentDefinition compositeDef =
@@ -97,6 +98,13 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
         BeanDefinition preInvocationVoter = null;
         ManagedList<BeanMetadataElement> afterInvocationProviders = new ManagedList<BeanMetadataElement>();
 
+        // Check for an external SecurityMetadataSource, which takes priority over other sources
+        String metaDataSourceId = element.getAttribute(ATT_META_DATA_SOURCE_REF);
+
+        if (StringUtils.hasText(metaDataSourceId)) {
+            delegates.add(new RuntimeBeanReference(metaDataSourceId));
+        }
+
         if (prePostAnnotationsEnabled) {
             Element prePostElt = DomUtils.getChildElementByTagName(element, INVOCATION_HANDLING);
             Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, EXPRESSION_HANDLER);

+ 2 - 0
config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc

@@ -226,6 +226,8 @@ global-method-security.attlist &=
 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"}?
+global-method-security.attlist &=
+    attribute metadata-source-ref {xsd:token}?
 
 after-invocation-provider =
     ## Allows addition of extra AfterInvocationProvider beans which should be called by the MethodSecurityInterceptor created by global-method-security.

+ 1 - 0
config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd

@@ -576,6 +576,7 @@
         </xs:restriction>
       </xs:simpleType>
     </xs:attribute>
+    <xs:attribute name="metadata-source-ref" type="xs:token"/>
   </xs:attributeGroup>
   
   

+ 22 - 0
config/src/test/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParserTests.java

@@ -346,6 +346,28 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
         assertSame(ram, FieldUtils.getFieldValue(msi.getAdvice(), "runAsManager"));
     }
 
+    @Test
+    @SuppressWarnings("unchecked")
+    public void supportsExternalMetadataSource() throws Exception {
+        setContext(
+                "<b:bean id='target' class='" + ConcreteFoo.class.getName()  + "'/>" +
+                "<method-security-metadata-source id='mds'>" +
+                "      <protect method='"+ Foo.class.getName() + ".foo' access='ROLE_ADMIN'/>" +
+                "</method-security-metadata-source>" +
+                "<global-method-security pre-post-annotations='enabled' metadata-source-ref='mds'/>" + AUTH_PROVIDER_XML
+        );
+        // External MDS should take precedence over PreAuthorize
+        SecurityContextHolder.getContext().setAuthentication(bob);
+        Foo foo = (Foo) appContext.getBean("target");
+        try {
+            foo.foo(new SecurityConfig("A"));
+            fail("Bob can't invoke admin methods");
+        } catch (AccessDeniedException expected) {
+        }
+        SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("admin", "password"));
+        foo.foo(new SecurityConfig("A"));
+    }
+
     private void setContext(String context) {
         appContext = new InMemoryXmlApplicationContext(context);
     }

+ 5 - 6
core/src/test/java/org/springframework/security/access/annotation/SecuredAnnotationSecurityMetadataDefinitionSourceTests.java

@@ -16,19 +16,18 @@ package org.springframework.security.access.annotation;
 
 import static org.junit.Assert.*;
 
+import org.junit.*;
+import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.access.SecurityConfig;
+import org.springframework.security.core.GrantedAuthority;
+
 import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.lang.reflect.Method;
 import java.util.*;
 
-import org.junit.*;
-import org.springframework.security.access.ConfigAttribute;
-import org.springframework.security.access.SecurityConfig;
-import org.springframework.security.core.GrantedAuthority;
-
 
 /**
  * Tests for {@link org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource}