Skip to content

Commit 86940bd

Browse files
committed
Merge pull request #45163 from ngocnhan-tran1996
* pr/45163: Polish 'Migrate from AntPathRequestMatcher to PathPatternRequestMatcher' Migrate from AntPathRequestMatcher to PathPatternRequestMatcher Closes gh-45163
2 parents bc9b331 + d5505ca commit 86940bd

File tree

14 files changed

+73
-67
lines changed

14 files changed

+73
-67
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java

+10-9
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
6363
import org.springframework.security.config.annotation.web.builders.WebSecurity;
6464
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
65+
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
6566
import org.springframework.security.web.util.matcher.OrRequestMatcher;
6667
import org.springframework.security.web.util.matcher.RequestMatcher;
6768
import org.springframework.web.cors.CorsConfiguration;
@@ -183,16 +184,16 @@ static class IgnoredCloudFoundryPathsWebSecurityCustomizer implements WebSecurit
183184
}
184185

185186
@Override
186-
@SuppressWarnings("removal")
187187
public void customize(WebSecurity web) {
188-
List<RequestMatcher> requestMatchers = new ArrayList<>();
189-
this.pathMappedEndpoints.getAllPaths()
190-
.forEach((path) -> requestMatchers
191-
.add(new org.springframework.security.web.util.matcher.AntPathRequestMatcher(path + "/**")));
192-
requestMatchers.add(new org.springframework.security.web.util.matcher.AntPathRequestMatcher(BASE_PATH));
193-
requestMatchers
194-
.add(new org.springframework.security.web.util.matcher.AntPathRequestMatcher(BASE_PATH + "/"));
195-
web.ignoring().requestMatchers(new OrRequestMatcher(requestMatchers));
188+
List<RequestMatcher> matchers = new ArrayList<>();
189+
this.pathMappedEndpoints.getAllPaths().forEach((path) -> matchers.add(pathMatcher(path + "/**")));
190+
matchers.add(pathMatcher(BASE_PATH));
191+
matchers.add(pathMatcher(BASE_PATH + "/"));
192+
web.ignoring().requestMatchers(new OrRequestMatcher(matchers));
193+
}
194+
195+
private PathPatternRequestMatcher pathMatcher(String path) {
196+
return PathPatternRequestMatcher.withDefaults().matcher(path);
196197
}
197198

198199
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.springframework.core.annotation.MergedAnnotation;
4343
import org.springframework.core.annotation.MergedAnnotations;
4444
import org.springframework.http.HttpMethod;
45+
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
4546
import org.springframework.security.web.util.matcher.OrRequestMatcher;
4647
import org.springframework.security.web.util.matcher.RequestMatcher;
4748
import org.springframework.util.Assert;
@@ -231,14 +232,12 @@ protected List<RequestMatcher> getLinksMatchers(RequestMatcherFactory requestMat
231232
return linksMatchers;
232233
}
233234

234-
@SuppressWarnings("removal")
235235
protected RequestMatcherProvider getRequestMatcherProvider(WebApplicationContext context) {
236236
try {
237237
return getRequestMatcherProviderBean(context);
238238
}
239239
catch (NoSuchBeanDefinitionException ex) {
240-
return (pattern, method) -> new org.springframework.security.web.util.matcher.AntPathRequestMatcher(
241-
pattern, (method != null) ? method.name() : null);
240+
return (pattern, method) -> PathPatternRequestMatcher.withDefaults().matcher(method, pattern);
242241
}
243242
}
244243

Original file line numberDiff line numberDiff line change
@@ -19,29 +19,26 @@
1919
import java.util.function.Function;
2020

2121
import org.springframework.http.HttpMethod;
22-
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
22+
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
2323
import org.springframework.security.web.util.matcher.RequestMatcher;
2424

