From 33023565a88edbf2241219cd6b455d00b7fda66f Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Thu, 28 Feb 2008 19:29:33 +0000 Subject: [PATCH] SEC-640: Add namespace support for FilterInvocationDefinitionSource configuration http://jira.springframework.org/browse/SEC-640 --- .../security/config/Elements.java | 1 + ...nDefinitionSourceBeanDefinitionParser.java | 54 ++++++ .../HttpSecurityBeanDefinitionParser.java | 162 +++++++++++------- .../config/SecurityNamespaceHandler.java | 1 + ...faultFilterInvocationDefinitionSource.java | 19 +- ...ilterInvocationDefinitionSourceEditor.java | 2 +- .../security/intercept/web/RequestKey.java | 30 +++- .../security/util/UrlMatcher.java | 2 +- .../security/config/spring-security-2.0.rnc | 14 +- .../security/config/spring-security-2.0.xsd | 40 +++++ ...HttpSecurityBeanDefinitionParserTests.java | 2 +- ...FilterInvocationDefinitionSourceTests.java | 33 ++++ .../web/FilterSecurityInterceptorTests.java | 6 +- .../security/util/FilterChainProxyTests.java | 7 +- 14 files changed, 289 insertions(+), 84 deletions(-) create mode 100644 core/src/main/java/org/springframework/security/config/FilterInvocationDefinitionSourceBeanDefinitionParser.java 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 00b0e2e4ca..9b7ec7b5e6 100644 --- a/core/src/main/java/org/springframework/security/config/Elements.java +++ b/core/src/main/java/org/springframework/security/config/Elements.java @@ -34,4 +34,5 @@ abstract class Elements { public static final String CUSTOM_FILTER = "custom-filter"; public static final String CUSTOM_AUTH_RPOVIDER = "custom-authentication-provider"; public static final String X509 = "x509"; + public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source"; } diff --git a/core/src/main/java/org/springframework/security/config/FilterInvocationDefinitionSourceBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/FilterInvocationDefinitionSourceBeanDefinitionParser.java new file mode 100644 index 0000000000..f8cf00c7a7 --- /dev/null +++ b/core/src/main/java/org/springframework/security/config/FilterInvocationDefinitionSourceBeanDefinitionParser.java @@ -0,0 +1,54 @@ +package org.springframework.security.config; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.security.util.AntUrlPathMatcher; +import org.springframework.security.util.UrlMatcher; +import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; + +/** + * Allows for convenient creation of a {@link FilterInvocationDefinitionSource} bean for use with a FilterSecurityInterceptor. + * + * @author Luke Taylor + * @version $Id$ + */ +public class FilterInvocationDefinitionSourceBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { + + protected String getBeanClassName(Element element) { + return "org.springframework.security.intercept.web.DefaultFilterInvocationDefinitionSource"; + } + + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + List interceptUrls = DomUtils.getChildElementsByTagName(element, "intercept-url"); + + // Check for attributes that aren't allowed in this context + Iterator interceptUrlElts = interceptUrls.iterator(); + while(interceptUrlElts.hasNext()) { + Element elt = (Element) interceptUrlElts.next(); + if (StringUtils.hasLength(elt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_REQUIRES_CHANNEL))) { + parserContext.getReaderContext().error("The attribute '" + HttpSecurityBeanDefinitionParser.ATT_REQUIRES_CHANNEL + "' isn't allowed here.", elt); + } + + if (StringUtils.hasLength(elt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_FILTERS))) { + parserContext.getReaderContext().error("The attribute '" + HttpSecurityBeanDefinitionParser.ATT_FILTERS + "' isn't allowed here.", elt); + } + } + + UrlMatcher matcher = HttpSecurityBeanDefinitionParser.createUrlMatcher(element); + boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl(); + + LinkedHashMap requestMap = new LinkedHashMap(); + HttpSecurityBeanDefinitionParser.parseInterceptUrlsForFilterInvocationRequestMap(interceptUrls, requestMap, + convertPathsToLowerCase, parserContext); + + builder.addConstructorArg(matcher); + builder.addConstructorArg(requestMap); + } +} 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 047224a962..7ff70ad094 100644 --- a/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java @@ -20,6 +20,7 @@ import org.springframework.security.wrapper.SecurityContextHolderAwareRequestFil import org.springframework.security.context.HttpSessionContextIntegrationFilter; import org.springframework.security.intercept.web.DefaultFilterInvocationDefinitionSource; import org.springframework.security.intercept.web.FilterSecurityInterceptor; +import org.springframework.security.intercept.web.RequestKey; import org.springframework.security.securechannel.ChannelDecisionManagerImpl; import org.springframework.security.securechannel.ChannelProcessingFilter; import org.springframework.security.securechannel.InsecureChannelProcessor; @@ -111,45 +112,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class); Map filterChainMap = new LinkedHashMap(); - - String patternType = element.getAttribute(ATT_PATH_TYPE); - if (!StringUtils.hasText(patternType)) { - patternType = DEF_PATH_TYPE_ANT; - } - - boolean useRegex = patternType.equals(OPT_PATH_TYPE_REGEX); - - UrlMatcher matcher = new AntUrlPathMatcher(); - - if (useRegex) { - matcher = new RegexUrlPathMatcher(); - } - - // Deal with lowercase conversion requests - String lowercaseComparisons = element.getAttribute(ATT_LOWERCASE_COMPARISONS); - if (!StringUtils.hasText(lowercaseComparisons)) { - lowercaseComparisons = null; - } - - - // Only change from the defaults if the attribute has been set - if ("true".equals(lowercaseComparisons)) { - if (useRegex) { - ((RegexUrlPathMatcher)matcher).setRequiresLowerCaseUrl(true); - } - // Default for ant is already to force lower case - } else if ("false".equals(lowercaseComparisons)) { - if (!useRegex) { - ((AntUrlPathMatcher)matcher).setRequiresLowerCaseUrl(false); - } - // Default for regex is no change - } - - DefaultFilterInvocationDefinitionSource interceptorFilterInvDefSource = - new DefaultFilterInvocationDefinitionSource(matcher); - DefaultFilterInvocationDefinitionSource channelFilterInvDefSource = - new DefaultFilterInvocationDefinitionSource(matcher); - + + UrlMatcher matcher = createUrlMatcher(element); + filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher); // Add servlet-api integration filter if required @@ -164,8 +129,6 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", filterChainMap); - filterSecurityInterceptorBuilder.addPropertyValue("objectDefinitionSource", interceptorFilterInvDefSource); - // Set up the access manager and authentication mananger references for http String accessManagerId = element.getAttribute(ATT_ACCESS_MGR); @@ -182,13 +145,26 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { // SEC-501 - should paths stored in request maps be converted to lower case // true if Ant path and using lower case boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl(); - - parseInterceptUrls(DomUtils.getChildElementsByTagName(element, "intercept-url"), - filterChainMap, interceptorFilterInvDefSource, channelFilterInvDefSource, + + LinkedHashMap channelRequestMap = new LinkedHashMap(); + LinkedHashMap filterInvocationDefinitionMap = new LinkedHashMap(); + + List interceptUrlElts = DomUtils.getChildElementsByTagName(element, "intercept-url"); + parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap, convertPathsToLowerCase, parserContext); + parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, filterInvocationDefinitionMap, + convertPathsToLowerCase, parserContext); + + DefaultFilterInvocationDefinitionSource interceptorFilterInvDefSource = + new DefaultFilterInvocationDefinitionSource(matcher, filterInvocationDefinitionMap); + DefaultFilterInvocationDefinitionSource channelFilterInvDefSource = + new DefaultFilterInvocationDefinitionSource(matcher, channelRequestMap); + filterSecurityInterceptorBuilder.addPropertyValue("objectDefinitionSource", interceptorFilterInvDefSource); + + // Check if we need to register the channel processing beans - if (((DefaultFilterInvocationDefinitionSource)channelFilterInvDefSource).getMapSize() > 0) { + if (channelRequestMap.size() > 0) { // At least one channel requirement has been specified RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class); channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager", @@ -271,18 +247,52 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { return null; } + + static UrlMatcher createUrlMatcher(Element element) { + String patternType = element.getAttribute(ATT_PATH_TYPE); + if (!StringUtils.hasText(patternType)) { + patternType = DEF_PATH_TYPE_ANT; + } + + boolean useRegex = patternType.equals(OPT_PATH_TYPE_REGEX); + + UrlMatcher matcher = new AntUrlPathMatcher(); + + if (useRegex) { + matcher = new RegexUrlPathMatcher(); + } + + // Deal with lowercase conversion requests + String lowercaseComparisons = element.getAttribute(ATT_LOWERCASE_COMPARISONS); + if (!StringUtils.hasText(lowercaseComparisons)) { + lowercaseComparisons = null; + } + + + // Only change from the defaults if the attribute has been set + if ("true".equals(lowercaseComparisons)) { + if (useRegex) { + ((RegexUrlPathMatcher)matcher).setRequiresLowerCaseUrl(true); + } + // Default for ant is already to force lower case + } else if ("false".equals(lowercaseComparisons)) { + if (!useRegex) { + ((AntUrlPathMatcher)matcher).setRequiresLowerCaseUrl(false); + } + // Default for regex is no change + } + + return matcher; + } /** * Parses the intercept-url elements and populates the FilterChainProxy's filter chain Map and the - * FilterInvocationDefinitionSource used in FilterSecurityInterceptor. + * map used to create the FilterInvocationDefintionSource for the FilterSecurityInterceptor. */ - private void parseInterceptUrls(List urlElts, Map filterChainMap, - DefaultFilterInvocationDefinitionSource interceptorFilterInvDefSource, - DefaultFilterInvocationDefinitionSource channelFilterInvDefSource, + void parseInterceptUrlsForChannelSecurityAndFilterChain(List urlElts, Map filterChainMap, Map channelRequestMap, boolean useLowerCasePaths, ParserContext parserContext) { Iterator urlEltsIterator = urlElts.iterator(); - ConfigAttributeEditor editor = new ConfigAttributeEditor(); while (urlEltsIterator.hasNext()) { @@ -298,19 +308,6 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { path = path.toLowerCase(); } - String method = urlElt.getAttribute(ATT_HTTP_METHOD); - if (!StringUtils.hasText(method)) { - method = null; - } - - String access = urlElt.getAttribute(ATT_ACCESS_CONFIG); - - // Convert the comma-separated list of access attributes to a ConfigAttributeDefinition - if (StringUtils.hasText(access)) { - editor.setAsText(access); - interceptorFilterInvDefSource.addSecureUrl(path, method, (ConfigAttributeDefinition) editor.getValue()); - } - String requiredChannel = urlElt.getAttribute(ATT_REQUIRES_CHANNEL); if (StringUtils.hasText(requiredChannel)) { @@ -327,9 +324,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { } editor.setAsText(channelConfigAttribute); - channelFilterInvDefSource.addSecureUrl(path, (ConfigAttributeDefinition) editor.getValue()); + channelRequestMap.put(new RequestKey(path), (ConfigAttributeDefinition) editor.getValue()); } - + String filters = urlElt.getAttribute(ATT_FILTERS); if (StringUtils.hasText(filters)) { @@ -342,4 +339,39 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { } } } + + static void parseInterceptUrlsForFilterInvocationRequestMap(List urlElts, Map filterInvocationDefinitionMap, + boolean useLowerCasePaths, ParserContext parserContext) { + + Iterator urlEltsIterator = urlElts.iterator(); + ConfigAttributeEditor editor = new ConfigAttributeEditor(); + + while (urlEltsIterator.hasNext()) { + Element urlElt = (Element) urlEltsIterator.next(); + + String path = urlElt.getAttribute(ATT_PATH_PATTERN); + + if(!StringUtils.hasText(path)) { + parserContext.getReaderContext().error("path attribute cannot be empty or null", urlElt); + } + + if (useLowerCasePaths) { + path = path.toLowerCase(); + } + + String method = urlElt.getAttribute(ATT_HTTP_METHOD); + if (!StringUtils.hasText(method)) { + method = null; + } + + String access = urlElt.getAttribute(ATT_ACCESS_CONFIG); + + // Convert the comma-separated list of access attributes to a ConfigAttributeDefinition + if (StringUtils.hasText(access)) { + editor.setAsText(access); + filterInvocationDefinitionMap.put(new RequestKey(path, method), editor.getValue()); + } + } + } + } 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 2122750101..ed60e3bfb0 100644 --- a/core/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java +++ b/core/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java @@ -23,6 +23,7 @@ public class SecurityNamespaceHandler extends NamespaceHandlerSupport { registerBeanDefinitionParser(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser()); registerBeanDefinitionParser(Elements.ANNOTATION_DRIVEN, new AnnotationDrivenBeanDefinitionParser()); registerBeanDefinitionParser(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser()); + registerBeanDefinitionParser(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationDefinitionSourceBeanDefinitionParser()); // Decorators registerBeanDefinitionDecorator(Elements.INTERCEPT_METHODS, new InterceptMethodsBeanDefinitionDecorator()); diff --git a/core/src/main/java/org/springframework/security/intercept/web/DefaultFilterInvocationDefinitionSource.java b/core/src/main/java/org/springframework/security/intercept/web/DefaultFilterInvocationDefinitionSource.java index 1ebb28b166..84dd0c289b 100644 --- a/core/src/main/java/org/springframework/security/intercept/web/DefaultFilterInvocationDefinitionSource.java +++ b/core/src/main/java/org/springframework/security/intercept/web/DefaultFilterInvocationDefinitionSource.java @@ -61,7 +61,7 @@ public class DefaultFilterInvocationDefinitionSource implements FilterInvocation /** * Non method-specific map of URL patterns to ConfigAttributeDefinitions - * TODO: Store in the httpMethod map with null key. + * TODO: Store in the httpMethod map with null key. */ private Map requestMap = new LinkedHashMap(); /** Stores request maps keyed by specific HTTP methods */ @@ -75,10 +75,18 @@ public class DefaultFilterInvocationDefinitionSource implements FilterInvocation * Creates a FilterInvocationDefinitionSource with the supplied URL matching strategy. * @param urlMatcher */ - public DefaultFilterInvocationDefinitionSource(UrlMatcher urlMatcher) { + DefaultFilterInvocationDefinitionSource(UrlMatcher urlMatcher) { this.urlMatcher = urlMatcher; } + /** + * Builds the internal request map from the supplied map. The key elements should be of type {@link RequestKey}, + * which contains a URL path and an optional HTTP method (may be null). The path stored in the key will depend on + * the type of the supplied UrlMatcher. + * + * @param urlMatcher typically an ant or regular expression matcher. + * @param requestMap order-preserving map of . + */ public DefaultFilterInvocationDefinitionSource(UrlMatcher urlMatcher, LinkedHashMap requestMap) { this.urlMatcher = urlMatcher; @@ -86,13 +94,14 @@ public class DefaultFilterInvocationDefinitionSource implements FilterInvocation while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); - addSecureUrl((String)entry.getKey(), (ConfigAttributeDefinition)entry.getValue()); + RequestKey reqKey = (RequestKey) entry.getKey(); + addSecureUrl(reqKey.getUrl(), reqKey.getMethod(), (ConfigAttributeDefinition) entry.getValue()); } } //~ Methods ======================================================================================================== - public void addSecureUrl(String pattern, ConfigAttributeDefinition attr) { + void addSecureUrl(String pattern, ConfigAttributeDefinition attr) { addSecureUrl(pattern, null, attr); } @@ -102,7 +111,7 @@ public class DefaultFilterInvocationDefinitionSource implements FilterInvocation * to the request map and will be passed back to the UrlMatcher when iterating through the map to find * a match for a particular URL. */ - public void addSecureUrl(String pattern, String method, ConfigAttributeDefinition attr) { + void addSecureUrl(String pattern, String method, ConfigAttributeDefinition attr) { Map mapToUse = getRequestMapForHttpMethod(method); mapToUse.put(urlMatcher.compile(pattern), attr); diff --git a/core/src/main/java/org/springframework/security/intercept/web/FilterInvocationDefinitionSourceEditor.java b/core/src/main/java/org/springframework/security/intercept/web/FilterInvocationDefinitionSourceEditor.java index c0dac27947..c5bf09cba0 100644 --- a/core/src/main/java/org/springframework/security/intercept/web/FilterInvocationDefinitionSourceEditor.java +++ b/core/src/main/java/org/springframework/security/intercept/web/FilterInvocationDefinitionSourceEditor.java @@ -167,7 +167,7 @@ public class FilterInvocationDefinitionSourceEditor extends PropertyEditorSuppor String[] tokens = StringUtils.commaDelimitedListToStringArray(value); - urlMap.put(name, new ConfigAttributeDefinition(tokens)); + urlMap.put(new RequestKey(name), new ConfigAttributeDefinition(tokens)); } DefaultFilterInvocationDefinitionSource fids = diff --git a/core/src/main/java/org/springframework/security/intercept/web/RequestKey.java b/core/src/main/java/org/springframework/security/intercept/web/RequestKey.java index af3cb50da6..84e02e2186 100644 --- a/core/src/main/java/org/springframework/security/intercept/web/RequestKey.java +++ b/core/src/main/java/org/springframework/security/intercept/web/RequestKey.java @@ -5,25 +5,35 @@ package org.springframework.security.intercept.web; * @version $Id$ */ public class RequestKey { - String url; - String method; + private String url; + private String method; public RequestKey(String url) { - this(url, ""); + this(url, null); } public RequestKey(String url, String method) { this.url = url; this.method = method; } + + String getUrl() { + return url; + } + + String getMethod() { + return method; + } public int hashCode() { int code = 31; code ^= url.hashCode(); - code ^= method.hashCode(); + + if (method != null) { + code ^= method.hashCode(); + } return code; - } public boolean equals(Object obj) { @@ -33,6 +43,14 @@ public class RequestKey { RequestKey key = (RequestKey) obj; - return url.equals(key.url) && method.equals(key.method); + if (!url.equals(key.url)) { + return false; + } + + if (method == null && key.method != null) { + return false; + } + + return method.equals(key.method); } } diff --git a/core/src/main/java/org/springframework/security/util/UrlMatcher.java b/core/src/main/java/org/springframework/security/util/UrlMatcher.java index 0eee4b8710..8166717aa9 100644 --- a/core/src/main/java/org/springframework/security/util/UrlMatcher.java +++ b/core/src/main/java/org/springframework/security/util/UrlMatcher.java @@ -3,7 +3,7 @@ package org.springframework.security.util; /** * Strategy for deciding whether configured path matches a submitted candidate URL. * - * @author luke + * @author Luke Taylor * @version $Id$ * @since 2.0 */ 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 beeea6196d..e050cf91ae 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 @@ -212,6 +212,18 @@ filter-chain.attlist &= filter-chain.attlist &= attribute filters {xsd:string} +filter-invocation-definition-source = + ## Used to explicitly configure a FilterInvocationDefinitionSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error. + element filter-invocation-definition-source {fids.attlist, intercept-url+} +fids.attlist &= + id? +fids.attlist &= + ## as for http element + attribute lowercase-comparisons {"true" | "false"}? +fids.attlist &= + ## as for http element + path-type? + http-basic = ## Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute) element http-basic {empty} @@ -328,6 +340,6 @@ before = ## The filter immediately before which the custom-filter should be placed in the chain attribute before {"FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SESSION_CONTEXT_INTEGRATION_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_PROCESSING_FILTER" | "AUTHENTICATION_PROCESSING_FILTER" | "BASIC_PROCESSING_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "NTLM_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER"} - + 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 0d2cf92a27..a30ebe7495 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 @@ -527,6 +527,46 @@ + + + Used to explicitly configure a FilterInvocationDefinitionSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the <http> element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error. + + + + + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + as for http element + + + + + + + + + + + Defines the type of pattern used to specify URL paths (either JDK 1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if unspecified. + + + + + + + + + Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute) 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 91dc3bf58d..bdb578a304 100644 --- a/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java +++ b/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java @@ -38,7 +38,7 @@ import java.util.List; */ public class HttpSecurityBeanDefinitionParserTests { private AbstractXmlApplicationContext appContext; - private static final String AUTH_PROVIDER_XML = + static final String AUTH_PROVIDER_XML = " " + " " + " " + diff --git a/core/src/test/java/org/springframework/security/intercept/web/DefaultFilterInvocationDefinitionSourceTests.java b/core/src/test/java/org/springframework/security/intercept/web/DefaultFilterInvocationDefinitionSourceTests.java index 294b715782..4fa1566377 100644 --- a/core/src/test/java/org/springframework/security/intercept/web/DefaultFilterInvocationDefinitionSourceTests.java +++ b/core/src/test/java/org/springframework/security/intercept/web/DefaultFilterInvocationDefinitionSourceTests.java @@ -19,6 +19,7 @@ import org.springframework.security.ConfigAttributeDefinition; import org.springframework.security.MockFilterChain; import org.springframework.security.SecurityConfig; import org.springframework.security.util.AntUrlPathMatcher; +import org.springframework.security.util.InMemoryXmlApplicationContext; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -169,6 +170,38 @@ public class DefaultFilterInvocationDefinitionSourceTests { response = map.lookupAttributes(fi.getRequestUrl()); assertEquals(def, response); } + + @Test + public void xmlMapConfigurationIsSuccessful() { + InMemoryXmlApplicationContext context = new InMemoryXmlApplicationContext( + "" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + "" + ); + + DefaultFilterInvocationDefinitionSource fids = (DefaultFilterInvocationDefinitionSource) context.getBean("fids"); + ConfigAttributeDefinition cad = fids.lookupAttributes("/anything", "GET"); + assertNotNull(cad); + assertEquals(1, cad.getConfigAttributes().size()); + context.close(); + } private FilterInvocation createFilterInvocation(String path, String method) { MockHttpServletRequest request = new MockHttpServletRequest(); diff --git a/core/src/test/java/org/springframework/security/intercept/web/FilterSecurityInterceptorTests.java b/core/src/test/java/org/springframework/security/intercept/web/FilterSecurityInterceptorTests.java index f91b94509c..4e64c455da 100644 --- a/core/src/test/java/org/springframework/security/intercept/web/FilterSecurityInterceptorTests.java +++ b/core/src/test/java/org/springframework/security/intercept/web/FilterSecurityInterceptorTests.java @@ -39,6 +39,7 @@ import org.springframework.mock.web.MockHttpServletResponse; import java.io.IOException; import java.util.Collection; +import java.util.LinkedHashMap; import javax.servlet.FilterChain; import javax.servlet.ServletException; @@ -220,9 +221,10 @@ public class FilterSecurityInterceptorTests extends TestCase { } public void testNotLoadedFromApplicationContext() throws Exception { + LinkedHashMap reqMap = new LinkedHashMap(); + reqMap.put(new RequestKey("/secure/**", null), new ConfigAttributeDefinition(new String[] {"ROLE_USER"})); DefaultFilterInvocationDefinitionSource fids - = new DefaultFilterInvocationDefinitionSource(new AntUrlPathMatcher()); - fids.addSecureUrl("/secure/**", null, new ConfigAttributeDefinition(new String[] {"ROLE_USER"})); + = new DefaultFilterInvocationDefinitionSource(new AntUrlPathMatcher()); FilterSecurityInterceptor filter = new FilterSecurityInterceptor(); filter.setObjectDefinitionSource(fids); diff --git a/core/src/test/java/org/springframework/security/util/FilterChainProxyTests.java b/core/src/test/java/org/springframework/security/util/FilterChainProxyTests.java index f3c03b59de..0dd2afd1e0 100644 --- a/core/src/test/java/org/springframework/security/util/FilterChainProxyTests.java +++ b/core/src/test/java/org/springframework/security/util/FilterChainProxyTests.java @@ -21,6 +21,7 @@ import org.springframework.security.MockFilterConfig; import org.springframework.security.context.HttpSessionContextIntegrationFilter; import org.springframework.security.intercept.web.MockFilterInvocationDefinitionSource; import org.springframework.security.intercept.web.DefaultFilterInvocationDefinitionSource; +import org.springframework.security.intercept.web.RequestKey; import org.springframework.security.ui.webapp.AuthenticationProcessingFilter; import org.springframework.beans.factory.BeanCreationException; @@ -34,6 +35,7 @@ import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; +import java.util.LinkedHashMap; import java.util.List; /** @@ -80,9 +82,10 @@ public class FilterChainProxyTests { ConfigAttributeDefinition cad = new ConfigAttributeDefinition(new MockConfigAttribute()); + LinkedHashMap map = new LinkedHashMap(); + map.put(new RequestKey("/**"), cad); DefaultFilterInvocationDefinitionSource fids = - new DefaultFilterInvocationDefinitionSource(new AntUrlPathMatcher()); - fids.addSecureUrl("/**", cad); + new DefaultFilterInvocationDefinitionSource(new AntUrlPathMatcher(), map); filterChainProxy.setFilterInvocationDefinitionSource(fids);