diff --git a/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java
index 6aa948b032..e9099e3ca3 100644
--- a/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java
+++ b/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java
@@ -94,6 +94,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
static final String ATT_USER_SERVICE_REF = "user-service-ref";
static final String ATT_ENTRY_POINT_REF = "entry-point-ref";
+
+ static final String ATT_ONCE_PER_REQUEST = "once-per-request";
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
@@ -156,6 +158,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
new RuntimeBeanReference(accessManagerId));
filterSecurityInterceptorBuilder.addPropertyValue("authenticationManager",
ConfigUtils.registerProviderManagerIfNecessary(parserContext));
+
+ if ("true".equals(element.getAttribute(ATT_ONCE_PER_REQUEST))) {
+ filterSecurityInterceptorBuilder.addPropertyValue("observeOncePerRequest", Boolean.TRUE);
+ }
// SEC-501 - should paths stored in request maps be converted to lower case
// true if Ant path and using lower case
diff --git a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc
index ba574adb9f..846d3514c1 100644
--- a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc
+++ b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc
@@ -214,6 +214,9 @@ http.attlist &=
http.attlist &=
## Allows a customized AuthenticationEntryPoint to be used.
attribute entry-point-ref {xsd:string}?
+http.attlist &=
+ ## Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "false"
+ attribute once-per-request {"true" | "false"}?
intercept-url =
diff --git a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd
index b2ad905700..457e1f1fe4 100644
--- a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd
+++ b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd
@@ -710,6 +710,18 @@
used.
+
+
+ Corresponds to the observeOncePerRequest property of
+ FilterSecurityInterceptor. Defaults to "false"
+
+
+
+
+
+
+
+
diff --git a/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java b/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java
index 99119f979c..63aae7bc47 100644
--- a/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java
+++ b/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java
@@ -189,6 +189,17 @@ public class HttpSecurityBeanDefinitionParserTests {
setContext("" + AUTH_PROVIDER_XML);
}
+ @Test
+ public void oncePerRequestAttributeIsSupported() {
+ setContext("" + AUTH_PROVIDER_XML);
+ FilterChainProxy filterChainProxy = getFilterChainProxy();
+ List filters = filterChainProxy.getFilters("/someurl");
+
+ FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) filters.get(filters.size() - 1);
+
+ assertTrue(fsi.isObserveOncePerRequest());
+ }
+
@Test
public void interceptUrlWithRequiresChannelAddsChannelFilterToStack() {
setContext(
@@ -196,7 +207,6 @@ public class HttpSecurityBeanDefinitionParserTests {
" " +
" " + AUTH_PROVIDER_XML);
FilterChainProxy filterChainProxy = getFilterChainProxy();
-
List filters = filterChainProxy.getFilters("/someurl");
assertEquals("Expected 12 filters in chain", 12, filters.size());