SEC-783: GlobalMethodSecurityBeanDefinitionParser should support AfterInvocationProviders
http://jira.springframework.org/browse/SEC-783. Added support for custom-after-invocation-provider
This commit is contained in:
parent
348d211b8c
commit
d3a0f05de9
|
@ -1,5 +1,7 @@
|
||||||
package org.springframework.security.config;
|
package org.springframework.security.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains all the default Bean IDs created by the namespace support in Spring Security 2.
|
* Contains all the default Bean IDs created by the namespace support in Spring Security 2.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -31,6 +33,7 @@ public abstract class BeanIds {
|
||||||
public static final String CONCURRENT_SESSION_CONTROLLER = "_concurrentSessionController";
|
public static final String CONCURRENT_SESSION_CONTROLLER = "_concurrentSessionController";
|
||||||
public static final String ACCESS_MANAGER = "_accessManager";
|
public static final String ACCESS_MANAGER = "_accessManager";
|
||||||
public static final String AUTHENTICATION_MANAGER = "_authenticationManager";
|
public static final String AUTHENTICATION_MANAGER = "_authenticationManager";
|
||||||
|
public static final String AFTER_INVOCATION_MANAGER = "_afterInvocationManager";
|
||||||
public static final String FORM_LOGIN_FILTER = "_formLoginFilter";
|
public static final String FORM_LOGIN_FILTER = "_formLoginFilter";
|
||||||
public static final String FORM_LOGIN_ENTRY_POINT = "_formLoginEntryPoint";
|
public static final String FORM_LOGIN_ENTRY_POINT = "_formLoginEntryPoint";
|
||||||
public static final String OPEN_ID_FILTER = "_openIDFilter";
|
public static final String OPEN_ID_FILTER = "_openIDFilter";
|
||||||
|
@ -50,6 +53,7 @@ public abstract class BeanIds {
|
||||||
public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
|
public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
|
||||||
public static final String SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter";
|
public static final String SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter";
|
||||||
public static final String METHOD_SECURITY_INTERCEPTOR = "_methodSecurityInterceptor";
|
public static final String METHOD_SECURITY_INTERCEPTOR = "_methodSecurityInterceptor";
|
||||||
|
public static final String METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR = "_methodSecurityInterceptorPostProcessor";
|
||||||
public static final String METHOD_DEFINITION_SOURCE_ADVISOR = "_methodDefinitionSourceAdvisor";
|
public static final String METHOD_DEFINITION_SOURCE_ADVISOR = "_methodDefinitionSourceAdvisor";
|
||||||
public static final String PROTECT_POINTCUT_POST_PROCESSOR = "_protectPointcutPostProcessor";
|
public static final String PROTECT_POINTCUT_POST_PROCESSOR = "_protectPointcutPostProcessor";
|
||||||
public static final String DELEGATING_METHOD_DEFINITION_SOURCE = "_delegatingMethodDefinitionSource";
|
public static final String DELEGATING_METHOD_DEFINITION_SOURCE = "_delegatingMethodDefinitionSource";
|
||||||
|
@ -62,4 +66,5 @@ public abstract class BeanIds {
|
||||||
public static final String X509_AUTH_PROVIDER = "_x509AuthenitcationProvider";
|
public static final String X509_AUTH_PROVIDER = "_x509AuthenitcationProvider";
|
||||||
public static final String PRE_AUTH_ENTRY_POINT = "_preAuthenticatedProcessingFilterEntryPoint";
|
public static final String PRE_AUTH_ENTRY_POINT = "_preAuthenticatedProcessingFilterEntryPoint";
|
||||||
public static final String REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR = "_rememberMeServicesInjectionBeanPostProcessor";
|
public static final String REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR = "_rememberMeServicesInjectionBeanPostProcessor";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
import org.springframework.beans.factory.support.ManagedList;
|
import org.springframework.beans.factory.support.ManagedList;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.beans.factory.xml.ParserContext;
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
|
import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
|
||||||
import org.springframework.security.providers.ProviderManager;
|
import org.springframework.security.providers.ProviderManager;
|
||||||
import org.springframework.security.userdetails.UserDetailsService;
|
import org.springframework.security.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.vote.AffirmativeBased;
|
import org.springframework.security.vote.AffirmativeBased;
|
||||||
|
@ -114,6 +115,23 @@ public abstract class ConfigUtils {
|
||||||
return (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
return (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ManagedList getRegisteredAfterInvocationProviders(ParserContext parserContext) {
|
||||||
|
BeanDefinition manager = registerAfterInvocationProviderManagerIfNecessary(parserContext);
|
||||||
|
return (ManagedList) manager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BeanDefinition registerAfterInvocationProviderManagerIfNecessary(ParserContext parserContext) {
|
||||||
|
if(parserContext.getRegistry().containsBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER)) {
|
||||||
|
return parserContext.getRegistry().getBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
BeanDefinition manager = new RootBeanDefinition(AfterInvocationProviderManager.class);
|
||||||
|
manager.getPropertyValues().addPropertyValue("providers", new ManagedList());
|
||||||
|
parserContext.getRegistry().registerBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER, manager);
|
||||||
|
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
private static void registerFilterChainPostProcessorIfNecessary(ParserContext pc) {
|
private static void registerFilterChainPostProcessorIfNecessary(ParserContext pc) {
|
||||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR)) {
|
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package org.springframework.security.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||||
|
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||||
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the decorated {@link org.springframework.security.afterinvocation.AfterInvocationProvider} to the
|
||||||
|
* AfterInvocationProviderManager's list.
|
||||||
|
*
|
||||||
|
* @author Luke Taylor
|
||||||
|
* @version $Id$
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
public class CustomAfterInvocationProviderBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||||
|
|
||||||
|
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||||
|
ConfigUtils.getRegisteredAfterInvocationProviders(parserContext).add(holder.getBeanDefinition());
|
||||||
|
|
||||||
|
return holder;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -36,6 +36,7 @@ abstract class Elements {
|
||||||
public static final String PORT_MAPPING = "port-mapping";
|
public static final String PORT_MAPPING = "port-mapping";
|
||||||
public static final String CUSTOM_FILTER = "custom-filter";
|
public static final String CUSTOM_FILTER = "custom-filter";
|
||||||
public static final String CUSTOM_AUTH_PROVIDER = "custom-authentication-provider";
|
public static final String CUSTOM_AUTH_PROVIDER = "custom-authentication-provider";
|
||||||
|
public static final String CUSTOM_AFTER_INVOCATION_PROVIDER = "custom-after-invocation-provider";
|
||||||
public static final String X509 = "x509";
|
public static final String X509 = "x509";
|
||||||
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
|
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
|
||||||
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
|
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
|
||||||
|
|
|
@ -168,6 +168,9 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
interceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
|
interceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
|
||||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR, interceptor);
|
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR, interceptor);
|
||||||
parserContext.registerComponent(new BeanComponentDefinition(interceptor, BeanIds.METHOD_SECURITY_INTERCEPTOR));
|
parserContext.registerComponent(new BeanComponentDefinition(interceptor, BeanIds.METHOD_SECURITY_INTERCEPTOR));
|
||||||
|
|
||||||
|
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR,
|
||||||
|
new RootBeanDefinition(MethodSecurityInterceptorPostProcessor.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerAdvisor(ParserContext parserContext, Object source) {
|
private void registerAdvisor(ParserContext parserContext, Object source) {
|
||||||
|
@ -179,5 +182,4 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
|
|
||||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor);
|
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package org.springframework.security.config;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
import org.springframework.security.AfterInvocationManager;
|
||||||
|
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BeanPostProcessor which sets the AfterInvocationManager on the default MethodSecurityInterceptor,
|
||||||
|
* if one has been configured.
|
||||||
|
*
|
||||||
|
* @author Luke Taylor
|
||||||
|
* @version $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MethodSecurityInterceptorPostProcessor implements BeanPostProcessor, BeanFactoryAware{
|
||||||
|
private Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
|
private BeanFactory beanFactory;
|
||||||
|
|
||||||
|
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
if(!beanName.equals(BeanIds.METHOD_SECURITY_INTERCEPTOR)) {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodSecurityInterceptor interceptor = (MethodSecurityInterceptor) bean;
|
||||||
|
|
||||||
|
if (beanFactory.containsBean(BeanIds.AFTER_INVOCATION_MANAGER)) {
|
||||||
|
logger.debug("Setting AfterInvocationManaer on MethodSecurityInterceptor");
|
||||||
|
interceptor.setAfterInvocationManager((AfterInvocationManager)
|
||||||
|
beanFactory.getBean(BeanIds.AFTER_INVOCATION_MANAGER));
|
||||||
|
}
|
||||||
|
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||||
|
this.beanFactory = beanFactory;
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,5 +30,6 @@ public class SecurityNamespaceHandler extends NamespaceHandlerSupport {
|
||||||
registerBeanDefinitionDecorator(Elements.FILTER_CHAIN_MAP, new FilterChainMapBeanDefinitionDecorator());
|
registerBeanDefinitionDecorator(Elements.FILTER_CHAIN_MAP, new FilterChainMapBeanDefinitionDecorator());
|
||||||
registerBeanDefinitionDecorator(Elements.CUSTOM_FILTER, new OrderedFilterBeanDefinitionDecorator());
|
registerBeanDefinitionDecorator(Elements.CUSTOM_FILTER, new OrderedFilterBeanDefinitionDecorator());
|
||||||
registerBeanDefinitionDecorator(Elements.CUSTOM_AUTH_PROVIDER, new CustomAuthenticationProviderBeanDefinitionDecorator());
|
registerBeanDefinitionDecorator(Elements.CUSTOM_AUTH_PROVIDER, new CustomAuthenticationProviderBeanDefinitionDecorator());
|
||||||
|
registerBeanDefinitionDecorator(Elements.CUSTOM_AFTER_INVOCATION_PROVIDER, new CustomAfterInvocationProviderBeanDefinitionDecorator());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package org.springframework.security.config;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||||
|
import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
|
||||||
|
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||||
|
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||||
|
|
||||||
|
public class CustomAfterInvocationProviderBeanDefinitionDecoratorTests {
|
||||||
|
private AbstractXmlApplicationContext appContext;
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void closeAppContext() {
|
||||||
|
if (appContext != null) {
|
||||||
|
appContext.close();
|
||||||
|
appContext = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customAuthenticationProviderIsAddedToInterceptor() {
|
||||||
|
setContext(
|
||||||
|
"<global-method-security />" +
|
||||||
|
"<b:bean id='aip' class='org.springframework.security.config.MockAfterInvocationProvider'>" +
|
||||||
|
" <custom-after-invocation-provider />" +
|
||||||
|
"</b:bean>" +
|
||||||
|
HttpSecurityBeanDefinitionParserTests.AUTH_PROVIDER_XML
|
||||||
|
);
|
||||||
|
|
||||||
|
MethodSecurityInterceptor msi = (MethodSecurityInterceptor) appContext.getBean(BeanIds.METHOD_SECURITY_INTERCEPTOR);
|
||||||
|
AfterInvocationProviderManager apm = (AfterInvocationProviderManager) msi.getAfterInvocationManager();
|
||||||
|
assertNotNull(apm);
|
||||||
|
assertEquals(1, apm.getProviders().size());
|
||||||
|
assertTrue(apm.getProviders().get(0) instanceof MockAfterInvocationProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setContext(String context) {
|
||||||
|
appContext = new InMemoryXmlApplicationContext(context);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package org.springframework.security.config;
|
||||||
|
|
||||||
|
import org.springframework.security.AccessDeniedException;
|
||||||
|
import org.springframework.security.Authentication;
|
||||||
|
import org.springframework.security.ConfigAttribute;
|
||||||
|
import org.springframework.security.ConfigAttributeDefinition;
|
||||||
|
import org.springframework.security.afterinvocation.AfterInvocationProvider;
|
||||||
|
|
||||||
|
public class MockAfterInvocationProvider implements AfterInvocationProvider {
|
||||||
|
|
||||||
|
public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config, Object returnedObject)
|
||||||
|
throws AccessDeniedException {
|
||||||
|
return returnedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supports(ConfigAttribute attribute) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supports(Class clazz) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue