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:
Luke Taylor 2008-04-25 12:28:30 +00:00
parent 348d211b8c
commit d3a0f05de9
9 changed files with 177 additions and 11 deletions

View File

@ -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";
} }

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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";

View File

@ -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);
} }
} }

View File

@ -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;
}
}

View File

@ -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());
} }
} }

View File

@ -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);
}
}

View File

@ -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;
}
}