Migrate from AntPathRequestMatcher to PathPatternRequestMatcher

See gh-45163

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
This commit is contained in:
Tran Ngoc Nhan
2025-04-11 19:07:42 +07:00
committed by Phillip Webb
parent bc9b331b1d
commit 106e9f54ab
13 changed files with 48 additions and 46 deletions

View File

@@ -62,6 +62,7 @@ import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
@@ -183,15 +184,12 @@ public class CloudFoundryActuatorAutoConfiguration {
}
@Override
@SuppressWarnings("removal")
public void customize(WebSecurity web) {
List<RequestMatcher> requestMatchers = new ArrayList<>();
this.pathMappedEndpoints.getAllPaths()
.forEach((path) -> requestMatchers
.add(new org.springframework.security.web.util.matcher.AntPathRequestMatcher(path + "/**")));
requestMatchers.add(new org.springframework.security.web.util.matcher.AntPathRequestMatcher(BASE_PATH));
requestMatchers
.add(new org.springframework.security.web.util.matcher.AntPathRequestMatcher(BASE_PATH + "/"));
.forEach((path) -> requestMatchers.add(PathPatternRequestMatcher.withDefaults().matcher(path + "/**")));
requestMatchers.add(PathPatternRequestMatcher.withDefaults().matcher(BASE_PATH));
requestMatchers.add(PathPatternRequestMatcher.withDefaults().matcher(BASE_PATH + "/"));
web.ignoring().requestMatchers(new OrRequestMatcher(requestMatchers));
}

View File

@@ -19,11 +19,11 @@ package org.springframework.boot.actuate.autoconfigure.security.servlet;
import java.util.function.Function;
import org.springframework.http.HttpMethod;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* {@link RequestMatcherProvider} that provides an {@link AntPathRequestMatcher}.
* {@link RequestMatcherProvider} that provides an {@link PathPatternRequestMatcher}.
*
* @author Madhura Bhave
* @author Chris Bono
@@ -37,11 +37,9 @@ class AntPathRequestMatcherProvider implements RequestMatcherProvider {
}
@Override
@SuppressWarnings("removal")
public RequestMatcher getRequestMatcher(String pattern, HttpMethod httpMethod) {
String path = this.pathFactory.apply(pattern);
return new org.springframework.security.web.util.matcher.AntPathRequestMatcher(path,
(httpMethod != null) ? httpMethod.name() : null);
return PathPatternRequestMatcher.withDefaults().matcher(httpMethod, path);
}
}

View File

