From 106e9f54ab8e04b6396bf50aee2a1e605eb084f2 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Fri, 11 Apr 2025 19:07:42 +0700 Subject: [PATCH 1/2] Migrate from AntPathRequestMatcher to PathPatternRequestMatcher See gh-45163 Signed-off-by: Tran Ngoc Nhan --- .../servlet/CloudFoundryActuatorAutoConfiguration.java | 10 ++++------ .../servlet/AntPathRequestMatcherProvider.java | 8 +++----- .../security/servlet/EndpointRequest.java | 5 ++--- .../CloudFoundryActuatorAutoConfigurationTests.java | 6 ++++-- .../security/servlet/EndpointRequestTests.java | 2 +- .../ManagementWebSecurityAutoConfigurationTests.java | 10 ++++------ ...estMatchersManagementContextConfigurationTests.java | 7 +++++-- .../autoconfigure/security/servlet/PathRequest.java | 8 ++++---- .../security/servlet/StaticResourceRequest.java | 5 ++--- .../security/servlet/PathRequestTests.java | 9 +++++---- .../security/servlet/StaticResourceRequestTests.java | 10 +++++++--- .../RemoteDevtoolsSecurityConfiguration.java | 6 +++--- .../actuator/customsecurity/SecurityConfiguration.java | 8 ++++---- 13 files changed, 48 insertions(+), 46 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java index 4b4c2d4c38..b1c95992be 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java @@ -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 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)); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/AntPathRequestMatcherProvider.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/AntPathRequestMatcherProvider.java index 62b477cffa..16e21d9b75 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/AntPathRequestMatcherProvider.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/AntPathRequestMatcherProvider.java @@ -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); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java index daf3eb5cc7..bcea3b9171 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java @@ -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); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java index ea064bf689..e9bb84386d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java @@ -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(); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java index 3c112666ef..3d90fa4343 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java @@ -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()); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java index 229541e046..354a81526a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java @@ -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(); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfigurationTests.java index 2423fff042..c08f6e30cd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfigurationTests.java @@ -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")); }); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/PathRequest.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/PathRequest.java index 530d30a044..438befcd63 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/PathRequest.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/PathRequest.java @@ -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) { - this.delegate = new org.springframework.security.web.util.matcher.AntPathRequestMatcher( - h2ConsoleProperties.get().getPath() + "/**"); + this.delegate = PathPatternRequestMatcher.withDefaults() + .matcher(h2ConsoleProperties.get().getPath() + "/**"); } @Override diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java index 67fd2a2231..62200d562f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java @@ -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 getDelegateMatchers(DispatcherServletPath dispatcherServletPath) { - return getPatterns(dispatcherServletPath) - .map(org.springframework.security.web.util.matcher.AntPathRequestMatcher::new); + return getPatterns(dispatcherServletPath).map(PathPatternRequestMatcher.withDefaults()::matcher); } private Stream getPatterns(DispatcherServletPath dispatcherServletPath) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/PathRequestTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/PathRequestTests.java index 7f30f8e782..b5c07801b4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/PathRequestTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/PathRequestTests.java @@ -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; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequestTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequestTests.java index 7f2fe7869d..99ddbd4c7f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequestTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequestTests.java @@ -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; } diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevtoolsSecurityConfiguration.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevtoolsSecurityConfiguration.java index 0a306881d9..5acf44cbf1 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevtoolsSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevtoolsSecurityConfiguration.java @@ -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(); diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-custom-security/src/main/java/smoketest/actuator/customsecurity/SecurityConfiguration.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-custom-security/src/main/java/smoketest/actuator/customsecurity/SecurityConfiguration.java index 4826137ba1..9bbb126d5c 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-custom-security/src/main/java/smoketest/actuator/customsecurity/SecurityConfiguration.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-custom-security/src/main/java/smoketest/actuator/customsecurity/SecurityConfiguration.java @@ -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()); From d5505ca3f40a23f03bf681d0fd984881ca1fe5a5 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 11 Apr 2025 17:23:44 -0700 Subject: [PATCH 2/2] Polish 'Migrate from AntPathRequestMatcher to PathPatternRequestMatcher' See gh-45163 --- .../CloudFoundryActuatorAutoConfiguration.java | 15 +++++++++------ ...ava => PathPatternRequestMatcherProvider.java} | 7 +++---- ...estMatchersManagementContextConfiguration.java | 4 ++-- ...loudFoundryActuatorAutoConfigurationTests.java | 4 ++-- .../security/servlet/EndpointRequestTests.java | 14 +++++++------- ...tchersManagementContextConfigurationTests.java | 14 ++++++++------ 6 files changed, 31 insertions(+), 27 deletions(-) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/{AntPathRequestMatcherProvider.java => PathPatternRequestMatcherProvider.java} (86%) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java index b1c95992be..ab4405f3b6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java @@ -185,12 +185,15 @@ public class CloudFoundryActuatorAutoConfiguration { @Override public void customize(WebSecurity web) { - List requestMatchers = new ArrayList<>(); - this.pathMappedEndpoints.getAllPaths() - .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)); + List matchers = new ArrayList<>(); + this.pathMappedEndpoints.getAllPaths().forEach((path) -> matchers.add(pathMatcher(path + "/**"))); + matchers.add(pathMatcher(BASE_PATH)); + matchers.add(pathMatcher(BASE_PATH + "/")); + web.ignoring().requestMatchers(new OrRequestMatcher(matchers)); + } + + private PathPatternRequestMatcher pathMatcher(String path) { + return PathPatternRequestMatcher.withDefaults().matcher(path); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/AntPathRequestMatcherProvider.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/PathPatternRequestMatcherProvider.java similarity index 86% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/AntPathRequestMatcherProvider.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/PathPatternRequestMatcherProvider.java index 16e21d9b75..091cff1807 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/AntPathRequestMatcherProvider.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/PathPatternRequestMatcherProvider.java @@ -28,18 +28,17 @@ import org.springframework.security.web.util.matcher.RequestMatcher; * @author Madhura Bhave * @author Chris Bono */ -class AntPathRequestMatcherProvider implements RequestMatcherProvider { +class PathPatternRequestMatcherProvider implements RequestMatcherProvider { private final Function pathFactory; - AntPathRequestMatcherProvider(Function pathFactory) { + PathPatternRequestMatcherProvider(Function pathFactory) { this.pathFactory = pathFactory; } @Override public RequestMatcher getRequestMatcher(String pattern, HttpMethod httpMethod) { - String path = this.pathFactory.apply(pattern); - return PathPatternRequestMatcher.withDefaults().matcher(httpMethod, path); + return PathPatternRequestMatcher.withDefaults().matcher(httpMethod, this.pathFactory.apply(pattern)); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfiguration.java index 260620f34f..142854c76f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfiguration.java @@ -52,7 +52,7 @@ public class SecurityRequestMatchersManagementContextConfiguration { @ConditionalOnMissingBean @ConditionalOnClass(DispatcherServlet.class) public RequestMatcherProvider requestMatcherProvider(DispatcherServletPath servletPath) { - return new AntPathRequestMatcherProvider(servletPath::getRelativePath); + return new PathPatternRequestMatcherProvider(servletPath::getRelativePath); } } @@ -65,7 +65,7 @@ public class SecurityRequestMatchersManagementContextConfiguration { @Bean public RequestMatcherProvider requestMatcherProvider(JerseyApplicationPath applicationPath) { - return new AntPathRequestMatcherProvider(applicationPath::getRelativePath); + return new PathPatternRequestMatcherProvider(applicationPath::getRelativePath); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java index e9bb84386d..d5dbe6f481 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java @@ -211,9 +211,9 @@ class CloudFoundryActuatorAutoConfigurationTests { throw new IllegalStateException("No FilterChainProxy found"); } - private static void testCloudFoundrySecurity(MockHttpServletRequest request, String servletPath, + private static void testCloudFoundrySecurity(MockHttpServletRequest request, String requestUri, SecurityFilterChain chain) { - request.setRequestURI(servletPath); + request.setRequestURI(requestUri); assertThat(chain.matches(request)).isTrue(); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java index 3d90fa4343..1f1cea6886 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java @@ -413,24 +413,24 @@ class EndpointRequestTests { assertThat(this.matcher.matches(request)).as("Matches " + getRequestPath(request)).isTrue(); } - void doesNotMatch(String servletPath) { - doesNotMatch(mockRequest(null, servletPath)); + void doesNotMatch(String requestUri) { + doesNotMatch(mockRequest(null, requestUri)); } - void doesNotMatch(HttpMethod httpMethod, String servletPath) { - doesNotMatch(mockRequest(httpMethod, servletPath)); + void doesNotMatch(HttpMethod httpMethod, String requestUri) { + doesNotMatch(mockRequest(httpMethod, requestUri)); } private void doesNotMatch(HttpServletRequest request) { assertThat(this.matcher.matches(request)).as("Does not match " + getRequestPath(request)).isFalse(); } - private MockHttpServletRequest mockRequest(HttpMethod httpMethod, String servletPath) { + private MockHttpServletRequest mockRequest(HttpMethod httpMethod, String requestUri) { MockServletContext servletContext = new MockServletContext(); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); MockHttpServletRequest request = new MockHttpServletRequest(servletContext); - if (servletPath != null) { - request.setRequestURI(servletPath); + if (requestUri != null) { + request.setRequestURI(requestUri); } if (httpMethod != null) { request.setMethod(httpMethod.name()); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfigurationTests.java index c08f6e30cd..44e609536e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/SecurityRequestMatchersManagementContextConfigurationTests.java @@ -59,7 +59,8 @@ class SecurityRequestMatchersManagementContextConfigurationTests { @Test void registersRequestMatcherProviderIfMvcPresent() { this.contextRunner.withUserConfiguration(TestMvcConfiguration.class).run((context) -> { - AntPathRequestMatcherProvider matcherProvider = context.getBean(AntPathRequestMatcherProvider.class); + PathPatternRequestMatcherProvider matcherProvider = context + .getBean(PathPatternRequestMatcherProvider.class); RequestMatcher requestMatcher = matcherProvider.getRequestMatcher("/example", null); assertThat(requestMatcher).extracting("pattern") .isEqualTo(PathPatternParser.defaultInstance.parse("/custom/example")); @@ -71,7 +72,8 @@ class SecurityRequestMatchersManagementContextConfigurationTests { this.contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet")) .withUserConfiguration(TestJerseyConfiguration.class) .run((context) -> { - AntPathRequestMatcherProvider matcherProvider = context.getBean(AntPathRequestMatcherProvider.class); + PathPatternRequestMatcherProvider matcherProvider = context + .getBean(PathPatternRequestMatcherProvider.class); RequestMatcher requestMatcher = matcherProvider.getRequestMatcher("/example", null); assertThat(requestMatcher).extracting("pattern") .isEqualTo(PathPatternParser.defaultInstance.parse("/admin/example")); @@ -81,20 +83,20 @@ class SecurityRequestMatchersManagementContextConfigurationTests { @Test void mvcRequestMatcherProviderConditionalOnDispatcherServletClass() { this.contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet")) - .run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class)); + .run((context) -> assertThat(context).doesNotHaveBean(PathPatternRequestMatcherProvider.class)); } @Test void mvcRequestMatcherProviderConditionalOnDispatcherServletPathBean() { new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class)) - .run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class)); + .run((context) -> assertThat(context).doesNotHaveBean(PathPatternRequestMatcherProvider.class)); } @Test void jerseyRequestMatcherProviderConditionalOnResourceConfigClass() { this.contextRunner.withClassLoader(new FilteredClassLoader("org.glassfish.jersey.server.ResourceConfig")) - .run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class)); + .run((context) -> assertThat(context).doesNotHaveBean(PathPatternRequestMatcherProvider.class)); } @Test @@ -102,7 +104,7 @@ class SecurityRequestMatchersManagementContextConfigurationTests { new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class)) .withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet")) - .run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class)); + .run((context) -> assertThat(context).doesNotHaveBean(PathPatternRequestMatcherProvider.class)); } @Configuration(proxyBeanMethods = false)