Browse Source

Default AntPathRequestMatcher to be case sensitive

Issue gh-3831
pull/3840/head
Rob Winch 10 years ago
parent
commit
7fe0a135ec
  1. 92
      config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy
  2. 4
      config/src/test/groovy/org/springframework/security/config/http/PlaceHolderAndELConfigTests.groovy
  3. 5
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java
  4. 2
      web/src/main/java/org/springframework/security/web/util/matcher/AntPathRequestMatcher.java
  5. 52
      web/src/test/java/org/springframework/security/web/access/intercept/DefaultFilterInvocationSecurityMetadataSourceTests.java
  6. 12
      web/src/test/java/org/springframework/security/web/util/matcher/AntPathRequestMatcherTests.java

92
config/src/test/groovy/org/springframework/security/config/http/MiscHttpConfigTests.groovy

@ -136,17 +136,17 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
} }
def debugFilterHandlesMissingAndEmptyFilterChains() { def debugFilterHandlesMissingAndEmptyFilterChains() {
when: when:
xml.debug() xml.debug()
xml.http(pattern: '/unprotected', security: 'none') xml.http(pattern: '/unprotected', security: 'none')
createAppContext() createAppContext()
then: then:
Filter debugFilter = appContext.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN); Filter debugFilter = appContext.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
MockHttpServletRequest request = new MockHttpServletRequest() MockHttpServletRequest request = new MockHttpServletRequest()
request.setServletPath("/unprotected"); request.setServletPath("/unprotected");
debugFilter.doFilter(request, new MockHttpServletResponse(), new MockFilterChain()); debugFilter.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());
request.setServletPath("/nomatch"); request.setServletPath("/nomatch");
debugFilter.doFilter(request, new MockHttpServletResponse(), new MockFilterChain()); debugFilter.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());
} }
def regexPathsWorkCorrectly() { def regexPathsWorkCorrectly() {
@ -254,39 +254,39 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
attrs.contains(new SecurityConfig("ROLE_B")) attrs.contains(new SecurityConfig("ROLE_B"))
} }
def httpMethodMatchIsSupportedForRequiresChannel() { def httpMethodMatchIsSupportedForRequiresChannel() {
httpAutoConfig { httpAutoConfig {
'intercept-url'(pattern: '/anyurl') 'intercept-url'(pattern: '/anyurl')
'intercept-url'(pattern: '/anyurl', 'method':'GET',access: 'ROLE_ADMIN', 'requires-channel': 'https') 'intercept-url'(pattern: '/anyurl', 'method':'GET',access: 'ROLE_ADMIN', 'requires-channel': 'https')
} }
createAppContext() createAppContext()
def fids = getFilter(ChannelProcessingFilter).getSecurityMetadataSource(); def fids = getFilter(ChannelProcessingFilter).getSecurityMetadataSource();
def attrs = fids.getAttributes(createFilterinvocation("/anyurl", "GET")); def attrs = fids.getAttributes(createFilterinvocation("/anyurl", "GET"));
def attrsPost = fids.getAttributes(createFilterinvocation("/anyurl", "POST")); def attrsPost = fids.getAttributes(createFilterinvocation("/anyurl", "POST"));
expect: expect:
attrs.size() == 1 attrs.size() == 1
attrs.contains(new SecurityConfig("REQUIRES_SECURE_CHANNEL")) attrs.contains(new SecurityConfig("REQUIRES_SECURE_CHANNEL"))
attrsPost == null attrsPost == null
} }
def httpMethodMatchIsSupportedForRequiresChannelAny() { def httpMethodMatchIsSupportedForRequiresChannelAny() {
httpAutoConfig { httpAutoConfig {
'intercept-url'(pattern: '/**') 'intercept-url'(pattern: '/**')
'intercept-url'(pattern: '/**', 'method':'GET',access: 'ROLE_ADMIN', 'requires-channel': 'https') 'intercept-url'(pattern: '/**', 'method':'GET',access: 'ROLE_ADMIN', 'requires-channel': 'https')
} }
createAppContext() createAppContext()
def fids = getFilter(ChannelProcessingFilter).getSecurityMetadataSource(); def fids = getFilter(ChannelProcessingFilter).getSecurityMetadataSource();
def attrs = fids.getAttributes(createFilterinvocation("/anyurl", "GET")); def attrs = fids.getAttributes(createFilterinvocation("/anyurl", "GET"));
def attrsPost = fids.getAttributes(createFilterinvocation("/anyurl", "POST")); def attrsPost = fids.getAttributes(createFilterinvocation("/anyurl", "POST"));
expect: expect:
attrs.size() == 1 attrs.size() == 1
attrs.contains(new SecurityConfig("REQUIRES_SECURE_CHANNEL")) attrs.contains(new SecurityConfig("REQUIRES_SECURE_CHANNEL"))
attrsPost == null attrsPost == null
} }
def oncePerRequestAttributeIsSupported() { def oncePerRequestAttributeIsSupported() {
xml.http('once-per-request': 'false') { xml.http('once-per-request': 'false') {
@ -498,7 +498,7 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
createAppContext() createAppContext()
def fis = getFilter(FilterSecurityInterceptor) def fis = getFilter(FilterSecurityInterceptor)
def fids = fis.securityMetadataSource def fids = fis.securityMetadataSource
Collection attrs = fids.getAttributes(createFilterinvocation("/someurl", null)); Collection attrs = fids.getAttributes(createFilterinvocation("/someUrl", null));
expect: expect:
attrs.size() == 1 attrs.size() == 1
@ -716,7 +716,7 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
def httpFirewallInjectionIsSupported() { def httpFirewallInjectionIsSupported() {
xml.'http-firewall'(ref: 'fw') xml.'http-firewall'(ref: 'fw')
xml.http() { xml.http() {
'form-login'() 'form-login'()
} }
bean('fw', DefaultHttpFirewall) bean('fw', DefaultHttpFirewall)
createAppContext() createAppContext()

4
config/src/test/groovy/org/springframework/security/config/http/PlaceHolderAndELConfigTests.groovy

@ -39,7 +39,7 @@ class PlaceHolderAndELConfigTests extends AbstractHttpConfigTests {
// SEC-1201 // SEC-1201
def interceptUrlsAndFormLoginSupportPropertyPlaceholders() { def interceptUrlsAndFormLoginSupportPropertyPlaceholders() {
System.setProperty("secure.Url", "/Secure"); System.setProperty("secure.Url", "/secure");
System.setProperty("secure.role", "ROLE_A"); System.setProperty("secure.role", "ROLE_A");
System.setProperty("login.page", "/loginPage"); System.setProperty("login.page", "/loginPage");
System.setProperty("default.target", "/defaultTarget"); System.setProperty("default.target", "/defaultTarget");
@ -60,7 +60,7 @@ class PlaceHolderAndELConfigTests extends AbstractHttpConfigTests {
// SEC-1309 // SEC-1309
def interceptUrlsAndFormLoginSupportEL() { def interceptUrlsAndFormLoginSupportEL() {
System.setProperty("secure.url", "/Secure"); System.setProperty("secure.url", "/secure");
System.setProperty("secure.role", "ROLE_A"); System.setProperty("secure.role", "ROLE_A");
System.setProperty("login.page", "/loginPage"); System.setProperty("login.page", "/loginPage");
System.setProperty("default.target", "/defaultTarget"); System.setProperty("default.target", "/defaultTarget");

5
config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java

@ -40,6 +40,7 @@ import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextImpl; import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -151,7 +152,7 @@ public class AuthorizeRequestsTests {
// @formatter:off // @formatter:off
http http
.authorizeRequests() .authorizeRequests()
.antMatchers("/user/{user}").access("#user == 'user'") .requestMatchers(new AntPathRequestMatcher("/user/{user}", null, false)).access("#user == 'user'")
.anyRequest().denyAll(); .anyRequest().denyAll();
// @formatter:on // @formatter:on
} }
@ -192,7 +193,7 @@ public class AuthorizeRequestsTests {
// @formatter:off // @formatter:off
http http
.authorizeRequests() .authorizeRequests()
.antMatchers("/user/{userName}").access("#userName == 'user'") .requestMatchers(new AntPathRequestMatcher("/user/{userName}", null, false)).access("#userName == 'user'")
.anyRequest().denyAll(); .anyRequest().denyAll();
// @formatter:on // @formatter:on
} }

2
web/src/main/java/org/springframework/security/web/util/matcher/AntPathRequestMatcher.java

@ -80,7 +80,7 @@ public final class AntPathRequestMatcher implements RequestMatcher {
* the incoming request doesn't have the same method. * the incoming request doesn't have the same method.
*/ */
public AntPathRequestMatcher(String pattern, String httpMethod) { public AntPathRequestMatcher(String pattern, String httpMethod) {
this(pattern, httpMethod, false); this(pattern, httpMethod, true);
} }
/** /**

52
web/src/test/java/org/springframework/security/web/access/intercept/DefaultFilterInvocationSecurityMetadataSourceTests.java

@ -16,15 +16,13 @@
package org.springframework.security.web.access.intercept; package org.springframework.security.web.access.intercept;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.mock;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import org.junit.Test; import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.ConfigAttribute;
@ -33,6 +31,9 @@ import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/** /**
* Tests {@link DefaultFilterInvocationSecurityMetadataSource}. * Tests {@link DefaultFilterInvocationSecurityMetadataSource}.
* *
@ -46,18 +47,18 @@ public class DefaultFilterInvocationSecurityMetadataSourceTests {
// ======================================================================================================== // ========================================================================================================
private void createFids(String pattern, String method) { private void createFids(String pattern, String method) {
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>(); LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
requestMap.put(new AntPathRequestMatcher(pattern, method), def); requestMap.put(new AntPathRequestMatcher(pattern, method), this.def);
fids = new DefaultFilterInvocationSecurityMetadataSource(requestMap); this.fids = new DefaultFilterInvocationSecurityMetadataSource(requestMap);
} }
@Test @Test
public void lookupNotRequiringExactMatchSucceedsIfNotMatching() { public void lookupNotRequiringExactMatchSucceedsIfNotMatching() {
createFids("/secure/super/**", null); createFids("/secure/super/**", null);
FilterInvocation fi = createFilterInvocation("/SeCuRE/super/somefile.html", null, FilterInvocation fi = createFilterInvocation("/secure/super/somefile.html", null,
null, null); null, null);
assertThat(fids.getAttributes(fi)).isEqualTo(def); assertThat(this.fids.getAttributes(fi)).isEqualTo(this.def);
} }
/** /**
@ -66,13 +67,13 @@ public class DefaultFilterInvocationSecurityMetadataSourceTests {
*/ */
@Test @Test
public void lookupNotRequiringExactMatchSucceedsIfSecureUrlPathContainsUpperCase() { public void lookupNotRequiringExactMatchSucceedsIfSecureUrlPathContainsUpperCase() {
createFids("/SeCuRE/super/**", null); createFids("/secure/super/**", null);
FilterInvocation fi = createFilterInvocation("/secure", "/super/somefile.html", FilterInvocation fi = createFilterInvocation("/secure", "/super/somefile.html",
null, null); null, null);
Collection<ConfigAttribute> response = fids.getAttributes(fi); Collection<ConfigAttribute> response = this.fids.getAttributes(fi);
assertThat(response).isEqualTo(def); assertThat(response).isEqualTo(this.def);
} }
@Test @Test
@ -82,8 +83,8 @@ public class DefaultFilterInvocationSecurityMetadataSourceTests {
FilterInvocation fi = createFilterInvocation("/SeCurE/super/somefile.html", null, FilterInvocation fi = createFilterInvocation("/SeCurE/super/somefile.html", null,
null, null); null, null);
Collection<ConfigAttribute> response = fids.getAttributes(fi); Collection<ConfigAttribute> response = this.fids.getAttributes(fi);
assertThat(response).isEqualTo(def); assertThat(response).isEqualTo(this.def);
} }
@Test @Test
@ -93,8 +94,9 @@ public class DefaultFilterInvocationSecurityMetadataSourceTests {
FilterInvocation fi = createFilterInvocation("/someAdminPage.html", null, FilterInvocation fi = createFilterInvocation("/someAdminPage.html", null,
"a=/test", null); "a=/test", null);
Collection<ConfigAttribute> response = fids.getAttributes(fi); Collection<ConfigAttribute> response = this.fids.getAttributes(fi);
assertThat(response); // see SEC-161 (it should truncate after ? sign).isEqualTo(def) assertThat(response); // see SEC-161 (it should truncate after ?
// sign).isEqualTo(def)
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
@ -107,8 +109,8 @@ public class DefaultFilterInvocationSecurityMetadataSourceTests {
createFids("/somepage**", "GET"); createFids("/somepage**", "GET");
FilterInvocation fi = createFilterInvocation("/somepage", null, null, "GET"); FilterInvocation fi = createFilterInvocation("/somepage", null, null, "GET");
Collection<ConfigAttribute> attrs = fids.getAttributes(fi); Collection<ConfigAttribute> attrs = this.fids.getAttributes(fi);
assertThat(attrs).isEqualTo(def); assertThat(attrs).isEqualTo(this.def);
} }
@Test @Test
@ -116,8 +118,8 @@ public class DefaultFilterInvocationSecurityMetadataSourceTests {
createFids("/somepage**", null); createFids("/somepage**", null);
FilterInvocation fi = createFilterInvocation("/somepage", null, null, "GET"); FilterInvocation fi = createFilterInvocation("/somepage", null, null, "GET");
Collection<ConfigAttribute> attrs = fids.getAttributes(fi); Collection<ConfigAttribute> attrs = this.fids.getAttributes(fi);
assertThat(attrs).isEqualTo(def); assertThat(attrs).isEqualTo(this.def);
} }
@Test @Test
@ -125,7 +127,7 @@ public class DefaultFilterInvocationSecurityMetadataSourceTests {
createFids("/somepage**", "GET"); createFids("/somepage**", "GET");
FilterInvocation fi = createFilterInvocation("/somepage", null, null, "POST"); FilterInvocation fi = createFilterInvocation("/somepage", null, null, "POST");
Collection<ConfigAttribute> attrs = fids.getAttributes(fi); Collection<ConfigAttribute> attrs = this.fids.getAttributes(fi);
assertThat(attrs).isNull(); assertThat(attrs).isNull();
} }
@ -138,10 +140,10 @@ public class DefaultFilterInvocationSecurityMetadataSourceTests {
requestMap.put(new AntPathRequestMatcher("/user/**", null), userAttrs); requestMap.put(new AntPathRequestMatcher("/user/**", null), userAttrs);
requestMap.put(new AntPathRequestMatcher("/teller/**", "GET"), requestMap.put(new AntPathRequestMatcher("/teller/**", "GET"),
SecurityConfig.createList("B")); SecurityConfig.createList("B"));
fids = new DefaultFilterInvocationSecurityMetadataSource(requestMap); this.fids = new DefaultFilterInvocationSecurityMetadataSource(requestMap);
FilterInvocation fi = createFilterInvocation("/user", null, null, "GET"); FilterInvocation fi = createFilterInvocation("/user", null, null, "GET");
Collection<ConfigAttribute> attrs = fids.getAttributes(fi); Collection<ConfigAttribute> attrs = this.fids.getAttributes(fi);
assertThat(attrs).isEqualTo(userAttrs); assertThat(attrs).isEqualTo(userAttrs);
} }
@ -155,13 +157,13 @@ public class DefaultFilterInvocationSecurityMetadataSourceTests {
FilterInvocation fi = createFilterInvocation("/someAdminPage.html", null, null, FilterInvocation fi = createFilterInvocation("/someAdminPage.html", null, null,
null); null);
Collection<ConfigAttribute> response = fids.getAttributes(fi); Collection<ConfigAttribute> response = this.fids.getAttributes(fi);
assertThat(response).isEqualTo(def); assertThat(response).isEqualTo(this.def);
fi = createFilterInvocation("/someAdminPage.html", null, "?", null); fi = createFilterInvocation("/someAdminPage.html", null, "?", null);
response = fids.getAttributes(fi); response = this.fids.getAttributes(fi);
assertThat(response).isEqualTo(def); assertThat(response).isEqualTo(this.def);
} }
private FilterInvocation createFilterInvocation(String servletPath, String pathInfo, private FilterInvocation createFilterInvocation(String servletPath, String pathInfo,

12
web/src/test/java/org/springframework/security/web/util/matcher/AntPathRequestMatcherTests.java

@ -52,7 +52,8 @@ public class AntPathRequestMatcherTests {
@Test @Test
public void trailingWildcardMatchesCorrectly() { public void trailingWildcardMatchesCorrectly() {
AntPathRequestMatcher matcher = new AntPathRequestMatcher("/blah/blAh/**"); AntPathRequestMatcher matcher = new AntPathRequestMatcher("/blah/blAh/**", null,
false);
assertThat(matcher.matches(createRequest("/BLAH/blah"))).isTrue(); assertThat(matcher.matches(createRequest("/BLAH/blah"))).isTrue();
assertThat(matcher.matches(createRequest("/blah/bleh"))).isFalse(); assertThat(matcher.matches(createRequest("/blah/bleh"))).isFalse();
assertThat(matcher.matches(createRequest("/blah/blah/"))).isTrue(); assertThat(matcher.matches(createRequest("/blah/blah/"))).isTrue();
@ -64,11 +65,11 @@ public class AntPathRequestMatcherTests {
request.setPathInfo("blah/bleh"); request.setPathInfo("blah/bleh");
assertThat(matcher.matches(request)).isTrue(); assertThat(matcher.matches(request)).isTrue();
matcher = new AntPathRequestMatcher("/bl?h/blAh/**"); matcher = new AntPathRequestMatcher("/bl?h/blAh/**", null, false);
assertThat(matcher.matches(createRequest("/BLAH/Blah/aaa/"))).isTrue(); assertThat(matcher.matches(createRequest("/BLAH/Blah/aaa/"))).isTrue();
assertThat(matcher.matches(createRequest("/bleh/Blah"))).isTrue(); assertThat(matcher.matches(createRequest("/bleh/Blah"))).isTrue();
matcher = new AntPathRequestMatcher("/blAh/**/blah/**"); matcher = new AntPathRequestMatcher("/blAh/**/blah/**", null, false);
assertThat(matcher.matches(createRequest("/blah/blah"))).isTrue(); assertThat(matcher.matches(createRequest("/blah/blah"))).isTrue();
assertThat(matcher.matches(createRequest("/blah/bleh"))).isFalse(); assertThat(matcher.matches(createRequest("/blah/bleh"))).isFalse();
assertThat(matcher.matches(createRequest("/blah/aaa/blah/bbb"))).isTrue(); assertThat(matcher.matches(createRequest("/blah/aaa/blah/bbb"))).isTrue();
@ -76,7 +77,8 @@ public class AntPathRequestMatcherTests {
@Test @Test
public void trailingWildcardWithVariableMatchesCorrectly() { public void trailingWildcardWithVariableMatchesCorrectly() {
AntPathRequestMatcher matcher = new AntPathRequestMatcher("/{id}/blAh/**"); AntPathRequestMatcher matcher = new AntPathRequestMatcher("/{id}/blAh/**", null,
false);
assertThat(matcher.matches(createRequest("/1234/blah"))).isTrue(); assertThat(matcher.matches(createRequest("/1234/blah"))).isTrue();
assertThat(matcher.matches(createRequest("/4567/bleh"))).isFalse(); assertThat(matcher.matches(createRequest("/4567/bleh"))).isFalse();
assertThat(matcher.matches(createRequest("/paskos/blah/"))).isTrue(); assertThat(matcher.matches(createRequest("/paskos/blah/"))).isTrue();
@ -210,7 +212,7 @@ public class AntPathRequestMatcherTests {
@Test @Test
public void postProcessVariableNameCaseInsensitive() { public void postProcessVariableNameCaseInsensitive() {
AntPathRequestMatcher matcher = new AntPathRequestMatcher("/**"); AntPathRequestMatcher matcher = new AntPathRequestMatcher("/**", null, false);
String variableName = "userName"; String variableName = "userName";
assertThat(matcher.postProcessVariableName(variableName)) assertThat(matcher.postProcessVariableName(variableName))
.isEqualTo(variableName.toLowerCase()); .isEqualTo(variableName.toLowerCase());

Loading…
Cancel
Save