@@ -42,6 +42,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.http.HttpMethod;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
@@ -231,14 +232,12 @@ public final class EndpointRequest {
return linksMatchers;
}
@SuppressWarnings("removal")
protected RequestMatcherProvider getRequestMatcherProvider(WebApplicationContext context) {
try {
return getRequestMatcherProviderBean(context);
}
catch (NoSuchBeanDefinitionException ex) {
return (pattern, method) -> new org.springframework.security.web.util.matcher.AntPathRequestMatcher(
pattern, (method != null) ? method.name() : null);
return (pattern, method) -> PathPatternRequestMatcher.withDefaults().matcher(method, pattern);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -182,8 +182,10 @@ class CloudFoundryActuatorAutoConfigurationTests {
testCloudFoundrySecurity(request, BASE_PATH + "/test", chain);
testCloudFoundrySecurity(request, BASE_PATH + "/test/a", chain);
request.setServletPath(BASE_PATH + "/other-path");
request.setRequestURI(BASE_PATH + "/other-path");
assertThat(chain.matches(request)).isFalse();
request.setServletPath("/some-other-path");
request.setRequestURI("/some-other-path");
assertThat(chain.matches(request)).isFalse();
});
}
@@ -211,7 +213,7 @@ class CloudFoundryActuatorAutoConfigurationTests {
private static void testCloudFoundrySecurity(MockHttpServletRequest request, String servletPath,
SecurityFilterChain chain) {
request.setServletPath(servletPath);
request.setRequestURI(servletPath);
assertThat(chain.matches(request)).isTrue();
}

View File

@@ -430,7 +430,7 @@ class EndpointRequestTests {
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
MockHttpServletRequest request = new MockHttpServletRequest(servletContext);
if (servletPath != null) {
request.setServletPath(servletPath);
request.setRequestURI(servletPath);
}
if (httpMethod != null) {
request.setMethod(httpMethod.name());

View File

@@ -52,7 +52,7 @@ import org.springframework.mock.web.MockServletContext;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.WebApplicationContext;
@@ -206,7 +206,7 @@ class ManagementWebSecurityAutoConfigurationTests {
MockHttpServletResponse response = new MockHttpServletResponse();
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
MockHttpServletRequest request = new MockHttpServletRequest(servletContext);
request.setServletPath(path);
request.setRequestURI(path);
request.setMethod("GET");
filterChainProxy.doFilter(request, response, new MockFilterChain());
return HttpStatus.valueOf(response.getStatus());
@@ -216,10 +216,9 @@ class ManagementWebSecurityAutoConfigurationTests {
static class CustomSecurityConfiguration {
@Bean
@SuppressWarnings("removal")
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
requests.requestMatchers(new AntPathRequestMatcher("/foo")).permitAll();
requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/foo")).permitAll();
requests.anyRequest().authenticated();
});
http.formLogin(withDefaults());
@@ -246,9 +245,8 @@ class ManagementWebSecurityAutoConfigurationTests {
@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER - 1)
@SuppressWarnings("removal")
SecurityFilterChain testRemoteDevToolsSecurityFilterChain(HttpSecurity http) throws Exception {
http.securityMatcher(new AntPathRequestMatcher("/**"));
http.securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/**"));
http.authorizeHttpRequests((requests) -> requests.anyRequest().anonymous());
http.csrf((csrf) -> csrf.disable());
return http.build();

View File

@@ -27,6 +27,7 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.util.pattern.PathPatternParser;
import static org.assertj.core.api.Assertions.assertThat;
@@ -60,7 +61,8 @@ class SecurityRequestMatchersManagementContextConfigurationTests {
this.contextRunner.withUserConfiguration(TestMvcConfiguration.class).run((context) -> {
AntPathRequestMatcherProvider matcherProvider = context.getBean(AntPathRequestMatcherProvider.class);
RequestMatcher requestMatcher = matcherProvider.getRequestMatcher("/example", null);
assertThat(requestMatcher).extracting("pattern").isEqualTo("/custom/example");
assertThat(requestMatcher).extracting("pattern")
.isEqualTo(PathPatternParser.defaultInstance.parse("/custom/example"));
});
}
@@ -71,7 +73,8 @@ class SecurityRequestMatchersManagementContextConfigurationTests {
.run((context) -> {
AntPathRequestMatcherProvider matcherProvider = context.getBean(AntPathRequestMatcherProvider.class);
RequestMatcher requestMatcher = matcherProvider.getRequestMatcher("/example", null);
assertThat(requestMatcher).extracting("pattern").isEqualTo("/admin/example");
assertThat(requestMatcher).extracting("pattern")
.isEqualTo(PathPatternParser.defaultInstance.parse("/admin/example"));
});
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@ import org.springframework.boot.autoconfigure.h2.H2ConsoleProperties;
import org.springframework.boot.autoconfigure.security.StaticResourceLocation;
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
import org.springframework.boot.web.context.WebServerApplicationContext;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.context.WebApplicationContext;
@@ -76,10 +77,9 @@ public final class PathRequest {
}
@Override
@SuppressWarnings("removal")
protected void initialized(Supplier<H2ConsoleProperties> h2ConsoleProperties) {
this.delegate = new org.springframework.security.web.util.matcher.AntPathRequestMatcher(
h2ConsoleProperties.get().getPath() + "/**");
this.delegate = PathPatternRequestMatcher.withDefaults()
.matcher(h2ConsoleProperties.get().getPath() + "/**");
}
@Override

View File

@@ -28,6 +28,7 @@ import org.springframework.boot.autoconfigure.security.StaticResourceLocation;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
import org.springframework.boot.web.context.WebServerApplicationContext;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
@@ -134,10 +135,8 @@ public final class StaticResourceRequest {
this.delegate = new OrRequestMatcher(getDelegateMatchers(dispatcherServletPath.get()).toList());
}
@SuppressWarnings("removal")
private Stream<RequestMatcher> getDelegateMatchers(DispatcherServletPath dispatcherServletPath) {
return getPatterns(dispatcherServletPath)
.map(org.springframework.security.web.util.matcher.AntPathRequestMatcher::new);
return getPatterns(dispatcherServletPath).map(PathPatternRequestMatcher.withDefaults()::matcher);
}
private Stream<String> getPatterns(DispatcherServletPath dispatcherServletPath) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
@@ -99,14 +100,14 @@ class PathRequestTests {
MockServletContext servletContext = new MockServletContext();
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
MockHttpServletRequest request = new MockHttpServletRequest(servletContext);
request.setPathInfo(path);
request.setRequestURI(path);
return request;
}
private String getRequestPath(HttpServletRequest request) {
String url = request.getServletPath();
if (request.getPathInfo() != null) {
url += request.getPathInfo();
if (StringUtils.hasText(request.getRequestURI())) {
url += request.getRequestURI();
}
return url;
}

View File

@@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
@@ -156,15 +157,18 @@ class StaticResourceRequestTests {
MockHttpServletRequest request = new MockHttpServletRequest(servletContext);
if (servletPath != null) {
request.setServletPath(servletPath);
request.setRequestURI(servletPath + path);
}
else {
request.setRequestURI(path);
}
request.setPathInfo(path);
return request;
}
private String getRequestPath(HttpServletRequest request) {
String url = request.getServletPath();
if (request.getPathInfo() != null) {
url += request.getPathInfo();
if (StringUtils.hasText(request.getRequestURI())) {
url += request.getRequestURI();
}
return url;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
/**
* Spring Security configuration that allows anonymous access to the remote devtools
@@ -45,10 +46,9 @@ class RemoteDevtoolsSecurityConfiguration {
}
@Bean
@SuppressWarnings("removal")
@Order(SecurityProperties.BASIC_AUTH_ORDER - 1)
SecurityFilterChain devtoolsSecurityFilterChain(HttpSecurity http) throws Exception {
http.securityMatcher(new org.springframework.security.web.util.matcher.AntPathRequestMatcher(this.url));
http.securityMatcher(PathPatternRequestMatcher.withDefaults().matcher(this.url));
http.authorizeHttpRequests((requests) -> requests.anyRequest().anonymous());
http.csrf(CsrfConfigurer::disable);
return http.build();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import static org.springframework.security.config.Customizer.withDefaults;
@@ -68,9 +68,9 @@ public class SecurityConfiguration {
requests.requestMatchers(EndpointRequest.toAnyEndpoint().excluding(MappingsEndpoint.class))
.hasRole("ACTUATOR");
requests.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();
requests.requestMatchers(new AntPathRequestMatcher("/foo")).permitAll();
requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/foo")).permitAll();
requests.requestMatchers(new MvcRequestMatcher(handlerMappingIntrospector, "/error")).permitAll();
requests.requestMatchers(new AntPathRequestMatcher("/**")).hasRole("USER");
requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/**")).hasRole("USER");
});
http.cors(withDefaults());
http.httpBasic(withDefaults());