diff --git a/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java index 97a7d2f9d7..a6c4553a12 100644 --- a/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java @@ -41,6 +41,7 @@ import java.util.*; public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { private static final Log logger = LogFactory.getLog(HttpSecurityBeanDefinitionParser.class); + private static final String ATT_REQUEST_MATCHER_REF = "request-matcher-ref"; static final String ATT_PATH_PATTERN = "pattern"; static final String ATT_HTTP_METHOD = "method"; @@ -90,9 +91,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { boolean secured = !OPT_SECURITY_NONE.equals(element.getAttribute(ATT_SECURED)); if (!secured) { - if (!StringUtils.hasText(element.getAttribute(ATT_PATH_PATTERN))) { + if (!StringUtils.hasText(element.getAttribute(ATT_PATH_PATTERN)) && + !StringUtils.hasText(ATT_REQUEST_MATCHER_REF)) { pc.getReaderContext().error("The '" + ATT_SECURED + "' attribute must be used in combination with" + - " the '" + ATT_PATH_PATTERN +"' attribute.", pc.extractSource(element)); + " the '" + ATT_PATH_PATTERN +"' or '" + ATT_REQUEST_MATCHER_REF + "' attributes.", + pc.extractSource(element)); } for (int n=0; n < element.getChildNodes().getLength(); n ++) { @@ -139,10 +142,19 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { } private BeanReference createSecurityFilterChainBean(Element element, ParserContext pc, List filterChain) { - BeanDefinition filterChainMatcher; + BeanMetadataElement filterChainMatcher; + String requestMatcherRef = element.getAttribute(ATT_REQUEST_MATCHER_REF); String filterChainPattern = element.getAttribute(ATT_PATH_PATTERN); + + if (StringUtils.hasText(requestMatcherRef)) { if (StringUtils.hasText(filterChainPattern)) { + pc.getReaderContext().error("You can't define a pattern and a request-matcher-ref for the " + + "same filter chain", pc.extractSource(element)); + } + filterChainMatcher = new RuntimeBeanReference(requestMatcherRef); + + } else if (StringUtils.hasText(filterChainPattern)) { filterChainMatcher = MatcherType.fromElement(element).createMatcher(filterChainPattern, null); } else { filterChainMatcher = new RootBeanDefinition(AnyRequestMatcher.class); diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc index 2adbdb7366..de57a115f3 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc @@ -275,7 +275,9 @@ http.attlist &= http.attlist &= ## When set to 'none', requests matching the pattern attribute will be ignored by Spring Security. No security filters will be applied and no SecurityContext will be available. If set, the element must be empty, with no children. attribute security {"none"}? - +http.attlist &= + ## Allows a RequestMatcher instance to be used, as an alternative to pattern-matching. + attribute request-matcher-ref { xsd:token }? http.attlist &= ## Automatically registers a login form, BASIC authentication, anonymous authentication, logout services, remember-me and servlet-api-integration. If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). If unspecified, defaults to "false". attribute auto-config {xsd:boolean}? diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd index 446de2e8d0..298c1b7305 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd @@ -706,6 +706,11 @@ + + + Allows a RequestMatcher instance to be used, as an alternative to pattern-matching. + + Automatically registers a login form, BASIC authentication, anonymous authentication, logout services, remember-me and servlet-api-integration. If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). If unspecified, defaults to "false". diff --git a/config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy b/config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy index 40a1cd9df2..03bd9e013e 100644 --- a/config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy +++ b/config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy @@ -53,6 +53,7 @@ import org.springframework.security.access.vote.AffirmativeBased import org.springframework.security.access.PermissionEvaluator import org.springframework.security.core.Authentication import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler +import org.springframework.security.web.util.AntPathRequestMatcher class MiscHttpConfigTests extends AbstractHttpConfigTests { def 'Minimal configuration parses'() { @@ -138,6 +139,17 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests { filtersMatchExpectedAutoConfigList('/Im_caught_by_the_Universal_Match'); } + def requestMatcherRefWorksCorrectly() { + xml.http('request-matcher-ref': 'matcher', security: 'none') + bean('matcher', AntPathRequestMatcher.class.name, ['/nofilters']) + httpAutoConfig() {} + createAppContext() + + expect: + getFilters('/nofilters').size() == 0 + filtersMatchExpectedAutoConfigList('/somethingElse'); + } + // SEC-1152 def anonymousFilterIsAddedByDefault() { xml.http {