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

This commit is contained in:
Luke Taylor 2011-04-04 19:49:36 +01:00
parent 3084ad878f
commit 8d99918798
5 changed files with 38 additions and 6 deletions

View File

@ -79,6 +79,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
private static final String ATT_REF = "ref"; private static final String ATT_REF = "ref";
private static final String ATT_MODE = "mode"; private static final String ATT_MODE = "mode";
private static final String ATT_ADVICE_ORDER = "order"; 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) { public BeanDefinition parse(Element element, ParserContext pc) {
CompositeComponentDefinition compositeDef = CompositeComponentDefinition compositeDef =
@ -97,6 +98,13 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
BeanDefinition preInvocationVoter = null; BeanDefinition preInvocationVoter = null;
ManagedList<BeanMetadataElement> afterInvocationProviders = new ManagedList<BeanMetadataElement>(); 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) { if (prePostAnnotationsEnabled) {
Element prePostElt = DomUtils.getChildElementByTagName(element, INVOCATION_HANDLING); Element prePostElt = DomUtils.getChildElementByTagName(element, INVOCATION_HANDLING);
Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, EXPRESSION_HANDLER); Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, EXPRESSION_HANDLER);

View File

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

View File

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

View File

@ -346,6 +346,28 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
assertSame(ram, FieldUtils.getFieldValue(msi.getAdvice(), "runAsManager")); 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) { private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context); appContext = new InMemoryXmlApplicationContext(context);
} }

View File

@ -16,19 +16,18 @@ package org.springframework.security.access.annotation;
import static org.junit.Assert.*; 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.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; 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} * Tests for {@link org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource}