WebFlux now uses ParsingPathMatcher

Fixes gh-4388
This commit is contained in:
Rob Winch 2017-06-09 17:21:48 -05:00
parent 554768f1e4
commit 337317a060
7 changed files with 35 additions and 37 deletions

View File

@ -20,10 +20,6 @@ import org.springframework.security.web.server.util.matcher.OrServerWebExchangeM
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher; import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers; import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
@ -52,8 +48,8 @@ abstract class AbstractServerWebExchangeMatcherRegistry<T> {
* *
* @return the object that is chained after creating the {@link ServerWebExchangeMatcher} * @return the object that is chained after creating the {@link ServerWebExchangeMatcher}
*/ */
public T antMatchers(HttpMethod method) { public T pathMatchers(HttpMethod method) {
return antMatchers(method, new String[] { "/**" }); return pathMatchers(method, new String[] { "/**" });
} }
/** /**
@ -68,8 +64,8 @@ abstract class AbstractServerWebExchangeMatcherRegistry<T> {
* *
* @return the object that is chained after creating the {@link ServerWebExchangeMatcher} * @return the object that is chained after creating the {@link ServerWebExchangeMatcher}
*/ */
public T antMatchers(HttpMethod method, String... antPatterns) { public T pathMatchers(HttpMethod method, String... antPatterns) {
return matcher(ServerWebExchangeMatchers.antMatchers(method, antPatterns)); return matcher(ServerWebExchangeMatchers.pathMatchers(method, antPatterns));
} }
/** /**
@ -82,8 +78,8 @@ abstract class AbstractServerWebExchangeMatcherRegistry<T> {
* *
* @return the object that is chained after creating the {@link ServerWebExchangeMatcher} * @return the object that is chained after creating the {@link ServerWebExchangeMatcher}
*/ */
public T antMatchers(String... antPatterns) { public T pathMatchers(String... antPatterns) {
return matcher(ServerWebExchangeMatchers.antMatchers(antPatterns)); return matcher(ServerWebExchangeMatchers.pathMatchers(antPatterns));
} }
/** /**

View File

@ -33,7 +33,7 @@ public class AuthorizeExchangeBuilderTests {
@Test @Test
public void antMatchersWhenMethodAndPatternsThenDiscriminatesByMethod() { public void antMatchersWhenMethodAndPatternsThenDiscriminatesByMethod() {
authorization.antMatchers(HttpMethod.POST, "/a", "/b").denyAll(); authorization.pathMatchers(HttpMethod.POST, "/a", "/b").denyAll();
authorization.anyExchange().permitAll(); authorization.anyExchange().permitAll();
WebTestClient client = buildClient(); WebTestClient client = buildClient();
@ -62,7 +62,7 @@ public class AuthorizeExchangeBuilderTests {
@Test @Test
public void antMatchersWhenPatternsThenAnyMethod() { public void antMatchersWhenPatternsThenAnyMethod() {
authorization.antMatchers("/a", "/b").denyAll(); authorization.pathMatchers("/a", "/b").denyAll();
authorization.anyExchange().permitAll(); authorization.anyExchange().permitAll();
WebTestClient client = buildClient(); WebTestClient client = buildClient();
@ -90,19 +90,19 @@ public class AuthorizeExchangeBuilderTests {
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void antMatchersWhenNoAccessAndAnotherMatcherThenThrowsException() { public void antMatchersWhenNoAccessAndAnotherMatcherThenThrowsException() {
authorization.antMatchers("/incomplete"); authorization.pathMatchers("/incomplete");
authorization.antMatchers("/throws-exception"); authorization.pathMatchers("/throws-exception");
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void anyExchangeWhenFollowedByMatcherThenThrowsException() { public void anyExchangeWhenFollowedByMatcherThenThrowsException() {
authorization.anyExchange().denyAll(); authorization.anyExchange().denyAll();
authorization.antMatchers("/never-reached"); authorization.pathMatchers("/never-reached");
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void buildWhenMatcherDefinedWithNoAccessThenThrowsException() { public void buildWhenMatcherDefinedWithNoAccessThenThrowsException() {
authorization.antMatchers("/incomplete"); authorization.pathMatchers("/incomplete");
authorization.build(); authorization.build();
} }

View File

@ -40,8 +40,8 @@ public class SecurityConfig {
@Bean @Bean
WebFilterChainFilter springSecurityFilterChain(HttpSecurity http) throws Exception { WebFilterChainFilter springSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeExchange() http.authorizeExchange()
.antMatchers("/admin/**").hasRole("ADMIN") .pathMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/users/{user}/**").access(this::currentUserMatchesPath) .pathMatchers("/users/{user}/**").access(this::currentUserMatchesPath)
.anyExchange().authenticated(); .anyExchange().authenticated();
return http.build(); return http.build();

View File

@ -40,8 +40,8 @@ public class SecurityConfig {
@Bean @Bean
WebFilterChainFilter springSecurityFilterChain(HttpSecurity http) throws Exception { WebFilterChainFilter springSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeExchange() http.authorizeExchange()
.antMatchers("/admin/**").hasRole("ADMIN") .pathMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/users/{user}/**").access(this::currentUserMatchesPath) .pathMatchers("/users/{user}/**").access(this::currentUserMatchesPath)
.anyExchange().authenticated(); .anyExchange().authenticated();
return http.build(); return http.build();

View File

@ -22,10 +22,10 @@ import java.util.Map;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.PathMatcher; import org.springframework.util.PathMatcher;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.ParsingPathMatcher;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
/** /**
@ -33,7 +33,9 @@ import reactor.core.publisher.Mono;
* @since 5.0 * @since 5.0
*/ */
public final class PathMatcherServerWebExchangeMatcher implements ServerWebExchangeMatcher { public final class PathMatcherServerWebExchangeMatcher implements ServerWebExchangeMatcher {
private PathMatcher pathMatcher = new AntPathMatcher(); private static final PathMatcher DEFAULT_PATH_MATCHER = new ParsingPathMatcher();
private PathMatcher pathMatcher = DEFAULT_PATH_MATCHER;
private final String pattern; private final String pattern;
private final HttpMethod method; private final HttpMethod method;

View File

@ -30,7 +30,7 @@ import java.util.List;
*/ */
public abstract class ServerWebExchangeMatchers { public abstract class ServerWebExchangeMatchers {
public static ServerWebExchangeMatcher antMatchers(HttpMethod method, String... patterns) { public static ServerWebExchangeMatcher pathMatchers(HttpMethod method, String... patterns) {
List<ServerWebExchangeMatcher> matchers = new ArrayList<>(patterns.length); List<ServerWebExchangeMatcher> matchers = new ArrayList<>(patterns.length);
for (String pattern : patterns) { for (String pattern : patterns) {
matchers.add(new PathMatcherServerWebExchangeMatcher(pattern, method)); matchers.add(new PathMatcherServerWebExchangeMatcher(pattern, method));
@ -38,8 +38,8 @@ public abstract class ServerWebExchangeMatchers {
return new OrServerWebExchangeMatcher(matchers); return new OrServerWebExchangeMatcher(matchers);
} }
public static ServerWebExchangeMatcher antMatchers(String... patterns) { public static ServerWebExchangeMatcher pathMatchers(String... patterns) {
return antMatchers(null, patterns); return pathMatchers(null, patterns);
} }
public static ServerWebExchangeMatcher matchers(ServerWebExchangeMatcher... matchers) { public static ServerWebExchangeMatcher matchers(ServerWebExchangeMatcher... matchers) {

View File

@ -27,7 +27,7 @@ import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.verifyZeroInteractions;
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.antMatchers; import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.pathMatchers;
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.anyExchange; import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.anyExchange;
/** /**
@ -38,28 +38,28 @@ public class ServerWebExchangeMatchersTests {
ServerWebExchange exchange = MockServerHttpRequest.get("/").toExchange(); ServerWebExchange exchange = MockServerHttpRequest.get("/").toExchange();
@Test @Test
public void antMatchersWhenSingleAndSamePatternThenMatches() throws Exception { public void pathMatchersWhenSingleAndSamePatternThenMatches() throws Exception {
assertThat(antMatchers("/").matches(exchange).block().isMatch()).isTrue(); assertThat(pathMatchers("/").matches(exchange).block().isMatch()).isTrue();
} }
@Test @Test
public void antMatchersWhenSingleAndSamePatternAndMethodThenMatches() throws Exception { public void pathMatchersWhenSingleAndSamePatternAndMethodThenMatches() throws Exception {
assertThat(antMatchers(HttpMethod.GET, "/").matches(exchange).block().isMatch()).isTrue(); assertThat(ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/").matches(exchange).block().isMatch()).isTrue();
} }
@Test @Test
public void antMatchersWhenSingleAndSamePatternAndDiffMethodThenDoesNotMatch() throws Exception { public void pathMatchersWhenSingleAndSamePatternAndDiffMethodThenDoesNotMatch() throws Exception {
assertThat(antMatchers(HttpMethod.POST, "/").matches(exchange).block().isMatch()).isFalse(); assertThat(ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, "/").matches(exchange).block().isMatch()).isFalse();
} }
@Test @Test
public void antMatchersWhenSingleAndDifferentPatternThenDoesNotMatch() throws Exception { public void pathMatchersWhenSingleAndDifferentPatternThenDoesNotMatch() throws Exception {
assertThat(antMatchers("/foobar").matches(exchange).block().isMatch()).isFalse(); assertThat(pathMatchers("/foobar").matches(exchange).block().isMatch()).isFalse();
} }
@Test @Test
public void antMatchersWhenMultiThenMatches() throws Exception { public void pathMatchersWhenMultiThenMatches() throws Exception {
assertThat(antMatchers("/foobar", "/").matches(exchange).block().isMatch()).isTrue(); assertThat(pathMatchers("/foobar", "/").matches(exchange).block().isMatch()).isTrue();
} }
@Test @Test
@ -74,7 +74,7 @@ public class ServerWebExchangeMatchersTests {
/** /**
* If a LinkedMap is used and anyRequest equals anyRequest then the following is added: * If a LinkedMap is used and anyRequest equals anyRequest then the following is added:
* anyRequest() -> authenticated() * anyRequest() -> authenticated()
* antMatchers("/admin/**") -> hasRole("ADMIN") * pathMatchers("/admin/**") -> hasRole("ADMIN")
* anyRequest() -> permitAll * anyRequest() -> permitAll
* *
* will result in the first entry being overridden * will result in the first entry being overridden