mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-08 03:32:39 +00:00
WebFlux now uses ParsingPathMatcher
Fixes gh-4388
This commit is contained in:
parent
554768f1e4
commit
337317a060
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user