2525
/**
26-
* {@link RequestMatcherProvider} that provides an {@link AntPathRequestMatcher}.
26+
* {@link RequestMatcherProvider} that provides an {@link PathPatternRequestMatcher}.
2727
*
2828
* @author Madhura Bhave
2929
* @author Chris Bono
3030
*/
31-
class AntPathRequestMatcherProvider implements RequestMatcherProvider {
31+
class PathPatternRequestMatcherProvider implements RequestMatcherProvider {
3232

3333
private final Function<String, String> pathFactory;
3434

35-
AntPathRequestMatcherProvider(Function<String, String> pathFactory) {
35+
PathPatternRequestMatcherProvider(Function<String, String> pathFactory) {
3636
this.pathFactory = pathFactory;
3737
}
3838

3939
@Override
40-
@SuppressWarnings("removal")
4140
public RequestMatcher getRequestMatcher(String pattern, HttpMethod httpMethod) {
42-
String path = this.pathFactory.apply(pattern);
43-
return new org.springframework.security.web.util.matcher.AntPathRequestMatcher(path,
44-
(httpMethod != null) ? httpMethod.name() : null);
41+
return PathPatternRequestMatcher.withDefaults().matcher(httpMethod, this.pathFactory.apply(pattern));
4542
}
4643

4744
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfiguration.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public static class MvcRequestMatcherConfiguration {
5252
@ConditionalOnMissingBean
5353
@ConditionalOnClass(DispatcherServlet.class)
5454
public RequestMatcherProvider requestMatcherProvider(DispatcherServletPath servletPath) {
55-
return new AntPathRequestMatcherProvider(servletPath::getRelativePath);
55+
return new PathPatternRequestMatcherProvider(servletPath::getRelativePath);
5656
}
5757

5858
}
@@ -65,7 +65,7 @@ public static class JerseyRequestMatcherConfiguration {
6565

6666
@Bean
6767
public RequestMatcherProvider requestMatcherProvider(JerseyApplicationPath applicationPath) {
68-
return new AntPathRequestMatcherProvider(applicationPath::getRelativePath);
68+
return new PathPatternRequestMatcherProvider(applicationPath::getRelativePath);
6969
}
7070

7171
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -182,8 +182,10 @@ void cloudFoundryPathsIgnoredBySpringSecurity() {
182182
testCloudFoundrySecurity(request, BASE_PATH + "/test", chain);
183183
testCloudFoundrySecurity(request, BASE_PATH + "/test/a", chain);
184184
request.setServletPath(BASE_PATH + "/other-path");
185+
request.setRequestURI(BASE_PATH + "/other-path");
185186
assertThat(chain.matches(request)).isFalse();
186187
request.setServletPath("/some-other-path");
188+
request.setRequestURI("/some-other-path");
187189
assertThat(chain.matches(request)).isFalse();
188190
});
189191
}
@@ -209,9 +211,9 @@ private FilterChainProxy getFilterChainProxy(Filter filter) {
209211
throw new IllegalStateException("No FilterChainProxy found");
210212
}
211213

212-
private static void testCloudFoundrySecurity(MockHttpServletRequest request, String servletPath,
214+
private static void testCloudFoundrySecurity(MockHttpServletRequest request, String requestUri,
213215
SecurityFilterChain chain) {
214-
request.setServletPath(servletPath);
216+
request.setRequestURI(requestUri);
215217
assertThat(chain.matches(request)).isTrue();
216218
}
217219

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -413,24 +413,24 @@ private void matches(HttpServletRequest request) {
413413
assertThat(this.matcher.matches(request)).as("Matches " + getRequestPath(request)).isTrue();
414414
}
415415

416-
void doesNotMatch(String servletPath) {
417-
doesNotMatch(mockRequest(null, servletPath));
416+
void doesNotMatch(String requestUri) {
417+
doesNotMatch(mockRequest(null, requestUri));
418418
}
419419

420-
void doesNotMatch(HttpMethod httpMethod, String servletPath) {
421-
doesNotMatch(mockRequest(httpMethod, servletPath));
420+
void doesNotMatch(HttpMethod httpMethod, String requestUri) {
421+
doesNotMatch(mockRequest(httpMethod, requestUri));
422422
}
423423

424424
private void doesNotMatch(HttpServletRequest request) {
425425
assertThat(this.matcher.matches(request)).as("Does not match " + getRequestPath(request)).isFalse();
426426
}
427427

428-
private MockHttpServletRequest mockRequest(HttpMethod httpMethod, String servletPath) {
428+
private MockHttpServletRequest mockRequest(HttpMethod httpMethod, String requestUri) {
429429
MockServletContext servletContext = new MockServletContext();
430430
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
431431
MockHttpServletRequest request = new MockHttpServletRequest(servletContext);
432-
if (servletPath != null) {
433-
request.setServletPath(servletPath);
432+
if (requestUri != null) {
433+
request.setRequestURI(requestUri);
434434
}
435435
if (httpMethod != null) {
436436
request.setMethod(httpMethod.name());

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java

+4-6
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
5353
import org.springframework.security.web.FilterChainProxy;
5454
import org.springframework.security.web.SecurityFilterChain;
55-
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
55+
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
5656
import org.springframework.web.context.ConfigurableWebApplicationContext;
5757
import org.springframework.web.context.WebApplicationContext;
5858

@@ -206,7 +206,7 @@ private HttpStatus getResponseStatus(AssertableWebApplicationContext context, St
206206
MockHttpServletResponse response = new MockHttpServletResponse();
207207
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
208208
MockHttpServletRequest request = new MockHttpServletRequest(servletContext);
209-
request.setServletPath(path);
209+
request.setRequestURI(path);
210210
request.setMethod("GET");
211211
filterChainProxy.doFilter(request, response, new MockFilterChain());
212212
return HttpStatus.valueOf(response.getStatus());
@@ -216,10 +216,9 @@ private HttpStatus getResponseStatus(AssertableWebApplicationContext context, St
216216
static class CustomSecurityConfiguration {
217217

218218
@Bean
219-
@SuppressWarnings("removal")
220219
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
221220
http.authorizeHttpRequests((requests) -> {
222-
requests.requestMatchers(new AntPathRequestMatcher("/foo")).permitAll();
221+
requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/foo")).permitAll();
223222
requests.anyRequest().authenticated();
224223
});
225224
http.formLogin(withDefaults());
@@ -246,9 +245,8 @@ static class TestRemoteDevToolsSecurityFilterChainConfig extends TestSecurityFil
246245

247246
@Bean
248247
@Order(SecurityProperties.BASIC_AUTH_ORDER - 1)
249-
@SuppressWarnings("removal")
250248
SecurityFilterChain testRemoteDevToolsSecurityFilterChain(HttpSecurity http) throws Exception {
251-
http.securityMatcher(new AntPathRequestMatcher("/**"));
249+
http.securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/**"));
252250
http.authorizeHttpRequests((requests) -> requests.anyRequest().anonymous());
253251
http.csrf((csrf) -> csrf.disable());
254252
return http.build();

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfigurationTests.java

+13-8
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.context.annotation.Bean;
2828
import org.springframework.context.annotation.Configuration;
2929
import org.springframework.security.web.util.matcher.RequestMatcher;
30+
import org.springframework.web.util.pattern.PathPatternParser;
3031

3132
import static org.assertj.core.api.Assertions.assertThat;
3233

@@ -58,9 +59,11 @@ void configurationConditionalOnRequestMatcherClass() {
5859
@Test
5960
void registersRequestMatcherProviderIfMvcPresent() {
6061
this.contextRunner.withUserConfiguration(TestMvcConfiguration.class).run((context) -> {
61-
AntPathRequestMatcherProvider matcherProvider = context.getBean(AntPathRequestMatcherProvider.class);
62+
PathPatternRequestMatcherProvider matcherProvider = context
63+
.getBean(PathPatternRequestMatcherProvider.class);
6264
RequestMatcher requestMatcher = matcherProvider.getRequestMatcher("/example", null);
63-
assertThat(requestMatcher).extracting("pattern").isEqualTo("/custom/example");
65+
assertThat(requestMatcher).extracting("pattern")
66+
.isEqualTo(PathPatternParser.defaultInstance.parse("/custom/example"));
6467
});
6568
}
6669

@@ -69,37 +72,39 @@ void registersRequestMatcherForJerseyProviderIfJerseyPresentAndMvcAbsent() {
6972
this.contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
7073
.withUserConfiguration(TestJerseyConfiguration.class)
7174
.run((context) -> {
72-
AntPathRequestMatcherProvider matcherProvider = context.getBean(AntPathRequestMatcherProvider.class);
75+
PathPatternRequestMatcherProvider matcherProvider = context
76+
.getBean(PathPatternRequestMatcherProvider.class);
7377
RequestMatcher requestMatcher = matcherProvider.getRequestMatcher("/example", null);
74-
assertThat(requestMatcher).extracting("pattern").isEqualTo("/admin/example");
78+
assertThat(requestMatcher).extracting("pattern")
79+
.isEqualTo(PathPatternParser.defaultInstance.parse("/admin/example"));
7580
});
7681
}
7782

7883
@Test
7984
void mvcRequestMatcherProviderConditionalOnDispatcherServletClass() {
8085
this.contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
81-
.run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class));
86+
.run((context) -> assertThat(context).doesNotHaveBean(PathPatternRequestMatcherProvider.class));
8287
}
8388

8489
@Test
8590
void mvcRequestMatcherProviderConditionalOnDispatcherServletPathBean() {
8691
new WebApplicationContextRunner()
8792
.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class))
88-
.run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class));
93+
.run((context) -> assertThat(context).doesNotHaveBean(PathPatternRequestMatcherProvider.class));
8994
}
9095

9196
@Test
9297
void jerseyRequestMatcherProviderConditionalOnResourceConfigClass() {
9398
this.contextRunner.withClassLoader(new FilteredClassLoader("org.glassfish.jersey.server.ResourceConfig"))
94-
.run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class));
99+
.run((context) -> assertThat(context).doesNotHaveBean(PathPatternRequestMatcherProvider.class));
95100
}
96101

97102
@Test
98103
void jerseyRequestMatcherProviderConditionalOnJerseyApplicationPathBean() {
99104
new WebApplicationContextRunner()
100105
.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class))
101106
.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
102-
.run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class));
107+
.run((context) -> assertThat(context).doesNotHaveBean(PathPatternRequestMatcherProvider.class));
103108
}
104109

105110
@Configuration(proxyBeanMethods = false)

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/PathRequest.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2022 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import org.springframework.boot.autoconfigure.security.StaticResourceLocation;
2525
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
2626
import org.springframework.boot.web.context.WebServerApplicationContext;
27+
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
2728
import org.springframework.security.web.util.matcher.RequestMatcher;
2829
import org.springframework.web.context.WebApplicationContext;
2930

@@ -76,10 +77,9 @@ protected boolean ignoreApplicationContext(WebApplicationContext applicationCont
7677
}
7778

7879
@Override
79-
@SuppressWarnings("removal")
8080
protected void initialized(Supplier<H2ConsoleProperties> h2ConsoleProperties) {
81-
this.delegate = new org.springframework.security.web.util.matcher.AntPathRequestMatcher(
82-
h2ConsoleProperties.get().getPath() + "/**");
81+
this.delegate = PathPatternRequestMatcher.withDefaults()
82+
.matcher(h2ConsoleProperties.get().getPath() + "/**");
8383
}
8484

8585
@Override

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
2929
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
3030
import org.springframework.boot.web.context.WebServerApplicationContext;
31+
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
3132
import org.springframework.security.web.util.matcher.OrRequestMatcher;
3233
import org.springframework.security.web.util.matcher.RequestMatcher;
3334
import org.springframework.util.Assert;
@@ -134,10 +135,8 @@ protected void initialized(Supplier<DispatcherServletPath> dispatcherServletPath
134135
this.delegate = new OrRequestMatcher(getDelegateMatchers(dispatcherServletPath.get()).toList());
135136
}
136137

137-
@SuppressWarnings("removal")
138138
private Stream<RequestMatcher> getDelegateMatchers(DispatcherServletPath dispatcherServletPath) {
139-
return getPatterns(dispatcherServletPath)
140-
.map(org.springframework.security.web.util.matcher.AntPathRequestMatcher::new);
139+
return getPatterns(dispatcherServletPath).map(PathPatternRequestMatcher.withDefaults()::matcher);
141140
}
142141

143142
private Stream<String> getPatterns(DispatcherServletPath dispatcherServletPath) {

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/PathRequestTests.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2022 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
2525
import org.springframework.mock.web.MockHttpServletRequest;
2626
import org.springframework.mock.web.MockServletContext;
2727
import org.springframework.security.web.util.matcher.RequestMatcher;
28+
import org.springframework.util.StringUtils;
2829
import org.springframework.web.context.WebApplicationContext;
2930

3031
import static org.assertj.core.api.Assertions.assertThat;
@@ -99,14 +100,14 @@ private MockHttpServletRequest mockRequest(String path) {
99100
MockServletContext servletContext = new MockServletContext();
100101
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
101102
MockHttpServletRequest request = new MockHttpServletRequest(servletContext);
102-
request.setPathInfo(path);
103+
request.setRequestURI(path);
103104
return request;
104105
}
105106

106107
private String getRequestPath(HttpServletRequest request) {
107108
String url = request.getServletPath();
108-
if (request.getPathInfo() != null) {
109-
url += request.getPathInfo();
109+
if (StringUtils.hasText(request.getRequestURI())) {
110+
url += request.getRequestURI();
110111
}
111112
return url;
112113
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequestTests.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.mock.web.MockHttpServletRequest;
2626
import org.springframework.mock.web.MockServletContext;
2727
import org.springframework.security.web.util.matcher.RequestMatcher;
28+
import org.springframework.util.StringUtils;
2829
import org.springframework.web.context.WebApplicationContext;
2930

3031
import static org.assertj.core.api.Assertions.assertThat;
@@ -156,15 +157,18 @@ private MockHttpServletRequest mockRequest(String servletPath, String path) {
156157
MockHttpServletRequest request = new MockHttpServletRequest(servletContext);
157158
if (servletPath != null) {
158159
request.setServletPath(servletPath);
160+
request.setRequestURI(servletPath + path);
161+
}
162+
else {
163+
request.setRequestURI(path);
159164
}
160-
request.setPathInfo(path);
161165
return request;
162166
}
163167

164168
private String getRequestPath(HttpServletRequest request) {
165169
String url = request.getServletPath();
166-
if (request.getPathInfo() != null) {
167-
url += request.getPathInfo();
170+
if (StringUtils.hasText(request.getRequestURI())) {
171+
url += request.getRequestURI();
168172
}
169173
return url;
170174
}

0 commit comments

Comments
 (0)