diff --git a/core/src/main/java/org/springframework/security/config/BeanIds.java b/core/src/main/java/org/springframework/security/config/BeanIds.java index 295f3225f4..347589d8b3 100644 --- a/core/src/main/java/org/springframework/security/config/BeanIds.java +++ b/core/src/main/java/org/springframework/security/config/BeanIds.java @@ -1,5 +1,7 @@ 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. *
@@ -31,6 +33,7 @@ public abstract class BeanIds {
public static final String CONCURRENT_SESSION_CONTROLLER = "_concurrentSessionController";
public static final String ACCESS_MANAGER = "_accessManager";
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_ENTRY_POINT = "_formLoginEntryPoint";
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 SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter";
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 PROTECT_POINTCUT_POST_PROCESSOR = "_protectPointcutPostProcessor";
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 PRE_AUTH_ENTRY_POINT = "_preAuthenticatedProcessingFilterEntryPoint";
public static final String REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR = "_rememberMeServicesInjectionBeanPostProcessor";
+
}
diff --git a/core/src/main/java/org/springframework/security/config/ConfigUtils.java b/core/src/main/java/org/springframework/security/config/ConfigUtils.java
index 491c036d7d..4ed59e7880 100644
--- a/core/src/main/java/org/springframework/security/config/ConfigUtils.java
+++ b/core/src/main/java/org/springframework/security/config/ConfigUtils.java
@@ -13,6 +13,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
import org.springframework.security.providers.ProviderManager;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.vote.AffirmativeBased;
@@ -114,7 +115,24 @@ public abstract class ConfigUtils {
return (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
}
- private static void registerFilterChainPostProcessorIfNecessary(ParserContext pc) {
+ 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) {
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR)) {
return;
}
@@ -158,5 +176,5 @@ public abstract class ConfigUtils {
public void setFilters(List filters) {
this.filters = filters;
}
- }
+ }
}
diff --git a/core/src/main/java/org/springframework/security/config/CustomAfterInvocationProviderBeanDefinitionDecorator.java b/core/src/main/java/org/springframework/security/config/CustomAfterInvocationProviderBeanDefinitionDecorator.java
new file mode 100644
index 0000000000..ab522a0dd7
--- /dev/null
+++ b/core/src/main/java/org/springframework/security/config/CustomAfterInvocationProviderBeanDefinitionDecorator.java
@@ -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;
+ }
+
+}
diff --git a/core/src/main/java/org/springframework/security/config/Elements.java b/core/src/main/java/org/springframework/security/config/Elements.java
index 1c6dfad992..e7d1ba2834 100644
--- a/core/src/main/java/org/springframework/security/config/Elements.java
+++ b/core/src/main/java/org/springframework/security/config/Elements.java
@@ -36,6 +36,7 @@ abstract class Elements {
public static final String PORT_MAPPING = "port-mapping";
public static final String CUSTOM_FILTER = "custom-filter";
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 FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
diff --git a/core/src/main/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParser.java
index 0cc52d1f22..d7fd483d6f 100644
--- a/core/src/main/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParser.java
+++ b/core/src/main/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParser.java
@@ -47,7 +47,7 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
parserContext.getReaderContext().error("Cannot locate '" + className + "'", element);
}
}
-
+
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
// The list of method metadata delegates
@@ -142,22 +142,22 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
Element childElt = (Element) i.next();
String accessConfig = childElt.getAttribute(ATT_ACCESS);
String expression = childElt.getAttribute(ATT_EXPRESSION);
-
+
if (!StringUtils.hasText(accessConfig)) {
parserContext.getReaderContext().error("Access configuration required", parserContext.extractSource(childElt));
}
-
+
if (!StringUtils.hasText(expression)) {
parserContext.getReaderContext().error("Pointcut expression required", parserContext.extractSource(childElt));
}
-
+
ConfigAttributeDefinition def = new ConfigAttributeDefinition(StringUtils.commaDelimitedListToStringArray(accessConfig));
pointcutMap.put(expression, def);
}
return pointcutMap;
}
-
+
private void registerMethodSecurityInterceptor(ParserContext parserContext, String accessManagerId, Object source) {
RootBeanDefinition interceptor = new RootBeanDefinition(MethodSecurityInterceptor.class);
interceptor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
@@ -167,9 +167,12 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
interceptor.getPropertyValues().addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
interceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
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) {
RootBeanDefinition advisor = new RootBeanDefinition(MethodDefinitionSourceAdvisor.class);
advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
@@ -178,6 +181,5 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
advisor.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor);
- }
-
+ }
}
diff --git a/core/src/main/java/org/springframework/security/config/MethodSecurityInterceptorPostProcessor.java b/core/src/main/java/org/springframework/security/config/MethodSecurityInterceptorPostProcessor.java
new file mode 100644
index 0000000000..4485f2ab0f
--- /dev/null
+++ b/core/src/main/java/org/springframework/security/config/MethodSecurityInterceptorPostProcessor.java
@@ -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;
+ }
+}
diff --git a/core/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java b/core/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java
index a0137ad165..3f5339323d 100644
--- a/core/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java
+++ b/core/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java
@@ -30,5 +30,6 @@ public class SecurityNamespaceHandler extends NamespaceHandlerSupport {
registerBeanDefinitionDecorator(Elements.FILTER_CHAIN_MAP, new FilterChainMapBeanDefinitionDecorator());
registerBeanDefinitionDecorator(Elements.CUSTOM_FILTER, new OrderedFilterBeanDefinitionDecorator());
registerBeanDefinitionDecorator(Elements.CUSTOM_AUTH_PROVIDER, new CustomAuthenticationProviderBeanDefinitionDecorator());
+ registerBeanDefinitionDecorator(Elements.CUSTOM_AFTER_INVOCATION_PROVIDER, new CustomAfterInvocationProviderBeanDefinitionDecorator());
}
}
diff --git a/core/src/test/java/org/springframework/security/config/CustomAfterInvocationProviderBeanDefinitionDecoratorTests.java b/core/src/test/java/org/springframework/security/config/CustomAfterInvocationProviderBeanDefinitionDecoratorTests.java
new file mode 100644
index 0000000000..04bfc718c3
--- /dev/null
+++ b/core/src/test/java/org/springframework/security/config/CustomAfterInvocationProviderBeanDefinitionDecoratorTests.java
@@ -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(
+ "