mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-03-08 22:39:20 +00:00
SEC-531: Provide support for HTTP methods in FilterInvocationDefinitionSource. Path/Regex versions of FIDS are now deprecated and in favour of using their (no longer abstract) parent class with a UrlPathMatcher strategy.
This commit is contained in:
parent
342677fabc
commit
d10450cfb7
@ -18,11 +18,8 @@ import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.ConfigAttributeEditor;
|
||||
import org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.context.HttpSessionContextIntegrationFilter;
|
||||
import org.springframework.security.intercept.web.AbstractFilterInvocationDefinitionSource;
|
||||
import org.springframework.security.intercept.web.FilterInvocationDefinitionMap;
|
||||
import org.springframework.security.intercept.web.DefaultFilterInvocationDefinitionSource;
|
||||
import org.springframework.security.intercept.web.FilterSecurityInterceptor;
|
||||
import org.springframework.security.intercept.web.PathBasedFilterInvocationDefinitionMap;
|
||||
import org.springframework.security.intercept.web.RegExpBasedFilterInvocationDefinitionMap;
|
||||
import org.springframework.security.securechannel.ChannelDecisionManagerImpl;
|
||||
import org.springframework.security.securechannel.ChannelProcessingFilter;
|
||||
import org.springframework.security.securechannel.InsecureChannelProcessor;
|
||||
@ -33,6 +30,7 @@ import org.springframework.security.ui.ExceptionTranslationFilter;
|
||||
import org.springframework.security.util.FilterChainProxy;
|
||||
import org.springframework.security.util.RegexUrlPathMatcher;
|
||||
import org.springframework.security.util.AntUrlPathMatcher;
|
||||
import org.springframework.security.util.UrlMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
@ -65,6 +63,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String OPT_REQUIRES_HTTPS = "https";
|
||||
static final String OPT_ANY_CHANNEL = "any";
|
||||
|
||||
static final String ATT_HTTP_METHOD = "method";
|
||||
|
||||
static final String ATT_CREATE_SESSION = "create-session";
|
||||
static final String DEF_CREATE_SESSION_IF_REQUIRED = "ifRequired";
|
||||
static final String OPT_CREATE_SESSION_ALWAYS = "always";
|
||||
@ -118,8 +118,13 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
patternType = DEF_PATH_TYPE_ANT;
|
||||
}
|
||||
|
||||
FilterInvocationDefinitionMap interceptorFilterInvDefSource = new PathBasedFilterInvocationDefinitionMap();
|
||||
FilterInvocationDefinitionMap channelFilterInvDefSource = new PathBasedFilterInvocationDefinitionMap();
|
||||
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);
|
||||
@ -127,33 +132,27 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
lowercaseComparisons = null;
|
||||
}
|
||||
|
||||
|
||||
// Only change from the defaults if the attribute has been set
|
||||
if ("true".equals(lowercaseComparisons)) {
|
||||
interceptorFilterInvDefSource.setConvertUrlToLowercaseBeforeComparison(true);
|
||||
channelFilterInvDefSource.setConvertUrlToLowercaseBeforeComparison(true);
|
||||
} else if ("false".equals(lowercaseComparisons)) {
|
||||
interceptorFilterInvDefSource.setConvertUrlToLowercaseBeforeComparison(false);
|
||||
channelFilterInvDefSource.setConvertUrlToLowercaseBeforeComparison(false);
|
||||
}
|
||||
|
||||
if (patternType.equals(OPT_PATH_TYPE_REGEX)) {
|
||||
RegexUrlPathMatcher matcher = new RegexUrlPathMatcher();
|
||||
|
||||
if (lowercaseComparisons != null) {
|
||||
matcher.setRequiresLowerCaseUrl("true".equals(lowercaseComparisons));
|
||||
if (useRegex) {
|
||||
((RegexUrlPathMatcher)matcher).setRequiresLowerCaseUrl(true);
|
||||
}
|
||||
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher);
|
||||
|
||||
interceptorFilterInvDefSource = new RegExpBasedFilterInvocationDefinitionMap();
|
||||
channelFilterInvDefSource = new RegExpBasedFilterInvocationDefinitionMap();
|
||||
} else if (lowercaseComparisons != null) {
|
||||
AntUrlPathMatcher matcher = new AntUrlPathMatcher();
|
||||
matcher.setRequiresLowerCaseUrl("true".equals(lowercaseComparisons));
|
||||
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher);
|
||||
// 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);
|
||||
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher);
|
||||
|
||||
// Add servlet-api integration filter if required
|
||||
String provideServletApi = element.getAttribute(ATT_SERVLET_API_PROVISION);
|
||||
if (!StringUtils.hasText(provideServletApi)) {
|
||||
@ -181,11 +180,16 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
filterSecurityInterceptorBuilder.addPropertyValue("authenticationManager",
|
||||
ConfigUtils.registerProviderManagerIfNecessary(parserContext));
|
||||
|
||||
// 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, parserContext);
|
||||
filterChainMap, interceptorFilterInvDefSource, channelFilterInvDefSource,
|
||||
convertPathsToLowerCase, parserContext);
|
||||
|
||||
// Check if we need to register the channel processing beans
|
||||
if (((AbstractFilterInvocationDefinitionSource)channelFilterInvDefSource).getMapSize() > 0) {
|
||||
if (((DefaultFilterInvocationDefinitionSource)channelFilterInvDefSource).getMapSize() > 0) {
|
||||
// At least one channel requirement has been specified
|
||||
RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
|
||||
channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager",
|
||||
@ -268,8 +272,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
* FilterInvocationDefinitionSource used in FilterSecurityInterceptor.
|
||||
*/
|
||||
private void parseInterceptUrls(List urlElts, Map filterChainMap,
|
||||
FilterInvocationDefinitionMap interceptorFilterInvDefSource,
|
||||
FilterInvocationDefinitionMap channelFilterInvDefSource, ParserContext parserContext) {
|
||||
DefaultFilterInvocationDefinitionSource interceptorFilterInvDefSource,
|
||||
DefaultFilterInvocationDefinitionSource channelFilterInvDefSource,
|
||||
boolean useLowerCasePaths, ParserContext parserContext) {
|
||||
|
||||
Iterator urlEltsIterator = urlElts.iterator();
|
||||
|
||||
@ -279,6 +284,14 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
Element urlElt = (Element) urlEltsIterator.next();
|
||||
|
||||
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
|
||||
if (useLowerCasePaths) {
|
||||
path = path.toLowerCase();
|
||||
}
|
||||
|
||||
String method = urlElt.getAttribute(ATT_HTTP_METHOD);
|
||||
if (!StringUtils.hasText(method)) {
|
||||
method = null;
|
||||
}
|
||||
|
||||
Assert.hasText(path, "path attribute cannot be empty or null");
|
||||
|
||||
@ -287,7 +300,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
// Convert the comma-separated list of access attributes to a ConfigAttributeDefinition
|
||||
if (StringUtils.hasText(access)) {
|
||||
editor.setAsText(access);
|
||||
interceptorFilterInvDefSource.addSecureUrl(path, (ConfigAttributeDefinition) editor.getValue());
|
||||
interceptorFilterInvDefSource.addSecureUrl(path, method, (ConfigAttributeDefinition) editor.getValue());
|
||||
}
|
||||
|
||||
String requiredChannel = urlElt.getAttribute(ATT_REQUIRES_CHANNEL);
|
||||
|
@ -1,152 +0,0 @@
|
||||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.intercept.web;
|
||||
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.util.UrlMatcher;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
* Abstract implementation of <Code>FilterInvocationDefinitionSource</code>.
|
||||
* <p>
|
||||
* Stores an ordered map of compiled URL paths to <tt>ConfigAttributeDefinition</tt>s and provides URL matching
|
||||
* against the items stored in this map using the confgured <tt>UrlMatcher</tt>.
|
||||
* <p>
|
||||
* The order of registering the regular expressions using the {@link #addSecureUrl(String,
|
||||
* ConfigAttributeDefinition)} is very important. The system will identify the <b>first</b> matching regular
|
||||
* expression for a given HTTP URL. It will not proceed to evaluate later regular expressions if a match has already
|
||||
* been found. Accordingly, the most specific regular expressions should be registered first, with the most general
|
||||
* regular expressions registered last.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class AbstractFilterInvocationDefinitionSource implements FilterInvocationDefinitionSource {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private Map requestMap = new LinkedHashMap();
|
||||
|
||||
private UrlMatcher urlMatcher;
|
||||
|
||||
protected AbstractFilterInvocationDefinitionSource(UrlMatcher urlMatcher) {
|
||||
this.urlMatcher = urlMatcher;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Adds a URL-ConfigAttributeDefinition pair to the request map, first allowing the <tt>UrlMatcher</tt> to
|
||||
* process the pattern if required, using its <tt>compile</tt> method. The returned object will be used as the key
|
||||
* to the request map and will be passed back to the <tt>UrlMatcher</tt> when iterating through the map to find
|
||||
* a match for a particular URL.
|
||||
*/
|
||||
public void addSecureUrl(String pattern, ConfigAttributeDefinition attr) {
|
||||
requestMap.put(urlMatcher.compile(pattern), attr);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added URL pattern: " + pattern + "; attributes: " + attr);
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator getConfigAttributeDefinitions() {
|
||||
return getRequestMap().values().iterator();
|
||||
}
|
||||
|
||||
public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
|
||||
if ((object == null) || !this.supports(object.getClass())) {
|
||||
throw new IllegalArgumentException("Object must be a FilterInvocation");
|
||||
}
|
||||
|
||||
String url = ((FilterInvocation) object).getRequestUrl();
|
||||
|
||||
return lookupAttributes(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual lookup of the relevant <code>ConfigAttributeDefinition</code> for the specified
|
||||
* <code>FilterInvocation</code>.
|
||||
* <p>
|
||||
* By default, iterates through the stored URL map and calls the
|
||||
* {@link UrlMatcher#pathMatchesUrl(Object path, String url)} method until a match is found.
|
||||
* <p>
|
||||
* Subclasses can override if required to perform any modifications to the URL.
|
||||
* <p>
|
||||
* Public visiblity so that tablibs or other view helper classes can access the
|
||||
* <code>ConfigAttributeDefinition</code> applying to a given URI pattern without needing to construct a mock
|
||||
* <code>FilterInvocation</code> and retrieving the attibutes via the {@link #getAttributes(Object)} method.
|
||||
*
|
||||
* @param url the URI to retrieve configuration attributes for
|
||||
*
|
||||
* @return the <code>ConfigAttributeDefinition</code> that applies to the specified <code>FilterInvocation</code>
|
||||
* or null if no match is foud
|
||||
*/
|
||||
public ConfigAttributeDefinition lookupAttributes(String url) {
|
||||
if (urlMatcher.requiresLowerCaseUrl()) {
|
||||
url = url.toLowerCase();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Converted URL to lowercase, from: '" + url + "'; to: '" + url + "'");
|
||||
}
|
||||
}
|
||||
|
||||
Iterator entries = requestMap.entrySet().iterator();
|
||||
|
||||
while (entries.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) entries.next();
|
||||
Object p = entry.getKey();
|
||||
boolean matched = urlMatcher.pathMatchesUrl(p, url);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Candidate is: '" + url + "'; pattern is " + p + "; matched=" + matched);
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
return (ConfigAttributeDefinition) entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean supports(Class clazz) {
|
||||
return FilterInvocation.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
public int getMapSize() {
|
||||
return this.requestMap.size();
|
||||
}
|
||||
|
||||
Map getRequestMap() {
|
||||
return requestMap;
|
||||
}
|
||||
|
||||
protected UrlMatcher getUrlMatcher() {
|
||||
return urlMatcher;
|
||||
}
|
||||
|
||||
public boolean isConvertUrlToLowercaseBeforeComparison() {
|
||||
return urlMatcher.requiresLowerCaseUrl();
|
||||
}
|
||||
}
|
@ -0,0 +1,263 @@
|
||||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.intercept.web;
|
||||
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.SecurityConfig;
|
||||
import org.springframework.security.util.UrlMatcher;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of <tt>FilterInvocationDefinitionSource</tt>.
|
||||
* <p>
|
||||
* Stores an ordered map of compiled URL paths to <tt>ConfigAttributeDefinition</tt>s and provides URL matching
|
||||
* against the items stored in this map using the configured <tt>UrlMatcher</tt>.
|
||||
* <p>
|
||||
* The order of registering the regular expressions using the
|
||||
* {@link #addSecureUrl(String, ConfigAttributeDefinition)} is very important.
|
||||
* The system will identify the <b>first</b> matching regular
|
||||
* expression for a given HTTP URL. It will not proceed to evaluate later regular expressions if a match has already
|
||||
* been found. Accordingly, the most specific regular expressions should be registered first, with the most general
|
||||
* regular expressions registered last.
|
||||
* <p>
|
||||
* If URLs are registered for a particular HTTP method using
|
||||
* {@link #addSecureUrl(String, String, ConfigAttributeDefinition)}, then the method-specific matches will take
|
||||
* precedence over any URLs which are registered without an HTTP method.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class DefaultFilterInvocationDefinitionSource implements FilterInvocationDefinitionSource {
|
||||
|
||||
private static final Set HTTP_METHODS = new HashSet(Arrays.asList(new String[]{ "GET", "PUT", "DELETE", "POST" }));
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/**
|
||||
* Non method-specific map of URL patterns to <tt>ConfigAttributeDefinition</tt>s
|
||||
* TODO: Store in the httpMethod map with null key.
|
||||
*/
|
||||
private Map requestMap = new LinkedHashMap();
|
||||
/** Stores request maps keyed by specific HTTP methods */
|
||||
private Map httpMethodMap = new HashMap();
|
||||
|
||||
private UrlMatcher urlMatcher;
|
||||
|
||||
private boolean stripQueryStringFromUrls;
|
||||
|
||||
/**
|
||||
* Creates a FilterInvocationDefinitionSource with the supplied URL matching strategy.
|
||||
* @param urlMatcher
|
||||
*/
|
||||
public DefaultFilterInvocationDefinitionSource(UrlMatcher urlMatcher) {
|
||||
this.urlMatcher = urlMatcher;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void addSecureUrl(String pattern, ConfigAttributeDefinition attr) {
|
||||
addSecureUrl(pattern, null, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a URL-ConfigAttributeDefinition pair to the request map, first allowing the <tt>UrlMatcher</tt> to
|
||||
* process the pattern if required, using its <tt>compile</tt> method. The returned object will be used as the key
|
||||
* to the request map and will be passed back to the <tt>UrlMatcher</tt> when iterating through the map to find
|
||||
* a match for a particular URL.
|
||||
*/
|
||||
public void addSecureUrl(String pattern, String method, ConfigAttributeDefinition attr) {
|
||||
Map mapToUse = getRequestMapForHttpMethod(method);
|
||||
|
||||
mapToUse.put(urlMatcher.compile(pattern), attr);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added URL pattern: " + pattern + "; attributes: " + attr +
|
||||
(method == null ? "" : " for HTTP method '" + method + "'"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HTTP method specific request map, creating it if it doesn't already exist.
|
||||
* @param method GET, POST etc
|
||||
* @return map of URL patterns to <tt>ConfigAttributeDefinition</tt>s for this method.
|
||||
*/
|
||||
private Map getRequestMapForHttpMethod(String method) {
|
||||
if (method == null) {
|
||||
return requestMap;
|
||||
}
|
||||
if (!HTTP_METHODS.contains(method)) {
|
||||
throw new IllegalArgumentException("Unrecognised HTTP method: '" + method + "'");
|
||||
}
|
||||
|
||||
Map methodRequestmap = (Map) httpMethodMap.get(method);
|
||||
|
||||
if (methodRequestmap == null) {
|
||||
methodRequestmap = new LinkedHashMap();
|
||||
httpMethodMap.put(method, methodRequestmap);
|
||||
}
|
||||
|
||||
return methodRequestmap;
|
||||
}
|
||||
|
||||
public Iterator getConfigAttributeDefinitions() {
|
||||
return getRequestMap().values().iterator();
|
||||
}
|
||||
|
||||
public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
|
||||
if ((object == null) || !this.supports(object.getClass())) {
|
||||
throw new IllegalArgumentException("Object must be a FilterInvocation");
|
||||
}
|
||||
|
||||
String url = ((FilterInvocation) object).getRequestUrl();
|
||||
String method = ((FilterInvocation) object).getHttpRequest().getMethod();
|
||||
|
||||
return lookupAttributes(url, method);
|
||||
}
|
||||
|
||||
protected ConfigAttributeDefinition lookupAttributes(String url) {
|
||||
return lookupAttributes(url, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual lookup of the relevant <code>ConfigAttributeDefinition</code> for the specified
|
||||
* <code>FilterInvocation</code>.
|
||||
* <p>
|
||||
* By default, iterates through the stored URL map and calls the
|
||||
* {@link UrlMatcher#pathMatchesUrl(Object path, String url)} method until a match is found.
|
||||
* <p>
|
||||
* Subclasses can override if required to perform any modifications to the URL.
|
||||
*
|
||||
* @param url the URI to retrieve configuration attributes for
|
||||
* @param method the HTTP method (GET, POST, DELETE...).
|
||||
*
|
||||
* @return the <code>ConfigAttributeDefinition</code> that applies to the specified <code>FilterInvocation</code>
|
||||
* or null if no match is foud
|
||||
*/
|
||||
protected ConfigAttributeDefinition lookupAttributes(String url, String method) {
|
||||
if (stripQueryStringFromUrls) {
|
||||
// Strip anything after a question mark symbol, as per SEC-161. See also SEC-321
|
||||
int firstQuestionMarkIndex = url.indexOf("?");
|
||||
|
||||
if (firstQuestionMarkIndex != -1) {
|
||||
url = url.substring(0, firstQuestionMarkIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (urlMatcher.requiresLowerCaseUrl()) {
|
||||
url = url.toLowerCase();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Converted URL to lowercase, from: '" + url + "'; to: '" + url + "'");
|
||||
}
|
||||
}
|
||||
|
||||
ConfigAttributeDefinition attributes = null;
|
||||
|
||||
Map methodSpecificMap = (Map) httpMethodMap.get(method);
|
||||
|
||||
if (methodSpecificMap != null) {
|
||||
attributes = lookupUrlInMap(methodSpecificMap, url);
|
||||
}
|
||||
|
||||
if (attributes == null) {
|
||||
attributes = lookupUrlInMap(requestMap, url);
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private ConfigAttributeDefinition lookupUrlInMap(Map requestMap, String url) {
|
||||
Iterator entries = requestMap.entrySet().iterator();
|
||||
|
||||
while (entries.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) entries.next();
|
||||
Object p = entry.getKey();
|
||||
boolean matched = urlMatcher.pathMatchesUrl(p, url);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Candidate is: '" + url + "'; pattern is " + p + "; matched=" + matched);
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
return (ConfigAttributeDefinition) entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows or easier configuration using {@link FilterInvocationDefinitionSourceMapping}.
|
||||
*
|
||||
* @param mappings
|
||||
* {@link java.util.List} of
|
||||
* {@link FilterInvocationDefinitionSourceMapping} objects.
|
||||
*/
|
||||
void setMappings(List mappings) {
|
||||
Iterator it = mappings.iterator();
|
||||
|
||||
while (it.hasNext()) {
|
||||
FilterInvocationDefinitionSourceMapping mapping = (FilterInvocationDefinitionSourceMapping) it.next();
|
||||
ConfigAttributeDefinition configDefinition = new ConfigAttributeDefinition();
|
||||
|
||||
Iterator configAttributesIt = mapping.getConfigAttributes().iterator();
|
||||
while (configAttributesIt.hasNext()) {
|
||||
String s = (String) configAttributesIt.next();
|
||||
configDefinition.addConfigAttribute(new SecurityConfig(s));
|
||||
}
|
||||
|
||||
addSecureUrl(mapping.getUrl(), configDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean supports(Class clazz) {
|
||||
return FilterInvocation.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
public int getMapSize() {
|
||||
return this.requestMap.size();
|
||||
}
|
||||
|
||||
Map getRequestMap() {
|
||||
return requestMap;
|
||||
}
|
||||
|
||||
protected UrlMatcher getUrlMatcher() {
|
||||
return urlMatcher;
|
||||
}
|
||||
|
||||
public boolean isConvertUrlToLowercaseBeforeComparison() {
|
||||
return urlMatcher.requiresLowerCaseUrl();
|
||||
}
|
||||
|
||||
protected void setStripQueryStringFromUrls(boolean stripQueryStringFromUrls) {
|
||||
this.stripQueryStringFromUrls = stripQueryStringFromUrls;
|
||||
}
|
||||
}
|
@ -29,13 +29,11 @@ public class FIDSToFilterChainMapConverter {
|
||||
// TODO: Check if this is necessary. Retained from refactoring of FilterChainProxy
|
||||
Assert.notNull(source.getConfigAttributeDefinitions(), "FilterChainProxy requires the " +
|
||||
"FilterInvocationDefinitionSource to return a non-null response to getConfigAttributeDefinitions()");
|
||||
Assert.isTrue(
|
||||
source instanceof PathBasedFilterInvocationDefinitionMap ||
|
||||
source instanceof RegExpBasedFilterInvocationDefinitionMap,
|
||||
Assert.isTrue(source instanceof DefaultFilterInvocationDefinitionSource,
|
||||
"Can't handle FilterInvocationDefinitionSource type " + source.getClass());
|
||||
|
||||
|
||||
AbstractFilterInvocationDefinitionSource fids = (AbstractFilterInvocationDefinitionSource)source;
|
||||
DefaultFilterInvocationDefinitionSource fids = (DefaultFilterInvocationDefinitionSource)source;
|
||||
Map requestMap = fids.getRequestMap();
|
||||
Iterator paths = requestMap.keySet().iterator();
|
||||
|
||||
|
@ -23,20 +23,31 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.util.StringSplitUtils;
|
||||
import org.springframework.security.util.RegexUrlPathMatcher;
|
||||
import org.springframework.security.util.UrlMatcher;
|
||||
import org.springframework.security.util.AntUrlPathMatcher;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Property editor to assist with the setup of a {@link FilterInvocationDefinitionSource}.<p>The class creates and
|
||||
* populates a {@link RegExpBasedFilterInvocationDefinitionMap} or {@link PathBasedFilterInvocationDefinitionMap}
|
||||
* (depending on the type of patterns presented).</p>
|
||||
* <p>By default the class treats presented patterns as regular expressions. If the keyword
|
||||
* Property editor to assist with the setup of a {@link FilterInvocationDefinitionSource}.
|
||||
* <p>
|
||||
* Note that from version 2.0, the use of property-editor based configuration is deprecated in favour of namespace
|
||||
* configuration options.
|
||||
* <p>
|
||||
* The class creates and populates a
|
||||
* {@link org.springframework.security.intercept.web.DefaultFilterInvocationDefinitionSource}
|
||||
* using either an Ant or Regular Expression URL matching strategy depending on the type of patterns presented.
|
||||
* <p>
|
||||
* By default the class treats presented patterns as regular expressions. If the keyword
|
||||
* <code>PATTERN_TYPE_APACHE_ANT</code> is present (case sensitive), patterns will be treated as Apache Ant paths
|
||||
* rather than regular expressions.</p>
|
||||
* rather than regular expressions.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @deprecated Use namespace configuration instead. May be removed in future versions.
|
||||
* @version $Id$
|
||||
*/
|
||||
public class FilterInvocationDefinitionSourceEditor extends PropertyEditorSupport {
|
||||
@ -50,38 +61,50 @@ public class FilterInvocationDefinitionSourceEditor extends PropertyEditorSuppor
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void setAsText(String s) throws IllegalArgumentException {
|
||||
FilterInvocationDefinitionDecorator source = new FilterInvocationDefinitionDecorator();
|
||||
//FilterInvocationDefinitionDecorator source = new FilterInvocationDefinitionDecorator();
|
||||
|
||||
if ((s == null) || "".equals(s)) {
|
||||
// Leave target object empty
|
||||
setValue(new RegExpBasedFilterInvocationDefinitionMap());
|
||||
setValue(new DefaultFilterInvocationDefinitionSource(new RegexUrlPathMatcher()));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we need to override the default definition map
|
||||
if (s.lastIndexOf(DIRECTIVE_PATTERN_TYPE_APACHE_ANT) != -1) {
|
||||
source.setDecorated(new PathBasedFilterInvocationDefinitionMap());
|
||||
boolean useAnt = s.lastIndexOf(DIRECTIVE_PATTERN_TYPE_APACHE_ANT) != -1;
|
||||
boolean converUrlToLowerCase = s.lastIndexOf(DIRECTIVE_CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON) != -1;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
if (useAnt) {
|
||||
logger.debug(("Detected " + DIRECTIVE_PATTERN_TYPE_APACHE_ANT
|
||||
+ " directive; using Apache Ant style path expressions"));
|
||||
}
|
||||
} else {
|
||||
source.setDecorated(new RegExpBasedFilterInvocationDefinitionMap());
|
||||
}
|
||||
|
||||
if (s.lastIndexOf(DIRECTIVE_CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON) != -1) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Detected " + DIRECTIVE_CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
|
||||
+ " directive; Instructing mapper to convert URLs to lowercase before comparison");
|
||||
if (converUrlToLowerCase) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Detected " + DIRECTIVE_CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
|
||||
+ " directive; Instructing mapper to convert URLs to lowercase before comparison");
|
||||
}
|
||||
}
|
||||
|
||||
source.setConvertUrlToLowercaseBeforeComparison(true);
|
||||
} else {
|
||||
source.setConvertUrlToLowercaseBeforeComparison(false);
|
||||
}
|
||||
|
||||
UrlMatcher matcher;
|
||||
|
||||
if (useAnt) {
|
||||
matcher = new AntUrlPathMatcher();
|
||||
((AntUrlPathMatcher)matcher).setRequiresLowerCaseUrl(converUrlToLowerCase);
|
||||
|
||||
} else {
|
||||
matcher = new RegexUrlPathMatcher();
|
||||
((RegexUrlPathMatcher)matcher).setRequiresLowerCaseUrl(converUrlToLowerCase);
|
||||
}
|
||||
|
||||
DefaultFilterInvocationDefinitionSource fids = new DefaultFilterInvocationDefinitionSource(matcher);
|
||||
|
||||
if (useAnt) {
|
||||
fids.setStripQueryStringFromUrls(true);
|
||||
}
|
||||
|
||||
|
||||
BufferedReader br = new BufferedReader(new StringReader(s));
|
||||
int counter = 0;
|
||||
String line;
|
||||
@ -147,8 +170,7 @@ public class FilterInvocationDefinitionSourceEditor extends PropertyEditorSuppor
|
||||
}
|
||||
|
||||
// Attempt to detect malformed lines (as per SEC-204)
|
||||
if (source.isConvertUrlToLowercaseBeforeComparison()
|
||||
&& source.getDecorated() instanceof PathBasedFilterInvocationDefinitionMap) {
|
||||
if (converUrlToLowerCase && useAnt) {
|
||||
// Should all be lowercase; check each character
|
||||
// We only do this for Ant (regexp have control chars)
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
@ -174,9 +196,8 @@ public class FilterInvocationDefinitionSourceEditor extends PropertyEditorSuppor
|
||||
|
||||
mappings.add(mapping);
|
||||
}
|
||||
source.setMappings(mappings);
|
||||
fids.setMappings(mappings);
|
||||
|
||||
|
||||
setValue(source.getDecorated());
|
||||
setValue(fids);
|
||||
}
|
||||
}
|
||||
|
@ -18,11 +18,8 @@ package org.springframework.security.intercept.web;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.util.AntUrlPathMatcher;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
* Extends AbstractFilterInvocationDefinitionSource, configuring it with a {@link AntUrlPathMatcher} to match URLs
|
||||
* Extends DefaultFilterInvocationDefinitionSource, configuring it with a {@link AntUrlPathMatcher} to match URLs
|
||||
* using Apache Ant path-based patterns.
|
||||
* <p>
|
||||
* Apache Ant path expressions are used to match a HTTP request URL against a <code>ConfigAttributeDefinition</code>.
|
||||
@ -39,42 +36,29 @@ import java.util.Iterator;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke taylor
|
||||
* @deprecated DefaultFilterInvocationDefinitionSource should now be used with an AntUrlPathMatcher instead.
|
||||
* @version $Id$
|
||||
*/
|
||||
public class PathBasedFilterInvocationDefinitionMap extends AbstractFilterInvocationDefinitionSource
|
||||
public class PathBasedFilterInvocationDefinitionMap extends DefaultFilterInvocationDefinitionSource
|
||||
implements FilterInvocationDefinition {
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public PathBasedFilterInvocationDefinitionMap() {
|
||||
super(new AntUrlPathMatcher());
|
||||
setStripQueryStringFromUrls(true);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void addSecureUrl(String antPath, ConfigAttributeDefinition attr) {
|
||||
public void addSecureUrl(String antPath, String method, ConfigAttributeDefinition attr) {
|
||||
// SEC-501: If using lower case comparison, we should convert the paths to lower case
|
||||
// as any upper case characters included by mistake will prevent the URL from ever being matched.
|
||||
if (getUrlMatcher().requiresLowerCaseUrl()) {
|
||||
antPath = antPath.toLowerCase();
|
||||
}
|
||||
|
||||
super.addSecureUrl(antPath, attr);
|
||||
}
|
||||
|
||||
public Iterator getConfigAttributeDefinitions() {
|
||||
return getRequestMap().values().iterator();
|
||||
}
|
||||
|
||||
public ConfigAttributeDefinition lookupAttributes(String url) {
|
||||
// Strip anything after a question mark symbol, as per SEC-161. See also SEC-321
|
||||
int firstQuestionMarkIndex = url.indexOf("?");
|
||||
|
||||
if (firstQuestionMarkIndex != -1) {
|
||||
url = url.substring(0, firstQuestionMarkIndex);
|
||||
}
|
||||
|
||||
return super.lookupAttributes(url);
|
||||
super.addSecureUrl(antPath, method, attr);
|
||||
}
|
||||
|
||||
public void setConvertUrlToLowercaseBeforeComparison(boolean bool) {
|
||||
|
@ -16,18 +16,18 @@
|
||||
package org.springframework.security.intercept.web;
|
||||
|
||||
import org.springframework.security.util.RegexUrlPathMatcher;
|
||||
import org.springframework.security.util.AntUrlPathMatcher;
|
||||
|
||||
|
||||
/**
|
||||
* Configures an {@link AbstractFilterInvocationDefinitionSource} with a regular expression URL matching strategy
|
||||
* Configures an {@link DefaultFilterInvocationDefinitionSource} with a regular expression URL matching strategy
|
||||
* {@link RegexUrlPathMatcher}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @deprecated
|
||||
* @version $Id$
|
||||
*/
|
||||
public class RegExpBasedFilterInvocationDefinitionMap extends AbstractFilterInvocationDefinitionSource
|
||||
public class RegExpBasedFilterInvocationDefinitionMap extends DefaultFilterInvocationDefinitionSource
|
||||
implements FilterInvocationDefinition {
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
@ -48,7 +48,7 @@ public final class FilterInvocationUtils {
|
||||
|
||||
/**
|
||||
* Creates a <code>FilterInvocation</code> for the specified <code>contextPath</code> and <code>Uri</code>.
|
||||
* Note the normal subclasses of <code>AbstractFilterInvocationDefinitionSource</code> disregard the
|
||||
* Note the normal subclasses of <code>DefaultFilterInvocationDefinitionSource</code> disregard the
|
||||
* <code>contextPath</code> when evaluating which secure object metadata applies to a given
|
||||
* <code>FilterInvocation</code>, so generally the <code>contextPath</code> is unimportant unless you are using a
|
||||
* custom <code>FilterInvocationDefinitionSource</code>.
|
||||
|
@ -132,6 +132,10 @@ intercept-url.attlist &=
|
||||
intercept-url.attlist &=
|
||||
## The access configuration attributes that apply for the configured path.
|
||||
attribute access {xsd:string}?
|
||||
intercept-url.attlist &=
|
||||
## The HTTP Method for which the access configuration attributes should apply. If not specified, the attributes will apply to any method.
|
||||
attribute method {"GET" | "PUT" | "POST" | "DELETE"}?
|
||||
|
||||
intercept-url.attlist &=
|
||||
## The filter list for the path. Currently can be set to "none" to remove a path from having any filters applied. The full filter stack (consisting of all defined filters, will be applied to any other paths).
|
||||
attribute filters {"none"}?
|
||||
|
@ -355,6 +355,19 @@
|
||||
<xs:documentation>The access configuration attributes that apply for the configured path.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="method">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The HTTP Method for which the access configuration attributes should apply. If not specified, the attributes will apply to any method.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="GET"/>
|
||||
<xs:enumeration value="PUT"/>
|
||||
<xs:enumeration value="POST"/>
|
||||
<xs:enumeration value="DELETE"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="filters">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The filter list for the path. Currently can be set to "none" to remove a path from having any filters applied. The full filter stack (consisting of all defined filters, will be applied to any other paths).</xs:documentation>
|
||||
|
@ -132,15 +132,32 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
|
||||
|
||||
FilterInvocationDefinitionSource fids = fis.getObjectDefinitionSource();
|
||||
ConfigAttributeDefinition attrs = fids.getAttributes(createFilterinvocation("/Secure"));
|
||||
ConfigAttributeDefinition attrs = fids.getAttributes(createFilterinvocation("/Secure", null));
|
||||
assertEquals(2, attrs.size());
|
||||
assertTrue(attrs.contains(new SecurityConfig("ROLE_A")));
|
||||
assertTrue(attrs.contains(new SecurityConfig("ROLE_B")));
|
||||
attrs = fids.getAttributes(createFilterinvocation("/secure"));
|
||||
attrs = fids.getAttributes(createFilterinvocation("/secure", null));
|
||||
assertEquals(1, attrs.size());
|
||||
assertTrue(attrs.contains(new SecurityConfig("ROLE_C")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpMethodMatchIsSupported() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true'>" +
|
||||
" <intercept-url pattern='/**' access='ROLE_C' />" +
|
||||
" <intercept-url pattern='/secure*' method='DELETE' access='ROLE_SUPERVISOR' />" +
|
||||
" <intercept-url pattern='/secure*' method='POST' access='ROLE_A,ROLE_B' />" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
|
||||
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
|
||||
FilterInvocationDefinitionSource fids = fis.getObjectDefinitionSource();
|
||||
ConfigAttributeDefinition attrs = fids.getAttributes(createFilterinvocation("/secure", "POST"));
|
||||
assertEquals(2, attrs.size());
|
||||
assertTrue(attrs.contains(new SecurityConfig("ROLE_A")));
|
||||
assertTrue(attrs.contains(new SecurityConfig("ROLE_B")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minimalConfigurationParses() {
|
||||
setContext("<http><http-basic /></http>" + AUTH_PROVIDER_XML);
|
||||
@ -213,8 +230,9 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
return (FilterChainProxy) appContext.getBean(BeanIds.FILTER_CHAIN_PROXY);
|
||||
}
|
||||
|
||||
private FilterInvocation createFilterinvocation(String path) {
|
||||
private FilterInvocation createFilterinvocation(String path, String method) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod(method);
|
||||
request.setRequestURI(null);
|
||||
|
||||
request.setServletPath(path);
|
||||
|
@ -29,7 +29,7 @@ import javax.servlet.ServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link AbstractFilterInvocationDefinitionSource}.
|
||||
* Tests {@link DefaultFilterInvocationDefinitionSource}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
|
@ -20,6 +20,7 @@ import junit.framework.TestCase;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.MockFilterChain;
|
||||
import org.springframework.security.SecurityConfig;
|
||||
import org.springframework.security.util.RegexUrlPathMatcher;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
@ -51,7 +52,7 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
|
||||
FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
|
||||
editor.setAsText("\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE\r\n\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER");
|
||||
|
||||
RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
assertFalse(map.isConvertUrlToLowercaseBeforeComparison());
|
||||
}
|
||||
|
||||
@ -72,7 +73,7 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
|
||||
editor.setAsText(
|
||||
"CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON\r\n\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE\r\n\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER");
|
||||
|
||||
RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
assertTrue(map.isConvertUrlToLowercaseBeforeComparison());
|
||||
}
|
||||
|
||||
@ -80,8 +81,8 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
|
||||
FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
|
||||
editor.setAsText("\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE\r\n\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER");
|
||||
|
||||
FilterInvocationDefinitionMap map = (FilterInvocationDefinitionMap) editor.getValue();
|
||||
assertTrue(map instanceof RegExpBasedFilterInvocationDefinitionMap);
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
assertTrue(map.getUrlMatcher() instanceof RegexUrlPathMatcher);
|
||||
}
|
||||
|
||||
public void testDetectsDuplicateDirectivesOnSameLineSituation1() {
|
||||
@ -124,7 +125,7 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
|
||||
FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
|
||||
editor.setAsText("");
|
||||
|
||||
RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
assertEquals(0, map.getMapSize());
|
||||
}
|
||||
|
||||
@ -142,7 +143,7 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
|
||||
FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
|
||||
editor.setAsText("\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE\r\n\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER");
|
||||
|
||||
RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
Iterator iter = map.getConfigAttributeDefinitions();
|
||||
int counter = 0;
|
||||
|
||||
@ -158,7 +159,7 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
|
||||
FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
|
||||
editor.setAsText("\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE,ANOTHER_ROLE");
|
||||
|
||||
RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
|
||||
MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
|
||||
httpRequest.setServletPath("/totally/different/path/index.html");
|
||||
@ -173,7 +174,7 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
|
||||
FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
|
||||
editor.setAsText("\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE\r\n\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER");
|
||||
|
||||
RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
assertEquals(2, map.getMapSize());
|
||||
}
|
||||
|
||||
@ -181,7 +182,7 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
|
||||
FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
|
||||
editor.setAsText(null);
|
||||
|
||||
RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
assertEquals(0, map.getMapSize());
|
||||
}
|
||||
|
||||
@ -190,7 +191,7 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
|
||||
editor.setAsText(
|
||||
"\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE,ANOTHER_ROLE\r\n\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER");
|
||||
|
||||
RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
|
||||
// Test ensures we match the first entry, not the second
|
||||
MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
|
||||
@ -211,7 +212,7 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
|
||||
editor.setAsText(
|
||||
"\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER\r\n\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE,ANOTHER_ROLE");
|
||||
|
||||
RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
|
||||
MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
|
||||
httpRequest.setServletPath("/secure/super/very_secret.html");
|
||||
@ -230,7 +231,7 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
|
||||
FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
|
||||
editor.setAsText("\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE,ANOTHER_ROLE");
|
||||
|
||||
RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
|
||||
MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
|
||||
httpRequest.setServletPath("/secure/super/very_secret.html");
|
||||
@ -249,7 +250,7 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
|
||||
FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
|
||||
editor.setAsText("PATTERN_TYPE_APACHE_ANT\r\n/secure/super/**=ROLE_WE_DONT_HAVE,ANOTHER_ROLE");
|
||||
|
||||
PathBasedFilterInvocationDefinitionMap map = (PathBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
|
||||
MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
|
||||
httpRequest.setServletPath("/secure/super/very_secret.html");
|
||||
@ -269,7 +270,7 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
|
||||
editor.setAsText(
|
||||
" \\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE,ANOTHER_ROLE \r\n \r\n \r\n // comment line \r\n \\A/testing.*\\Z=ROLE_TEST \r\n");
|
||||
|
||||
RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
assertEquals(2, map.getMapSize());
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import junit.framework.TestCase;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.MockFilterChain;
|
||||
import org.springframework.security.SecurityConfig;
|
||||
import org.springframework.security.util.AntUrlPathMatcher;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
@ -52,8 +53,8 @@ public class FilterInvocationDefinitionSourceEditorWithPathsTests extends TestCa
|
||||
editor.setAsText(
|
||||
"PATTERN_TYPE_APACHE_ANT\r\n/secure/super/*=ROLE_WE_DONT_HAVE\r\n/secure/*=ROLE_SUPERVISOR,ROLE_TELLER");
|
||||
|
||||
FilterInvocationDefinitionMap map = (FilterInvocationDefinitionMap) editor.getValue();
|
||||
assertTrue(map instanceof PathBasedFilterInvocationDefinitionMap);
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
assertTrue(map.getUrlMatcher() instanceof AntUrlPathMatcher);
|
||||
}
|
||||
|
||||
public void testConvertUrlToLowercaseDefaultSettingUnchangedByEditor() {
|
||||
@ -61,8 +62,8 @@ public class FilterInvocationDefinitionSourceEditorWithPathsTests extends TestCa
|
||||
editor.setAsText(
|
||||
"PATTERN_TYPE_APACHE_ANT\r\n/secure/super/*=ROLE_WE_DONT_HAVE\r\n/secure/*=ROLE_SUPERVISOR,ROLE_TELLER");
|
||||
|
||||
PathBasedFilterInvocationDefinitionMap map = (PathBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
assertFalse(map.isConvertUrlToLowercaseBeforeComparison());
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
assertFalse(map.getUrlMatcher().requiresLowerCaseUrl());
|
||||
}
|
||||
|
||||
public void testConvertUrlToLowercaseSettingApplied() {
|
||||
@ -70,8 +71,8 @@ public class FilterInvocationDefinitionSourceEditorWithPathsTests extends TestCa
|
||||
editor.setAsText(
|
||||
"CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON\r\nPATTERN_TYPE_APACHE_ANT\r\n/secure/super/*=ROLE_WE_DONT_HAVE\r\n/secure/*=ROLE_SUPERVISOR,ROLE_TELLER");
|
||||
|
||||
PathBasedFilterInvocationDefinitionMap map = (PathBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
assertTrue(map.isConvertUrlToLowercaseBeforeComparison());
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
assertTrue(map.getUrlMatcher().requiresLowerCaseUrl());
|
||||
}
|
||||
|
||||
public void testInvalidNameValueFailsToParse() {
|
||||
@ -89,7 +90,7 @@ public class FilterInvocationDefinitionSourceEditorWithPathsTests extends TestCa
|
||||
editor.setAsText(
|
||||
"PATTERN_TYPE_APACHE_ANT\r\n/secure/super/*=ROLE_WE_DONT_HAVE\r\n/secure/*=ROLE_SUPERVISOR,ROLE_TELLER");
|
||||
|
||||
PathBasedFilterInvocationDefinitionMap map = (PathBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
Iterator iter = map.getConfigAttributeDefinitions();
|
||||
int counter = 0;
|
||||
|
||||
@ -105,7 +106,7 @@ public class FilterInvocationDefinitionSourceEditorWithPathsTests extends TestCa
|
||||
FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
|
||||
editor.setAsText("PATTERN_TYPE_APACHE_ANT\r\n/secure/super/*=ROLE_WE_DONT_HAVE");
|
||||
|
||||
PathBasedFilterInvocationDefinitionMap map = (PathBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
|
||||
MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
|
||||
httpRequest.setServletPath("/totally/different/path/index.html");
|
||||
@ -121,7 +122,7 @@ public class FilterInvocationDefinitionSourceEditorWithPathsTests extends TestCa
|
||||
editor.setAsText(
|
||||
"PATTERN_TYPE_APACHE_ANT\r\n/secure/super/*=ROLE_WE_DONT_HAVE\r\n/secure/*=ROLE_SUPERVISOR,ROLE_TELLER");
|
||||
|
||||
PathBasedFilterInvocationDefinitionMap map = (PathBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
assertEquals(2, map.getMapSize());
|
||||
}
|
||||
|
||||
@ -130,7 +131,7 @@ public class FilterInvocationDefinitionSourceEditorWithPathsTests extends TestCa
|
||||
editor.setAsText(
|
||||
"PATTERN_TYPE_APACHE_ANT\r\n/secure/super/**=ROLE_WE_DONT_HAVE,ANOTHER_ROLE\r\n/secure/**=ROLE_SUPERVISOR,ROLE_TELLER");
|
||||
|
||||
PathBasedFilterInvocationDefinitionMap map = (PathBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
|
||||
// Test ensures we match the first entry, not the second
|
||||
MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
|
||||
@ -151,7 +152,7 @@ public class FilterInvocationDefinitionSourceEditorWithPathsTests extends TestCa
|
||||
editor.setAsText(
|
||||
"PATTERN_TYPE_APACHE_ANT\r\n/secure/**=ROLE_SUPERVISOR,ROLE_TELLER\r\n/secure/super/**=ROLE_WE_DONT_HAVE");
|
||||
|
||||
PathBasedFilterInvocationDefinitionMap map = (PathBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
|
||||
MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
|
||||
httpRequest.setServletPath("/secure/super/very_secret.html");
|
||||
@ -170,7 +171,7 @@ public class FilterInvocationDefinitionSourceEditorWithPathsTests extends TestCa
|
||||
FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
|
||||
editor.setAsText("PATTERN_TYPE_APACHE_ANT\r\n/secure/super/*=ROLE_WE_DONT_HAVE,ANOTHER_ROLE");
|
||||
|
||||
PathBasedFilterInvocationDefinitionMap map = (PathBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
|
||||
MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
|
||||
httpRequest.setServletPath("/secure/super/very_secret.html");
|
||||
@ -190,7 +191,7 @@ public class FilterInvocationDefinitionSourceEditorWithPathsTests extends TestCa
|
||||
editor.setAsText(
|
||||
" PATTERN_TYPE_APACHE_ANT\r\n /secure/super/*=ROLE_WE_DONT_HAVE\r\n /secure/*=ROLE_SUPERVISOR,ROLE_TELLER \r\n \r\n \r\n // comment line \r\n \r\n");
|
||||
|
||||
PathBasedFilterInvocationDefinitionMap map = (PathBasedFilterInvocationDefinitionMap) editor.getValue();
|
||||
DefaultFilterInvocationDefinitionSource map = (DefaultFilterInvocationDefinitionSource) editor.getValue();
|
||||
assertEquals(2, map.getMapSize());
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ import java.util.Vector;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class MockFilterInvocationDefinitionSource extends AbstractFilterInvocationDefinitionSource {
|
||||
public class MockFilterInvocationDefinitionSource extends DefaultFilterInvocationDefinitionSource {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private List list;
|
||||
@ -77,7 +77,7 @@ public class MockFilterInvocationDefinitionSource extends AbstractFilterInvocati
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigAttributeDefinition lookupAttributes(String url) {
|
||||
public ConfigAttributeDefinition lookupAttributes(String url, String method) {
|
||||
throw new UnsupportedOperationException("mock method not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,6 @@
|
||||
|
||||
package org.springframework.security.intercept.web;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.MockFilterChain;
|
||||
import org.springframework.security.SecurityConfig;
|
||||
@ -24,6 +22,9 @@ import org.springframework.security.SecurityConfig;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests parts of {@link PathBasedFilterInvocationDefinitionMap} not tested by {@link
|
||||
@ -32,30 +33,25 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class PathBasedFilterDefinitionMapTests extends TestCase {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public PathBasedFilterDefinitionMapTests() {
|
||||
}
|
||||
|
||||
public PathBasedFilterDefinitionMapTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
public class PathBasedFilterInvocationDefinitionMapTests {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void testConvertUrlToLowercaseIsTrueByDefault() {
|
||||
@Test
|
||||
public void convertUrlToLowercaseIsTrueByDefault() {
|
||||
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
|
||||
assertTrue(map.isConvertUrlToLowercaseBeforeComparison());
|
||||
}
|
||||
|
||||
public void testConvertUrlToLowercaseSetterRespected() {
|
||||
@Test
|
||||
public void convertUrlToLowercaseSetterRespected() {
|
||||
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
|
||||
map.setConvertUrlToLowercaseBeforeComparison(false);
|
||||
assertFalse(map.isConvertUrlToLowercaseBeforeComparison());
|
||||
}
|
||||
|
||||
public void testLookupNotRequiringExactMatchSuccessIfNotMatching() {
|
||||
@Test
|
||||
public void lookupNotRequiringExactMatchSuccessIfNotMatching() {
|
||||
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
|
||||
map.setConvertUrlToLowercaseBeforeComparison(true);
|
||||
|
||||
@ -63,90 +59,146 @@ public class PathBasedFilterDefinitionMapTests extends TestCase {
|
||||
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
|
||||
map.addSecureUrl("/secure/super/**", def);
|
||||
|
||||
FilterInvocation fi = createFilterinvocation("/SeCuRE/super/somefile.html");
|
||||
FilterInvocation fi = createFilterInvocation("/SeCuRE/super/somefile.html", null);
|
||||
|
||||
ConfigAttributeDefinition response = map.lookupAttributes(fi.getRequestUrl());
|
||||
assertEquals(def, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* SEC-501. Not that as of 2.0, lower case comparisons are the default for this class.
|
||||
* SEC-501. Note that as of 2.0, lower case comparisons are the default for this class.
|
||||
*/
|
||||
public void testLookupNotRequiringExactMatchSucceedsIfSecureUrlPathContainsUpperCase() {
|
||||
@Test
|
||||
public void lookupNotRequiringExactMatchSucceedsIfSecureUrlPathContainsUpperCase() {
|
||||
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
|
||||
|
||||
ConfigAttributeDefinition def = new ConfigAttributeDefinition();
|
||||
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
|
||||
map.addSecureUrl("/SeCuRE/super/**", def);
|
||||
|
||||
FilterInvocation fi = createFilterinvocation("/secure/super/somefile.html");
|
||||
FilterInvocation fi = createFilterInvocation("/secure/super/somefile.html", null);
|
||||
|
||||
ConfigAttributeDefinition response = map.lookupAttributes(fi.getRequestUrl());
|
||||
assertEquals(def, response);
|
||||
}
|
||||
|
||||
|
||||
public void testLookupRequiringExactMatchFailsIfNotMatching() {
|
||||
@Test
|
||||
public void lookupRequiringExactMatchFailsIfNotMatching() {
|
||||
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
|
||||
map.setConvertUrlToLowercaseBeforeComparison(false);
|
||||
ConfigAttributeDefinition def = new ConfigAttributeDefinition();
|
||||
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
|
||||
map.addSecureUrl("/secure/super/**", def);
|
||||
|
||||
FilterInvocation fi = createFilterinvocation("/SeCuRE/super/somefile.html");
|
||||
FilterInvocation fi = createFilterInvocation("/SeCuRE/super/somefile.html", null);
|
||||
|
||||
ConfigAttributeDefinition response = map.lookupAttributes(fi.getRequestUrl());
|
||||
assertEquals(null, response);
|
||||
}
|
||||
|
||||
public void testLookupRequiringExactMatchIsSuccessful() {
|
||||
@Test
|
||||
public void lookupRequiringExactMatchIsSuccessful() {
|
||||
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
|
||||
map.setConvertUrlToLowercaseBeforeComparison(false);
|
||||
ConfigAttributeDefinition def = new ConfigAttributeDefinition();
|
||||
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
|
||||
map.addSecureUrl("/SeCurE/super/**", def);
|
||||
|
||||
FilterInvocation fi = createFilterinvocation("/SeCurE/super/somefile.html");
|
||||
FilterInvocation fi = createFilterInvocation("/SeCurE/super/somefile.html", null);
|
||||
|
||||
ConfigAttributeDefinition response = map.lookupAttributes(fi.getRequestUrl());
|
||||
assertEquals(def, response);
|
||||
}
|
||||
|
||||
public void testLookupRequiringExactMatchWithAdditionalSlashesIsSuccessful() {
|
||||
@Test
|
||||
public void lookupRequiringExactMatchWithAdditionalSlashesIsSuccessful() {
|
||||
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
|
||||
ConfigAttributeDefinition def = new ConfigAttributeDefinition();
|
||||
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
|
||||
map.addSecureUrl("/someAdminPage.html**", def);
|
||||
|
||||
FilterInvocation fi = createFilterinvocation("/someAdminPage.html?a=/test");
|
||||
FilterInvocation fi = createFilterInvocation("/someAdminPage.html?a=/test", null);
|
||||
|
||||
ConfigAttributeDefinition response = map.lookupAttributes(fi.getRequestUrl());
|
||||
assertEquals(def, response); // see SEC-161 (it should truncate after ? sign)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void unknownHttpMethodIsRejected() {
|
||||
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
|
||||
ConfigAttributeDefinition def = new ConfigAttributeDefinition();
|
||||
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
|
||||
map.addSecureUrl("/someAdminPage.html**", "UNKNOWN", def);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpMethodLookupSucceeds() {
|
||||
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
|
||||
ConfigAttributeDefinition def = new ConfigAttributeDefinition();
|
||||
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
|
||||
map.addSecureUrl("/somepage**", "GET", def);
|
||||
|
||||
FilterInvocation fi = createFilterInvocation("/somepage", "GET");
|
||||
ConfigAttributeDefinition attrs = map.getAttributes(fi);
|
||||
assertEquals(def, attrs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithDifferentHttpMethodDoesntMatch() {
|
||||
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
|
||||
ConfigAttributeDefinition def = new ConfigAttributeDefinition();
|
||||
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
|
||||
map.addSecureUrl("/somepage**", "GET", def);
|
||||
|
||||
FilterInvocation fi = createFilterInvocation("/somepage", null);
|
||||
ConfigAttributeDefinition attrs = map.getAttributes(fi);
|
||||
assertNull(attrs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpMethodSpecificUrlTakesPrecedence() {
|
||||
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
|
||||
|
||||
// Even though this is added before the method-specific def, the latter should match
|
||||
ConfigAttributeDefinition allMethodDef = new ConfigAttributeDefinition();
|
||||
allMethodDef.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
|
||||
map.addSecureUrl("/**", null, allMethodDef);
|
||||
|
||||
ConfigAttributeDefinition postOnlyDef = new ConfigAttributeDefinition();
|
||||
postOnlyDef.addConfigAttribute(new SecurityConfig("ROLE_TWO"));
|
||||
map.addSecureUrl("/somepage**", "POST", postOnlyDef);
|
||||
|
||||
FilterInvocation fi = createFilterInvocation("/somepage", "POST");
|
||||
ConfigAttributeDefinition attrs = map.getAttributes(fi);
|
||||
assertEquals(postOnlyDef, attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check fixes for SEC-321
|
||||
*/
|
||||
public void testExtraQuestionMarkStillMatches() {
|
||||
@Test
|
||||
public void extraQuestionMarkStillMatches() {
|
||||
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
|
||||
ConfigAttributeDefinition def = new ConfigAttributeDefinition();
|
||||
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
|
||||
map.addSecureUrl("/someAdminPage.html*", def);
|
||||
|
||||
FilterInvocation fi = createFilterinvocation("/someAdminPage.html?x=2/aa?y=3");
|
||||
FilterInvocation fi = createFilterInvocation("/someAdminPage.html?x=2/aa?y=3", null);
|
||||
|
||||
ConfigAttributeDefinition response = map.lookupAttributes(fi.getRequestUrl());
|
||||
assertEquals(def, response);
|
||||
|
||||
fi = createFilterinvocation("/someAdminPage.html??");
|
||||
fi = createFilterInvocation("/someAdminPage.html??", null);
|
||||
|
||||
response = map.lookupAttributes(fi.getRequestUrl());
|
||||
assertEquals(def, response);
|
||||
}
|
||||
|
||||
private FilterInvocation createFilterinvocation(String path) {
|
||||
private FilterInvocation createFilterInvocation(String path, String method) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI(null);
|
||||
request.setMethod(method);
|
||||
|
||||
request.setServletPath(path);
|
||||
|
Loading…
x
Reference in New Issue
Block a user