From ef50ff29ad3b13c7b9a75f4e0ff9c1b05c6a745e Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 24 Jun 2025 15:20:24 -0600 Subject: [PATCH] Prgress --- .../cas/web/CasAuthenticationFilter.java | 3 +- .../web/AbstractRequestMatcherRegistry.java | 343 +----------------- .../annotation/web/RequestMatcherFactory.java | 13 +- .../annotation/web/builders/HttpSecurity.java | 62 +--- .../annotation/web/builders/WebSecurity.java | 3 +- .../WebMvcSecurityConfiguration.java | 95 ----- .../WebSecurityConfiguration.java | 8 +- .../web/configurers/CorsConfigurer.java | 17 +- .../configurers/RequestCacheConfigurer.java | 8 +- ...bMvcSecurityConfigurationRuntimeHints.java | 4 - .../http/AuthorizationFilterParser.java | 2 +- .../config/http/CorsBeanDefinitionParser.java | 15 +- ...> CorsConfigurationSourceFactoryBean.java} | 17 +- .../http/DefaultFilterChainValidator.java | 15 +- ...nvocationSecurityMetadataSourceParser.java | 2 +- .../config/http/HttpConfigurationBuilder.java | 20 +- .../security/config/http/MatcherType.java | 39 +- .../PathPatternRequestMatcherFactoryBean.java | 77 ++++ .../http/RequestMatcherFactoryBean.java | 9 +- .../web/AbstractRequestMatcherDsl.kt | 2 +- .../web/AuthorizeHttpRequestsDsl.kt | 27 +- .../annotation/web/AuthorizeRequestsDsl.kt | 28 +- .../config/annotation/web/HttpSecurityDsl.kt | 1 - .../annotation/web/RequiresChannelDsl.kt | 27 +- .../security/config/spring-security-7.0.rnc | 2 +- .../security/config/spring-security-7.0.xsd | 3 +- .../config/FilterChainProxyConfigTests.java | 3 +- .../annotation/issue50/SecurityConfig.java | 4 +- ...RequestMatcherRegistryAnyMatcherTests.java | 18 +- ...tractRequestMatcherRegistryNoMvcTests.java | 16 +- .../AbstractRequestMatcherRegistryTests.java | 276 ++------------ .../web/builders/HttpConfigurationTests.java | 6 +- .../web/builders/NamespaceHttpTests.java | 25 +- .../WebSecurityFilterChainValidatorTests.java | 22 +- .../web/builders/WebSecurityTests.java | 25 +- ...vocationPrivilegeEvaluatorConfigTests.java | 32 +- ...ingIntrospectorCacheFilterConfigTests.java | 127 ------- .../WebSecurityConfigurationTests.java | 58 ++- ...gAttributeRequestMatcherRegistryTests.java | 15 +- .../AuthorizeHttpRequestsConfigurerTests.java | 19 +- .../configurers/AuthorizeRequestsTests.java | 50 ++- ...onfigurerIgnoringRequestMatchersTests.java | 10 +- .../web/configurers/CsrfConfigurerTests.java | 4 +- .../web/configurers/DefaultFiltersTests.java | 3 +- ...ingConfigurerAccessDeniedHandlerTests.java | 8 +- .../HttpSecurityRequestMatchersTests.java | 91 +++-- ...ttpSecuritySecurityMatchersNoMvcTests.java | 4 +- .../HttpSecuritySecurityMatchersTests.java | 32 +- .../configurers/NamespaceRememberMeTests.java | 3 +- .../RequestMatcherConfigurerTests.java | 10 +- ...ionManagementConfigurerServlet31Tests.java | 2 +- .../UrlAuthorizationConfigurerTests.java | 25 +- .../client/OAuth2LoginConfigurerTests.java | 2 +- .../saml2/Saml2LogoutConfigurerTests.java | 5 +- ...ecurityConfigurationRuntimeHintsTests.java | 8 - .../DefaultFilterChainValidatorTests.java | 11 +- ...tadataSourceBeanDefinitionParserTests.java | 13 +- .../config/http/FormLoginConfigTests.java | 2 +- .../config/http/InterceptUrlConfigTests.java | 65 ---- .../customconfigurer/CustomConfigurer.java | 4 +- .../config/annotation/web/CsrfDslTests.kt | 10 +- .../web/ExceptionHandlingDslTests.kt | 12 +- .../config/annotation/web/LogoutDslTests.kt | 8 +- .../annotation/web/RememberMeDslTests.kt | 3 +- .../HttpStrictTransportSecurityDslTests.kt | 4 +- ...erDataValueProcessorOnyIfNotRegistered.xml | 4 +- .../http/CsrfConfigTests-CsrfEnabled.xml | 2 +- ...rmLoginConfigTests-WithRequestMatcher.xml} | 2 +- ...figTests-WithSuccessAndFailureHandlers.xml | 2 +- ...rceptUrlWhenRequestMatcherRefThenWorks.xml | 12 +- ...izationManagerFilterAllDispatcherTypes.xml | 8 +- ...tUrlConfigTests-CamelCasePathVariables.xml | 2 +- ...lCasePathVariablesAuthorizationManager.xml | 2 +- ...lConfigTests-DefaultMatcherServletPath.xml | 2 +- ...MatcherServletPathAuthorizationManager.xml | 2 +- ...figTests-FilterAllDispatcherTypesFalse.xml | 8 +- .../InterceptUrlConfigTests-PatchMethod.xml | 2 +- ...gTests-PatchMethodAuthorizationManager.xml | 2 +- .../InterceptUrlConfigTests-PathVariables.xml | 2 +- ...ests-PathVariablesAuthorizationManager.xml | 2 +- .../http/InterceptUrlConfigTests-Sec2256.xml | 2 +- ...onfigTests-Sec2256AuthorizationManager.xml | 2 +- ...onfigTests-TypeConversionPathVariables.xml | 2 +- ...rsionPathVariablesAuthorizationManager.xml | 2 +- .../MiscHttpConfigTests-AnonymousDisabled.xml | 2 +- ...MiscHttpConfigTests-AnonymousEndpoints.xml | 2 +- ...nfigTests-CustomHttpBasicEntryPointRef.xml | 2 +- ...scHttpConfigTests-CustomRequestMatcher.xml | 2 +- ...scHttpConfigTests-NoSecurityForPattern.xml | 2 +- .../MiscHttpConfigTests-OncePerRequest.xml | 2 +- ...MiscHttpConfigTests-OncePerRequestTrue.xml | 2 +- ...MiscHttpConfigTests-ProtectedLoginPage.xml | 2 +- ...ProtectedLoginPageAuthorizationManager.xml | 2 +- ...pBlockConfigTests-DistinctHttpElements.xml | 2 +- ...Tests-IdenticallyPatternedHttpElements.xml | 2 +- .../MultiHttpBlockConfigTests-Sec1937.xml | 2 +- ...serTests-AuthenticationManagerResolver.xml | 2 +- ...tionParserTests-BasicAndResourceServer.xml | 2 +- ...itionParserTests-FormAndResourceServer.xml | 2 +- ...verBeanDefinitionParserTests-JwkSetUri.xml | 2 +- ...rceServerBeanDefinitionParserTests-Jwt.xml | 2 +- ...JwtCustomSecurityContextHolderStrategy.xml | 2 +- ...nDefinitionParserTests-MultipleIssuers.xml | 2 +- ...rBeanDefinitionParserTests-OpaqueToken.xml | 2 +- ...-OpaqueTokenAndAuthenticationConverter.xml | 2 +- ...olderAndELConfigTests-AccessDeniedPage.xml | 2 +- ...ELConfigTests-AccessDeniedPageWithSpEL.xml | 2 +- ...ELConfigTests-InterceptUrlAndFormLogin.xml | 2 +- ...Tests-InterceptUrlAndFormLoginWithSpEL.xml | 2 +- ...laceHolderAndELConfigTests-PortMapping.xml | 2 +- ...HolderAndELConfigTests-RequiresChannel.xml | 2 +- ...olderAndELConfigTests-UnsecuredPattern.xml | 2 +- .../RememberMeConfigTests-DefaultConfig.xml | 2 +- ...berMeConfigTests-NegativeTokenValidity.xml | 2 +- .../http/RememberMeConfigTests-Sec1827.xml | 2 +- .../http/RememberMeConfigTests-Sec2165.xml | 2 +- .../http/RememberMeConfigTests-Sec742.xml | 2 +- .../RememberMeConfigTests-SecureCookie.xml | 2 +- .../RememberMeConfigTests-TokenValidity.xml | 2 +- ...Tests-WithAuthenticationSuccessHandler.xml | 2 +- .../RememberMeConfigTests-WithDataSource.xml | 2 +- ...mberMeConfigTests-WithRememberMeCookie.xml | 2 +- ...rMeConfigTests-WithRememberMeParameter.xml | 2 +- ...ests-WithSecurityContextHolderStrategy.xml | 2 +- .../RememberMeConfigTests-WithServicesRef.xml | 2 +- ...emberMeConfigTests-WithTokenRepository.xml | 2 +- ...erMeConfigTests-WithUserDetailsService.xml | 2 +- ...olderAwareRequestConfigTests-MultiHttp.xml | 4 +- ...entConfigTests-CreateSessionIfRequired.xml | 2 +- ...nagementConfigTests-CreateSessionNever.xml | 2 +- ...mentConfigTests-CreateSessionStateless.xml | 2 +- ...tConfigTests-NoSessionManagementFilter.xml | 2 +- .../SessionManagementConfigTests-Sec1208.xml | 2 +- .../SessionManagementConfigTests-Sec2137.xml | 2 +- ...Tests-SessionAuthenticationStrategyRef.xml | 2 +- ...essionFixationProtectionMigrateSession.xml | 2 +- ...figTests-SessionFixationProtectionNone.xml | 2 +- ...ionProtectionNoneWithInvalidSessionUrl.xml | 2 +- ...l => pathpatternrequestmatcherbuilder.xml} | 2 +- .../security/util/filtertest-valid.xml | 10 +- .../servlet/appendix/namespace/http.adoc | 5 +- .../authorize-http-requests.adoc | 16 +- .../pages/servlet/configuration/java.adoc | 2 +- .../ROOT/pages/servlet/exploits/csrf.adoc | 6 +- .../ROOT/pages/servlet/exploits/firewall.adoc | 2 +- .../ROOT/pages/servlet/exploits/headers.adoc | 6 +- .../pages/servlet/integrations/websocket.adoc | 2 +- etc/checkstyle/checkstyle.xml | 2 +- .../filter-chain-performance-app-context.xml | 4 +- .../spring/http-security-concurrency.xml | 2 +- ...ml4AuthenticationRequestResolverTests.java | 5 +- ...ml5AuthenticationRequestResolverTests.java | 5 +- .../service/web/Saml2MetadataFilterTests.java | 8 +- .../Saml2WebSsoAuthenticationFilterTests.java | 4 +- .../test/web/support/WebTestUtilsTests.java | 4 +- .../security/web/FilterChainProxy.java | 5 +- ...MappingIntrospectorRequestTransformer.java | 98 ----- ...ilterInvocationSecurityMetadataSource.java | 12 +- ...bstractAuthenticationProcessingFilter.java | 4 +- .../switchuser/SwitchUserFilter.java | 17 +- .../util/matcher/MvcRequestMatcher.java | 251 ------------- .../util/matcher/AntPathRequestMatcher.java | 330 ----------------- .../RequestMatcherRedirectFilterTests.java | 14 +- ...ngIntrospectorRequestTransformerTests.java | 206 ----------- ...InvocationSecurityMetadataSourceTests.java | 16 +- ...erDelegatingAuthorizationManagerTests.java | 17 +- ...ctAuthenticationProcessingFilterTests.java | 7 +- ...ingAuthenticationManagerResolverTests.java | 10 +- ...PreAuthenticatedProcessingFilterTests.java | 8 +- .../www/BasicAuthenticationFilterTests.java | 4 +- .../util/matcher/MvcRequestMatcherTests.java | 275 -------------- .../util/matcher/AndRequestMatcherTests.java | 3 +- .../matcher/AntPathRequestMatcherTests.java | 266 -------------- .../util/matcher/OrRequestMatcherTests.java | 3 +- 174 files changed, 713 insertions(+), 2967 deletions(-) rename config/src/main/java/org/springframework/security/config/http/{HandlerMappingIntrospectorFactoryBean.java => CorsConfigurationSourceFactoryBean.java} (76%) create mode 100644 config/src/main/java/org/springframework/security/config/http/PathPatternRequestMatcherFactoryBean.java delete mode 100644 config/src/test/java/org/springframework/security/config/annotation/web/configuration/HandlerMappingIntrospectorCacheFilterConfigTests.java rename config/src/test/resources/org/springframework/security/config/http/{FormLoginConfigTests-WithAntRequestMatcher.xml => FormLoginConfigTests-WithRequestMatcher.xml} (92%) rename config/src/test/resources/org/springframework/security/config/http/{handlermappingintrospector.xml => pathpatternrequestmatcherbuilder.xml} (90%) delete mode 100644 web/src/main/java/org/springframework/security/web/access/HandlerMappingIntrospectorRequestTransformer.java delete mode 100644 web/src/main/java/org/springframework/security/web/servlet/util/matcher/MvcRequestMatcher.java delete mode 100644 web/src/main/java/org/springframework/security/web/util/matcher/AntPathRequestMatcher.java delete mode 100644 web/src/test/java/org/springframework/security/web/access/HandlerMappingIntrospectorRequestTransformerTests.java delete mode 100644 web/src/test/java/org/springframework/security/web/servlet/util/matcher/MvcRequestMatcherTests.java delete mode 100644 web/src/test/java/org/springframework/security/web/util/matcher/AntPathRequestMatcherTests.java diff --git a/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java b/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java index 43283b7ccf..0e7ff836c0 100644 --- a/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java +++ b/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java @@ -52,7 +52,6 @@ import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -335,7 +334,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil } public final void setProxyReceptorUrl(final String proxyReceptorUrl) { - this.proxyReceptorMatcher = new AntPathRequestMatcher("/**" + proxyReceptorUrl); + this.proxyReceptorMatcher = PathPatternRequestMatcher.withDefaults().matcher(proxyReceptorUrl); } public final void setProxyGrantingTicketStorage(final ProxyGrantingTicketStorage proxyGrantingTicketStorage) { diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java b/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java index ba0a291653..5d2624f8e3 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java @@ -18,41 +18,20 @@ package org.springframework.security.config.annotation.web; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; import jakarta.servlet.DispatcherType; -import jakarta.servlet.ServletContext; -import jakarta.servlet.ServletRegistration; -import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.ApplicationContext; -import org.springframework.core.ResolvableType; import org.springframework.http.HttpMethod; import org.springframework.lang.Nullable; -import org.springframework.security.config.ObjectPostProcessor; -import org.springframework.security.config.annotation.web.ServletRegistrationsSupport.RegistrationMapping; -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.security.web.util.matcher.AnyRequestMatcher; import org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher; -import org.springframework.security.web.util.matcher.OrRequestMatcher; -import org.springframework.security.web.util.matcher.RegexRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.servlet.DispatcherServlet; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; /** * A base class for registering {@link RequestMatcher}'s. For example, it might allow for @@ -65,23 +44,12 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector; */ public abstract class AbstractRequestMatcherRegistry { - private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector"; - - private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"; - - private static final boolean mvcPresent; - private static final RequestMatcher ANY_REQUEST = AnyRequestMatcher.INSTANCE; private ApplicationContext context; private boolean anyRequestConfigured = false; - static { - mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, - AbstractRequestMatcherRegistry.class.getClassLoader()); - } - private final Log logger = LogFactory.getLog(getClass()); protected final void setApplicationContext(ApplicationContext context) { @@ -107,40 +75,6 @@ public abstract class AbstractRequestMatcherRegistry { return configurer; } - /** - * Creates {@link MvcRequestMatcher} instances for the method and patterns passed in - * @param method the HTTP method to use or null if any should be used - * @param mvcPatterns the Spring MVC patterns to match on - * @return a List of {@link MvcRequestMatcher} instances - * @deprecated Please use - * {@link org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.Builder} - * instead - */ - @Deprecated - protected final List createMvcMatchers(HttpMethod method, String... mvcPatterns) { - Assert.state(!this.anyRequestConfigured, "Can't configure mvcMatchers after anyRequest"); - ResolvableType type = ResolvableType.forClassWithGenerics(ObjectPostProcessor.class, Object.class); - ObjectProvider> postProcessors = this.context.getBeanProvider(type); - ObjectPostProcessor opp = postProcessors.getObject(); - if (!this.context.containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) { - throw new NoSuchBeanDefinitionException("A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME - + " of type " + HandlerMappingIntrospector.class.getName() - + " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext."); - } - HandlerMappingIntrospector introspector = this.context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, - HandlerMappingIntrospector.class); - List matchers = new ArrayList<>(mvcPatterns.length); - for (String mvcPattern : mvcPatterns) { - MvcRequestMatcher matcher = new MvcRequestMatcher(introspector, mvcPattern); - opp.postProcess(matcher); - if (method != null) { - matcher.setMethod(method); - } - matchers.add(matcher); - } - return matchers; - } - /** * Maps a {@link List} of * {@link org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher} @@ -184,12 +118,9 @@ public abstract class AbstractRequestMatcherRegistry { /** *

- * If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an - * {@link MvcRequestMatcher} that also specifies a specific {@link HttpMethod} to - * match on. This matcher will use the same rules that Spring MVC uses for matching. - * For example, often times a mapping of the path "/path" will match on "/path", - * "/path/", "/path.html", etc. If the {@link HandlerMappingIntrospector} is not - * available, maps to an {@link AntPathRequestMatcher}. + * Match when the {@link HttpMethod} is {@code method} and when the request URI + * matches one of {@code patterns}. See + * {@link org.springframework.web.util.pattern.PathPattern} for matching rules. *

*

* If a specific {@link RequestMatcher} must be specified, use @@ -197,8 +128,7 @@ public abstract class AbstractRequestMatcherRegistry { *

* @param method the {@link HttpMethod} to use or {@code null} for any * {@link HttpMethod}. - * @param patterns the patterns to match on. The rules for matching are defined by - * Spring MVC if {@link MvcRequestMatcher} is used + * @param patterns the patterns to match on * @return the object that is chained after creating the {@link RequestMatcher}. * @since 5.8 */ @@ -209,27 +139,13 @@ public abstract class AbstractRequestMatcherRegistry { + "leading slash in all your request matcher patterns. In future versions of " + "Spring Security, leaving out the leading slash will result in an exception."); } - if (!mvcPresent) { - return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns)); - } - if (!(this.context instanceof WebApplicationContext)) { - return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns)); - } - WebApplicationContext context = (WebApplicationContext) this.context; - ServletContext servletContext = context.getServletContext(); - if (servletContext == null) { - return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns)); - } + Assert.state(!this.anyRequestConfigured, "Can't configure requestMatchers after anyRequest"); + PathPatternRequestMatcher.Builder builder = this.context + .getBeanProvider(PathPatternRequestMatcher.Builder.class) + .getIfUnique(PathPatternRequestMatcher::withDefaults); List matchers = new ArrayList<>(); for (String pattern : patterns) { - if (RequestMatcherFactory.usesPathPatterns()) { - matchers.add(RequestMatcherFactory.matcher(method, pattern)); - } - else { - AntPathRequestMatcher ant = new AntPathRequestMatcher(pattern, (method != null) ? method.name() : null); - MvcRequestMatcher mvc = createMvcMatchers(method, pattern).get(0); - matchers.add(new DeferredRequestMatcher((c) -> resolve(ant, mvc, c), mvc, ant)); - } + matchers.add(builder.matcher(method, pattern)); } return requestMatchers(matchers.toArray(new RequestMatcher[0])); } @@ -243,64 +159,16 @@ public abstract class AbstractRequestMatcherRegistry { return false; } - private RequestMatcher resolve(AntPathRequestMatcher ant, MvcRequestMatcher mvc, ServletContext servletContext) { - ServletRegistrationsSupport registrations = new ServletRegistrationsSupport(servletContext); - Collection mappings = registrations.mappings(); - if (mappings.isEmpty()) { - return new DispatcherServletDelegatingRequestMatcher(ant, mvc, new MockMvcRequestMatcher()); - } - Collection dispatcherServletMappings = registrations.dispatcherServletMappings(); - if (dispatcherServletMappings.isEmpty()) { - return new DispatcherServletDelegatingRequestMatcher(ant, mvc, new MockMvcRequestMatcher()); - } - if (dispatcherServletMappings.size() > 1) { - String errorMessage = computeErrorMessage(servletContext.getServletRegistrations().values()); - throw new IllegalArgumentException(errorMessage); - } - RegistrationMapping dispatcherServlet = dispatcherServletMappings.iterator().next(); - if (mappings.size() > 1 && !dispatcherServlet.isDefault()) { - String errorMessage = computeErrorMessage(servletContext.getServletRegistrations().values()); - throw new IllegalArgumentException(errorMessage); - } - if (dispatcherServlet.isDefault()) { - if (mappings.size() == 1) { - return mvc; - } - return new DispatcherServletDelegatingRequestMatcher(ant, mvc); - } - return mvc; - } - - private static String computeErrorMessage(Collection registrations) { - String template = """ - This method cannot decide whether these patterns are Spring MVC patterns or not. \ - This is because there is more than one mappable servlet in your servlet context: %s. - - To address this, please create one PathPatternRequestMatcher.Builder#servletPath for each servlet that has \ - authorized endpoints and use them to construct request matchers manually. - """; - Map> mappings = new LinkedHashMap<>(); - for (ServletRegistration registration : registrations) { - mappings.put(registration.getClassName(), registration.getMappings()); - } - return String.format(template, mappings); - } - /** *

- * If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an - * {@link MvcRequestMatcher} that does not care which {@link HttpMethod} is used. This - * matcher will use the same rules that Spring MVC uses for matching. For example, - * often times a mapping of the path "/path" will match on "/path", "/path/", - * "/path.html", etc. If the {@link HandlerMappingIntrospector} is not available, maps - * to an {@link AntPathRequestMatcher}. + * Match when the request URI matches one of {@code patterns}. See + * {@link org.springframework.web.util.pattern.PathPattern} for matching rules. *

*

* If a specific {@link RequestMatcher} must be specified, use * {@link #requestMatchers(RequestMatcher...)} instead *

- * @param patterns the patterns to match on. The rules for matching are defined by - * Spring MVC if {@link MvcRequestMatcher} is used + * @param patterns the patterns to match on * @return the object that is chained after creating the {@link RequestMatcher}. * @since 5.8 */ @@ -310,12 +178,7 @@ public abstract class AbstractRequestMatcherRegistry { /** *

- * If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an - * {@link MvcRequestMatcher} that matches on a specific {@link HttpMethod}. This - * matcher will use the same rules that Spring MVC uses for matching. For example, - * often times a mapping of the path "/path" will match on "/path", "/path/", - * "/path.html", etc. If the {@link HandlerMappingIntrospector} is not available, maps - * to an {@link AntPathRequestMatcher}. + * Match when the {@link HttpMethod} is {@code method} *

*

* If a specific {@link RequestMatcher} must be specified, use @@ -339,182 +202,4 @@ public abstract class AbstractRequestMatcherRegistry { */ protected abstract C chainRequestMatchers(List requestMatchers); - /** - * Utilities for creating {@link RequestMatcher} instances. - * - * @author Rob Winch - * @since 3.2 - */ - private static final class RequestMatchers { - - private RequestMatchers() { - } - - /** - * Create a {@link List} of {@link AntPathRequestMatcher} instances. - * @param httpMethod the {@link HttpMethod} to use or {@code null} for any - * {@link HttpMethod}. - * @param antPatterns the ant patterns to create {@link AntPathRequestMatcher} - * from - * @return a {@link List} of {@link AntPathRequestMatcher} instances - */ - static List antMatchers(HttpMethod httpMethod, String... antPatterns) { - return Arrays.asList(antMatchersAsArray(httpMethod, antPatterns)); - } - - /** - * Create a {@link List} of {@link AntPathRequestMatcher} instances that do not - * specify an {@link HttpMethod}. - * @param antPatterns the ant patterns to create {@link AntPathRequestMatcher} - * from - * @return a {@link List} of {@link AntPathRequestMatcher} instances - */ - static List antMatchers(String... antPatterns) { - return antMatchers(null, antPatterns); - } - - static RequestMatcher[] antMatchersAsArray(HttpMethod httpMethod, String... antPatterns) { - String method = (httpMethod != null) ? httpMethod.toString() : null; - RequestMatcher[] matchers = new RequestMatcher[antPatterns.length]; - for (int index = 0; index < antPatterns.length; index++) { - matchers[index] = new AntPathRequestMatcher(antPatterns[index], method); - } - return matchers; - } - - /** - * Create a {@link List} of {@link RegexRequestMatcher} instances. - * @param httpMethod the {@link HttpMethod} to use or {@code null} for any - * {@link HttpMethod}. - * @param regexPatterns the regular expressions to create - * {@link RegexRequestMatcher} from - * @return a {@link List} of {@link RegexRequestMatcher} instances - */ - static List regexMatchers(HttpMethod httpMethod, String... regexPatterns) { - String method = (httpMethod != null) ? httpMethod.toString() : null; - List matchers = new ArrayList<>(); - for (String pattern : regexPatterns) { - matchers.add(new RegexRequestMatcher(pattern, method)); - } - return matchers; - } - - /** - * Create a {@link List} of {@link RegexRequestMatcher} instances that do not - * specify an {@link HttpMethod}. - * @param regexPatterns the regular expressions to create - * {@link RegexRequestMatcher} from - * @return a {@link List} of {@link RegexRequestMatcher} instances - */ - static List regexMatchers(String... regexPatterns) { - return regexMatchers(null, regexPatterns); - } - - } - - static class DeferredRequestMatcher implements RequestMatcher { - - final Function requestMatcherFactory; - - final AtomicReference description = new AtomicReference<>(); - - final Map requestMatchers = new ConcurrentHashMap<>(); - - DeferredRequestMatcher(Function resolver, RequestMatcher... candidates) { - this.requestMatcherFactory = (sc) -> this.requestMatchers.computeIfAbsent(sc, resolver); - this.description.set("Deferred " + Arrays.toString(candidates)); - } - - RequestMatcher requestMatcher(ServletContext servletContext) { - return this.requestMatcherFactory.apply(servletContext); - } - - @Override - public boolean matches(HttpServletRequest request) { - return this.requestMatcherFactory.apply(request.getServletContext()).matches(request); - } - - @Override - public MatchResult matcher(HttpServletRequest request) { - return this.requestMatcherFactory.apply(request.getServletContext()).matcher(request); - } - - @Override - public String toString() { - return this.description.get(); - } - - } - - static class MockMvcRequestMatcher implements RequestMatcher { - - @Override - public boolean matches(HttpServletRequest request) { - return request.getAttribute("org.springframework.test.web.servlet.MockMvc.MVC_RESULT_ATTRIBUTE") != null; - } - - } - - static class DispatcherServletRequestMatcher implements RequestMatcher { - - @Override - public boolean matches(HttpServletRequest request) { - String name = request.getHttpServletMapping().getServletName(); - ServletRegistration registration = request.getServletContext().getServletRegistration(name); - Assert.notNull(registration, - () -> computeErrorMessage(request.getServletContext().getServletRegistrations().values())); - try { - Class clazz = Class.forName(registration.getClassName()); - return DispatcherServlet.class.isAssignableFrom(clazz); - } - catch (ClassNotFoundException ex) { - return false; - } - } - - } - - static class DispatcherServletDelegatingRequestMatcher implements RequestMatcher { - - private final AntPathRequestMatcher ant; - - private final MvcRequestMatcher mvc; - - private final RequestMatcher dispatcherServlet; - - DispatcherServletDelegatingRequestMatcher(AntPathRequestMatcher ant, MvcRequestMatcher mvc) { - this(ant, mvc, new OrRequestMatcher(new MockMvcRequestMatcher(), new DispatcherServletRequestMatcher())); - } - - DispatcherServletDelegatingRequestMatcher(AntPathRequestMatcher ant, MvcRequestMatcher mvc, - RequestMatcher dispatcherServlet) { - this.ant = ant; - this.mvc = mvc; - this.dispatcherServlet = dispatcherServlet; - } - - RequestMatcher requestMatcher(HttpServletRequest request) { - if (this.dispatcherServlet.matches(request)) { - return this.mvc; - } - return this.ant; - } - - @Override - public boolean matches(HttpServletRequest request) { - return requestMatcher(request).matches(request); - } - - @Override - public MatchResult matcher(HttpServletRequest request) { - return requestMatcher(request).matcher(request); - } - - @Override - public String toString() { - return "DispatcherServletDelegating [" + "ant = " + this.ant + ", mvc = " + this.mvc + "]"; - } - - } - } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/RequestMatcherFactory.java b/config/src/main/java/org/springframework/security/config/annotation/web/RequestMatcherFactory.java index e6cca45bf1..ddf839a6e9 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/RequestMatcherFactory.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/RequestMatcherFactory.java @@ -19,7 +19,6 @@ package org.springframework.security.config.annotation.web; import org.springframework.context.ApplicationContext; import org.springframework.http.HttpMethod; import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; /** @@ -34,11 +33,8 @@ public final class RequestMatcherFactory { private static PathPatternRequestMatcher.Builder builder; public static void setApplicationContext(ApplicationContext context) { - builder = context.getBeanProvider(PathPatternRequestMatcher.Builder.class).getIfUnique(); - } - - public static boolean usesPathPatterns() { - return builder != null; + builder = context.getBeanProvider(PathPatternRequestMatcher.Builder.class) + .getIfUnique(PathPatternRequestMatcher::withDefaults); } public static RequestMatcher matcher(String path) { @@ -46,10 +42,7 @@ public final class RequestMatcherFactory { } public static RequestMatcher matcher(HttpMethod method, String path) { - if (builder != null) { - return builder.matcher(method, path); - } - return new AntPathRequestMatcher(path, (method != null) ? method.name() : null); + return builder.matcher(method, path); } private RequestMatcherFactory() { diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java index 1c89141824..b9ea681ec9 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java @@ -28,7 +28,6 @@ import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.ApplicationContext; import org.springframework.core.OrderComparator; @@ -45,7 +44,6 @@ import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; -import org.springframework.security.config.annotation.web.RequestMatcherFactory; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration; import org.springframework.security.config.annotation.web.configurers.AnonymousConfigurer; @@ -91,17 +89,14 @@ import org.springframework.security.web.PortMapperImpl; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; import org.springframework.security.web.context.SecurityContextRepository; -import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.session.HttpSessionEventPublisher; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AnyRequestMatcher; import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.filter.CorsFilter; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; /** * A {@link HttpSecurity} is similar to Spring Security's XML <http> element in the @@ -153,12 +148,6 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector; public final class HttpSecurity extends AbstractConfiguredSecurityBuilder implements SecurityBuilder, HttpSecurityBuilder { - private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector"; - - private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"; - - private static final boolean mvcPresent; - private final RequestMatcherConfigurer requestMatcherConfigurer; private List filters = new ArrayList<>(); @@ -169,10 +158,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder * @Configuration @@ -2202,10 +2185,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder * Invoking {@link #securityMatcher(String...)} will override previous invocations of @@ -2215,19 +2196,16 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder * @param patterns the pattern to match on (i.e. "/admin/**") * @return the {@link HttpSecurity} for further customizations - * @see AntPathRequestMatcher - * @see MvcRequestMatcher + * @see org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher + * @see org.springframework.web.util.pattern.PathPattern */ public HttpSecurity securityMatcher(String... patterns) { List matchers = new ArrayList<>(); + PathPatternRequestMatcher.Builder builder = getContext() + .getBeanProvider(PathPatternRequestMatcher.Builder.class) + .getIfUnique(PathPatternRequestMatcher::withDefaults); for (String pattern : patterns) { - if (RequestMatcherFactory.usesPathPatterns()) { - matchers.add(RequestMatcherFactory.matcher(pattern)); - } - else { - RequestMatcher matcher = mvcPresent ? createMvcMatcher(pattern) : createAntMatcher(pattern); - matchers.add(matcher); - } + matchers.add(builder.matcher(pattern)); } this.requestMatcher = new OrRequestMatcher(matchers); return this; @@ -2258,26 +2236,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder> postProcessors = getContext().getBeanProvider(type); - ObjectPostProcessor opp = postProcessors.getObject(); - if (!getContext().containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) { - throw new NoSuchBeanDefinitionException("A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME - + " of type " + HandlerMappingIntrospector.class.getName() - + " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext."); - } - HandlerMappingIntrospector introspector = getContext().getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, - HandlerMappingIntrospector.class); - MvcRequestMatcher matcher = new MvcRequestMatcher(introspector, mvcPattern); - opp.postProcess(matcher); - return matcher; - } - /** * If the {@link SecurityConfigurer} has already been specified get the original, * otherwise apply the new {@link SecurityConfigurerAdapter}. diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java index 9b906ebdfd..729690afbb 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java @@ -55,6 +55,7 @@ import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer; import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator; +import org.springframework.security.web.access.PathPatternRequestTransformer; import org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; @@ -430,7 +431,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder requestTransformerClass = HttpServletRequestTransformer.class; this.privilegeEvaluatorRequestTransformer = applicationContext.getBeanProvider(requestTransformerClass) - .getIfUnique(); + .getIfUnique(PathPatternRequestTransformer::new); } @Override diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java index 73a56456d8..3e6459918c 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java @@ -26,15 +26,7 @@ import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; -import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.BeansException; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; -import org.springframework.beans.factory.support.ManagedList; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; @@ -45,8 +37,6 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.access.HandlerMappingIntrospectorRequestTransformer; -import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; import org.springframework.security.web.debug.DebugFilter; import org.springframework.security.web.firewall.HttpFirewall; import org.springframework.security.web.firewall.RequestRejectedHandler; @@ -58,7 +48,6 @@ import org.springframework.web.filter.CompositeFilter; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import org.springframework.web.servlet.support.RequestDataValueProcessor; /** @@ -76,10 +65,6 @@ import org.springframework.web.servlet.support.RequestDataValueProcessor; */ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContextAware { - private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector"; - - private static final String PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME = "pathPatternRequestTransformer"; - private BeanResolver beanResolver; private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder @@ -121,86 +106,6 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex } } - @Bean - static BeanDefinitionRegistryPostProcessor springSecurityHandlerMappingIntrospectorBeanDefinitionRegistryPostProcessor() { - return new BeanDefinitionRegistryPostProcessor() { - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { - } - - @Override - public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { - if (!registry.containsBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) { - return; - } - - String hmiRequestTransformerBeanName = HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + "RequestTransformer"; - if (!registry.containsBeanDefinition(PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME) - && !registry.containsBeanDefinition(hmiRequestTransformerBeanName)) { - if (!registry.containsBeanDefinition(hmiRequestTransformerBeanName)) { - BeanDefinition hmiRequestTransformer = BeanDefinitionBuilder - .rootBeanDefinition(HandlerMappingIntrospectorRequestTransformer.class) - .addConstructorArgReference(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME) - .getBeanDefinition(); - registry.registerBeanDefinition(hmiRequestTransformerBeanName, hmiRequestTransformer); - } - } - - BeanDefinition filterChainProxy = registry - .getBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME); - - if (!filterChainProxy.getResolvableType().isInstance(CompositeFilterChainProxy.class)) { - BeanDefinitionBuilder hmiCacheFilterBldr = BeanDefinitionBuilder - .rootBeanDefinition(HandlerMappingIntrospectorCacheFilterFactoryBean.class) - .setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - - ManagedList filters = new ManagedList<>(); - filters.add(hmiCacheFilterBldr.getBeanDefinition()); - filters.add(filterChainProxy); - BeanDefinitionBuilder compositeSpringSecurityFilterChainBldr = BeanDefinitionBuilder - .rootBeanDefinition(CompositeFilterChainProxy.class) - .addConstructorArgValue(filters); - - registry.removeBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME); - registry.registerBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME, - compositeSpringSecurityFilterChainBldr.getBeanDefinition()); - } - } - }; - } - - /** - * {@link FactoryBean} to defer creation of - * {@link HandlerMappingIntrospector#createCacheFilter()} - * - * @deprecated see {@link WebSecurityConfiguration} for - * {@link org.springframework.web.util.pattern.PathPattern} replacement - */ - @Deprecated - static class HandlerMappingIntrospectorCacheFilterFactoryBean - implements ApplicationContextAware, FactoryBean { - - private ApplicationContext applicationContext; - - @Override - public void setApplicationContext(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - } - - @Override - public Filter getObject() throws Exception { - HandlerMappingIntrospector handlerMappingIntrospector = this.applicationContext - .getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, HandlerMappingIntrospector.class); - return handlerMappingIntrospector.createCacheFilter(); - } - - @Override - public Class getObjectType() { - return Filter.class; - } - - } - /** * Extends {@link FilterChainProxy} to provide as much passivity as possible but * delegates to {@link CompositeFilter} for diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java index 7e31a0ebf9..a3befc654f 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java @@ -69,7 +69,6 @@ import org.springframework.security.web.firewall.HttpFirewall; import org.springframework.security.web.firewall.RequestRejectedHandler; import org.springframework.web.filter.CompositeFilter; import org.springframework.web.filter.ServletRequestPathFilter; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; /** * Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web @@ -209,12 +208,11 @@ public class WebSecurityConfiguration implements ImportAware { /** * Used to ensure Spring MVC request matching is cached. * - * Creates a {@link BeanDefinitionRegistryPostProcessor} that detects if a bean named - * HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME is defined. If so, it moves the + * Creates a {@link BeanDefinitionRegistryPostProcessor} that moves the * AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME to another bean name * and then adds a {@link CompositeFilter} that contains - * {@link HandlerMappingIntrospector#createCacheFilter()} and the original - * FilterChainProxy under the original Bean name. + * {@link ServletRequestPathFilter} and the original FilterChainProxy under the + * original Bean name. * @return */ @Bean diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurer.java index c35c2eb5e2..751f1bf0bc 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurer.java @@ -22,18 +22,14 @@ import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.filter.CorsFilter; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; /** * Adds {@link CorsFilter} to the Spring Security filter chain. If a bean by the name of * corsFilter is provided, that {@link CorsFilter} is used. Else if * corsConfigurationSource is defined, then that {@link CorsConfiguration} is used. - * Otherwise, if Spring MVC is on the classpath a {@link HandlerMappingIntrospector} is - * used. * * @param the builder to return. * @author Rob Winch @@ -45,16 +41,8 @@ public class CorsConfigurer> extends AbstractHt private static final String CORS_FILTER_BEAN_NAME = "corsFilter"; - private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"; - - private static final boolean mvcPresent; - private CorsConfigurationSource configurationSource; - static { - mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, CorsConfigurer.class.getClassLoader()); - } - /** * Creates a new instance * @@ -91,10 +79,7 @@ public class CorsConfigurer> extends AbstractHt CorsConfigurationSource.class); return new CorsFilter(configurationSource); } - if (mvcPresent) { - return MvcCorsFilter.getMvcCorsFilter(context); - } - return null; + return MvcCorsFilter.getMvcCorsFilter(context); } static class MvcCorsFilter { diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurer.java index 3be334a17d..161e8872f7 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurer.java @@ -31,7 +31,6 @@ import org.springframework.security.web.savedrequest.NullRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.RequestCacheAwareFilter; import org.springframework.security.web.util.matcher.AndRequestMatcher; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher; import org.springframework.security.web.util.matcher.NegatedRequestMatcher; import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher; @@ -174,12 +173,7 @@ public final class RequestCacheConfigurer> } private RequestMatcher getFaviconRequestMatcher() { - if (RequestMatcherFactory.usesPathPatterns()) { - return RequestMatcherFactory.matcher("/favicon.*"); - } - else { - return new AntPathRequestMatcher("/**/favicon.*"); - } + return RequestMatcherFactory.matcher("/favicon.*"); } } diff --git a/config/src/main/java/org/springframework/security/config/aot/hint/WebMvcSecurityConfigurationRuntimeHints.java b/config/src/main/java/org/springframework/security/config/aot/hint/WebMvcSecurityConfigurationRuntimeHints.java index 9d292b2477..18ff47e5ca 100644 --- a/config/src/main/java/org/springframework/security/config/aot/hint/WebMvcSecurityConfigurationRuntimeHints.java +++ b/config/src/main/java/org/springframework/security/config/aot/hint/WebMvcSecurityConfigurationRuntimeHints.java @@ -35,10 +35,6 @@ class WebMvcSecurityConfigurationRuntimeHints implements RuntimeHintsRegistrar { .registerType(TypeReference .of("org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy"), MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); - hints.reflection() - .registerType(TypeReference - .of("org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$HandlerMappingIntrospectorCacheFilterFactoryBean"), - MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); } } diff --git a/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java b/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java index 53ff1238b0..dff1e58368 100644 --- a/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java +++ b/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java @@ -153,7 +153,7 @@ class AuthorizationFilterParser implements BeanDefinitionParser { if (!StringUtils.hasText(servletPath)) { servletPath = null; } - else if (!MatcherType.mvc.equals(matcherType)) { + else if (!MatcherType.path.equals(matcherType)) { parserContext.getReaderContext() .error(ATT_SERVLET_PATH + " is not applicable for request-matcher: '" + matcherType.name() + "'", urlElt); diff --git a/config/src/main/java/org/springframework/security/config/http/CorsBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/CorsBeanDefinitionParser.java index 94d8730062..6410f2f2fa 100644 --- a/config/src/main/java/org/springframework/security/config/http/CorsBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/http/CorsBeanDefinitionParser.java @@ -24,7 +24,6 @@ import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.web.filter.CorsFilter; @@ -40,15 +39,6 @@ public class CorsBeanDefinitionParser { private static final String ATT_REF = "ref"; - private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"; - - private static final boolean mvcPresent; - - static { - mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, - CorsBeanDefinitionParser.class.getClassLoader()); - } - public BeanMetadataElement parse(Element element, ParserContext parserContext) { if (element == null) { return null; @@ -71,10 +61,7 @@ public class CorsBeanDefinitionParser { if (StringUtils.hasText(configurationSourceRef)) { return new RuntimeBeanReference(configurationSourceRef); } - if (!mvcPresent) { - return null; - } - return new RootBeanDefinition(HandlerMappingIntrospectorFactoryBean.class); + return new RootBeanDefinition(CorsConfigurationSourceFactoryBean.class); } } diff --git a/config/src/main/java/org/springframework/security/config/http/HandlerMappingIntrospectorFactoryBean.java b/config/src/main/java/org/springframework/security/config/http/CorsConfigurationSourceFactoryBean.java similarity index 76% rename from config/src/main/java/org/springframework/security/config/http/HandlerMappingIntrospectorFactoryBean.java rename to config/src/main/java/org/springframework/security/config/http/CorsConfigurationSourceFactoryBean.java index 302e95834a..60da7445cc 100644 --- a/config/src/main/java/org/springframework/security/config/http/HandlerMappingIntrospectorFactoryBean.java +++ b/config/src/main/java/org/springframework/security/config/http/CorsConfigurationSourceFactoryBean.java @@ -22,38 +22,37 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.lang.Nullable; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; +import org.springframework.web.cors.CorsConfigurationSource; /** - * Used for creating an instance of {@link HandlerMappingIntrospector} and autowiring the + * Used for creating an instance of {@link CorsConfigurationSource} and autowiring the * {@link ApplicationContext}. * * @author Rob Winch * @since 4.1.1 */ -class HandlerMappingIntrospectorFactoryBean - implements FactoryBean, ApplicationContextAware { +class CorsConfigurationSourceFactoryBean implements FactoryBean, ApplicationContextAware { private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector"; private ApplicationContext context; @Override - public HandlerMappingIntrospector getObject() { + public CorsConfigurationSource getObject() { if (!this.context.containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) { throw new NoSuchBeanDefinitionException(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, "A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + " of type " - + HandlerMappingIntrospector.class.getName() - + " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring " + + CorsConfigurationSource.class.getName() + + " is required to use . Please ensure Spring Security & Spring " + "MVC are configured in a shared ApplicationContext."); } - return this.context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, HandlerMappingIntrospector.class); + return this.context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, CorsConfigurationSource.class); } @Nullable @Override public Class getObjectType() { - return HandlerMappingIntrospector.class; + return CorsConfigurationSource.class; } @Override diff --git a/config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java b/config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java index 8f2baeb4c6..84c9d65e97 100644 --- a/config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java +++ b/config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java @@ -40,7 +40,9 @@ import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.UnreachableFilterChainException; +import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.ExceptionTranslationFilter; +import org.springframework.security.web.access.PathPatternRequestTransformer; import org.springframework.security.web.access.intercept.AuthorizationFilter; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; @@ -61,6 +63,8 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain private final Log logger = LogFactory.getLog(getClass()); + private final AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer requestTransformer = new PathPatternRequestTransformer(); + @Override public void validate(FilterChainProxy fcp) { for (SecurityFilterChain filterChain : fcp.getFilterChains()) { @@ -188,7 +192,8 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain String loginPage = ((LoginUrlAuthenticationEntryPoint) exceptions.getAuthenticationEntryPoint()) .getLoginFormUrl(); this.logger.info("Checking whether login URL '" + loginPage + "' is accessible with your configuration"); - FilterInvocation loginRequest = new FilterInvocation(loginPage, "POST"); + FilterInvocation invocation = new FilterInvocation(loginPage, "POST"); + HttpServletRequest loginRequest = this.requestTransformer.transform(invocation.getRequest()); List filters = null; try { filters = fcp.getFilters(loginPage); @@ -237,7 +242,7 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain } } - private boolean checkLoginPageIsPublic(List filters, FilterInvocation loginRequest) { + private boolean checkLoginPageIsPublic(List filters, HttpServletRequest loginRequest) { FilterSecurityInterceptor authorizationInterceptor = getFilter(FilterSecurityInterceptor.class, filters); if (authorizationInterceptor != null) { FilterInvocationSecurityMetadataSource fids = authorizationInterceptor.getSecurityMetadataSource(); @@ -257,7 +262,7 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain AuthorizationManager authorizationManager = authorizationFilter .getAuthorizationManager(); try { - AuthorizationResult result = authorizationManager.authorize(() -> TEST, loginRequest.getHttpRequest()); + AuthorizationResult result = authorizationManager.authorize(() -> TEST, loginRequest); return result != null && result.isGranted(); } catch (Exception ex) { @@ -267,7 +272,7 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain return false; } - private Supplier deriveAnonymousCheck(List filters, FilterInvocation loginRequest, + private Supplier deriveAnonymousCheck(List filters, HttpServletRequest loginRequest, AnonymousAuthenticationToken token) { FilterSecurityInterceptor authorizationInterceptor = getFilter(FilterSecurityInterceptor.class, filters); if (authorizationInterceptor != null) { @@ -288,7 +293,7 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain return () -> { AuthorizationManager authorizationManager = authorizationFilter .getAuthorizationManager(); - AuthorizationResult result = authorizationManager.authorize(() -> token, loginRequest.getHttpRequest()); + AuthorizationResult result = authorizationManager.authorize(() -> token, loginRequest); return result != null && result.isGranted(); }; } diff --git a/config/src/main/java/org/springframework/security/config/http/FilterInvocationSecurityMetadataSourceParser.java b/config/src/main/java/org/springframework/security/config/http/FilterInvocationSecurityMetadataSourceParser.java index 506aa3cd2b..19e0502f4f 100644 --- a/config/src/main/java/org/springframework/security/config/http/FilterInvocationSecurityMetadataSourceParser.java +++ b/config/src/main/java/org/springframework/security/config/http/FilterInvocationSecurityMetadataSourceParser.java @@ -159,7 +159,7 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit if (!StringUtils.hasText(servletPath)) { servletPath = null; } - else if (!MatcherType.mvc.equals(matcherType)) { + else if (!MatcherType.path.equals(matcherType)) { parserContext.getReaderContext() .error(ATT_SERVLET_PATH + " is not applicable for request-matcher: '" + matcherType.name() + "'", urlElt); diff --git a/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java b/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java index 1b22c044f6..93e9fba462 100644 --- a/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java +++ b/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java @@ -50,7 +50,6 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator; -import org.springframework.security.web.access.HandlerMappingIntrospectorRequestTransformer; import org.springframework.security.web.access.PathPatternRequestTransformer; import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl; import org.springframework.security.web.access.channel.ChannelProcessingFilter; @@ -88,7 +87,6 @@ import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; /** * Stateful class which helps HttpSecurityBDP to create the configuration for the @@ -100,11 +98,6 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector; */ class HttpConfigurationBuilder { - private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"; - - private static final boolean mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, - HttpConfigurationBuilder.class.getClassLoader()); - private static final String ATT_CREATE_SESSION = "create-session"; private static final String ATT_SESSION_FIXATION_PROTECTION = "session-fixation-protection"; @@ -793,10 +786,8 @@ class HttpConfigurationBuilder { BeanDefinitionBuilder wipeBldr = BeanDefinitionBuilder .rootBeanDefinition(AuthorizationManagerWebInvocationPrivilegeEvaluator.class) .addConstructorArgReference(authorizationFilterParser.getAuthorizationManagerRef()); - if (mvcPresent) { - wipeBldr.addPropertyValue("requestTransformer", - new RootBeanDefinition(HandlerMappingIntrospectorRequestTransformerFactoryBean.class)); - } + wipeBldr.addPropertyValue("requestTransformer", + new RootBeanDefinition(PathPatternRequestTransformerFactoryBean.class)); BeanDefinition wipe = wipeBldr.getBeanDefinition(); this.pc.registerBeanComponent( new BeanComponentDefinition(wipe, this.pc.getReaderContext().generateBeanName(wipe))); @@ -966,7 +957,7 @@ class HttpConfigurationBuilder { return BeanDefinitionBuilder.rootBeanDefinition(ObservationRegistryFactory.class).getBeanDefinition(); } - static class HandlerMappingIntrospectorRequestTransformerFactoryBean + static class PathPatternRequestTransformerFactoryBean implements FactoryBean, ApplicationContextAware { @@ -982,10 +973,7 @@ class HttpConfigurationBuilder { if (requestTransformer != null) { return requestTransformer; } - HandlerMappingIntrospector hmi = this.applicationContext.getBeanProvider(HandlerMappingIntrospector.class) - .getIfAvailable(); - return (hmi != null) ? new HandlerMappingIntrospectorRequestTransformer(hmi) - : new PathPatternRequestTransformer(); + return new PathPatternRequestTransformer(); } @Override diff --git a/config/src/main/java/org/springframework/security/config/http/MatcherType.java b/config/src/main/java/org/springframework/security/config/http/MatcherType.java index 3755cb84e8..68b1bd960f 100644 --- a/config/src/main/java/org/springframework/security/config/http/MatcherType.java +++ b/config/src/main/java/org/springframework/security/config/http/MatcherType.java @@ -22,13 +22,10 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.http.HttpMethod; -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.security.web.util.matcher.AnyRequestMatcher; import org.springframework.security.web.util.matcher.RegexRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; -import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** @@ -39,21 +36,12 @@ import org.springframework.util.StringUtils; */ public enum MatcherType { - ant(AntPathRequestMatcher.class), regex(RegexRequestMatcher.class), ciRegex(RegexRequestMatcher.class), - mvc(MvcRequestMatcher.class); - - private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"; - - private static final boolean mvcPresent; + path(PathPatternRequestMatcher.class), regex(RegexRequestMatcher.class), ciRegex(RegexRequestMatcher.class); private static final String ATT_MATCHER_TYPE = "request-matcher"; final Class type; - static { - mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, MatcherType.class.getClassLoader()); - } - MatcherType(Class type) { this.type = type; } @@ -66,18 +54,17 @@ public enum MatcherType { if (("/**".equals(path) || "**".equals(path)) && method == null) { return new RootBeanDefinition(AnyRequestMatcher.class); } - BeanDefinitionBuilder matcherBldr = BeanDefinitionBuilder.rootBeanDefinition(this.type); - if (this == mvc) { - matcherBldr.addConstructorArgValue(new RootBeanDefinition(HandlerMappingIntrospectorFactoryBean.class)); - } - matcherBldr.addConstructorArgValue(path); - if (this == mvc) { - matcherBldr.addPropertyValue("method", (StringUtils.hasText(method) ? HttpMethod.valueOf(method) : null)); - matcherBldr.addPropertyValue("servletPath", servletPath); + BeanDefinitionBuilder matcherBldr; + if (this == MatcherType.path) { + matcherBldr = BeanDefinitionBuilder.rootBeanDefinition(PathPatternRequestMatcherFactoryBean.class); + matcherBldr.addConstructorArgValue(path); + matcherBldr.addPropertyValue("basePath", servletPath); } else { - matcherBldr.addConstructorArgValue(method); + matcherBldr = BeanDefinitionBuilder.rootBeanDefinition(this.type); + matcherBldr.addConstructorArgValue(path); } + matcherBldr.addConstructorArgValue(method); if (this == ciRegex) { matcherBldr.addConstructorArgValue(true); } @@ -89,14 +76,10 @@ public enum MatcherType { return valueOf(elt.getAttribute(ATT_MATCHER_TYPE)); } - return ant; + return path; } static MatcherType fromElementOrMvc(Element elt) { - String matcherTypeName = elt.getAttribute(ATT_MATCHER_TYPE); - if (!StringUtils.hasText(matcherTypeName) && mvcPresent) { - return MatcherType.mvc; - } return MatcherType.fromElement(elt); } diff --git a/config/src/main/java/org/springframework/security/config/http/PathPatternRequestMatcherFactoryBean.java b/config/src/main/java/org/springframework/security/config/http/PathPatternRequestMatcherFactoryBean.java new file mode 100644 index 0000000000..7037bd2853 --- /dev/null +++ b/config/src/main/java/org/springframework/security/config/http/PathPatternRequestMatcherFactoryBean.java @@ -0,0 +1,77 @@ +/* + * Copyright 2002-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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.config.http; + +import org.jspecify.annotations.Nullable; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.http.HttpMethod; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; +import org.springframework.util.StringUtils; + +public final class PathPatternRequestMatcherFactoryBean + implements FactoryBean, ApplicationContextAware, InitializingBean { + + private final String pattern; + + private String basePath; + + private HttpMethod method; + + private PathPatternRequestMatcher.Builder builder; + + PathPatternRequestMatcherFactoryBean(String pattern) { + this.pattern = pattern; + } + + PathPatternRequestMatcherFactoryBean(String pattern, String method) { + this.pattern = pattern; + this.method = StringUtils.hasText(method) ? HttpMethod.valueOf(method) : null; + } + + @Override + public @Nullable PathPatternRequestMatcher getObject() throws Exception { + return this.builder.matcher(this.method, this.pattern); + } + + @Override + public @Nullable Class getObjectType() { + return PathPatternRequestMatcher.class; + } + + public void setBasePath(String basePath) { + this.basePath = basePath; + } + + @Override + public void setApplicationContext(ApplicationContext context) throws BeansException { + this.builder = context.getBeanProvider(PathPatternRequestMatcher.Builder.class) + .getIfUnique(PathPatternRequestMatcher::withDefaults); + } + + @Override + public void afterPropertiesSet() throws Exception { + if (this.basePath != null) { + this.builder.basePath(this.basePath); + } + } + +} diff --git a/config/src/main/java/org/springframework/security/config/http/RequestMatcherFactoryBean.java b/config/src/main/java/org/springframework/security/config/http/RequestMatcherFactoryBean.java index f08a21727a..6bb93665f7 100644 --- a/config/src/main/java/org/springframework/security/config/http/RequestMatcherFactoryBean.java +++ b/config/src/main/java/org/springframework/security/config/http/RequestMatcherFactoryBean.java @@ -22,7 +22,6 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.http.HttpMethod; import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; @Deprecated @@ -45,10 +44,7 @@ public final class RequestMatcherFactoryBean implements FactoryBean) protected enum class PatternType { - ANT, MVC + PATH; } } diff --git a/config/src/main/kotlin/org/springframework/security/config/annotation/web/AuthorizeHttpRequestsDsl.kt b/config/src/main/kotlin/org/springframework/security/config/annotation/web/AuthorizeHttpRequestsDsl.kt index 0133670a18..5488dd0289 100644 --- a/config/src/main/kotlin/org/springframework/security/config/annotation/web/AuthorizeHttpRequestsDsl.kt +++ b/config/src/main/kotlin/org/springframework/security/config/annotation/web/AuthorizeHttpRequestsDsl.kt @@ -31,11 +31,9 @@ import org.springframework.security.core.Authentication import org.springframework.security.web.access.IpAddressAuthorizationManager import org.springframework.security.web.access.intercept.AuthorizationFilter import org.springframework.security.web.access.intercept.RequestAuthorizationContext -import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher import org.springframework.security.web.util.matcher.AnyRequestMatcher import org.springframework.security.web.util.matcher.RequestMatcher -import org.springframework.util.ClassUtils -import org.springframework.web.servlet.handler.HandlerMappingIntrospector import java.util.function.Supplier /** @@ -69,12 +67,7 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl { private val rolePrefix: String private val roleHierarchy: RoleHierarchy - private val HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector" - private val HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector" - private val MVC_PRESENT = ClassUtils.isPresent( - HANDLER_MAPPING_INTROSPECTOR, - AuthorizeHttpRequestsDsl::class.java.classLoader) - private val PATTERN_TYPE = if (MVC_PRESENT) PatternType.MVC else PatternType.ANT + private val PATTERN_TYPE = PatternType.PATH /** * Adds a request authorization rule. @@ -288,17 +281,13 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl { when (rule) { is MatcherAuthorizationManagerRule -> requests.requestMatchers(rule.matcher).access(rule.rule) is PatternAuthorizationManagerRule -> { - when (rule.patternType) { - PatternType.ANT -> requests.requestMatchers(rule.httpMethod, rule.pattern).access(rule.rule) - PatternType.MVC -> { - val introspector = requests.applicationContext.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, HandlerMappingIntrospector::class.java) - val mvcMatcher = MvcRequestMatcher.Builder(introspector) - .servletPath(rule.servletPath) - .pattern(rule.pattern) - mvcMatcher.setMethod(rule.httpMethod) - requests.requestMatchers(mvcMatcher).access(rule.rule) - } + var builder = requests.applicationContext.getBeanProvider( + PathPatternRequestMatcher.Builder::class.java) + .getIfUnique(PathPatternRequestMatcher::withDefaults) + if (rule.servletPath != null) { + builder = builder.basePath(rule.servletPath) } + requests.requestMatchers(builder.matcher(rule.httpMethod, rule.pattern)).access(rule.rule) } } } diff --git a/config/src/main/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDsl.kt b/config/src/main/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDsl.kt index f6891ca0ef..2620ccbe82 100644 --- a/config/src/main/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDsl.kt +++ b/config/src/main/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDsl.kt @@ -19,11 +19,9 @@ package org.springframework.security.config.annotation.web import org.springframework.http.HttpMethod import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer -import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher import org.springframework.security.web.util.matcher.AnyRequestMatcher import org.springframework.security.web.util.matcher.RequestMatcher -import org.springframework.util.ClassUtils -import org.springframework.web.servlet.handler.HandlerMappingIntrospector /** * A Kotlin DSL to configure [HttpSecurity] request authorization using idiomatic Kotlin code. @@ -33,13 +31,7 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector */ class AuthorizeRequestsDsl : AbstractRequestMatcherDsl() { private val authorizationRules = mutableListOf() - - private val HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector" - private val HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector" - private val MVC_PRESENT = ClassUtils.isPresent( - HANDLER_MAPPING_INTROSPECTOR, - AuthorizeRequestsDsl::class.java.classLoader) - private val PATTERN_TYPE = if (MVC_PRESENT) PatternType.MVC else PatternType.ANT + private val PATTERN_TYPE = PatternType.PATH; /** * Adds a request authorization rule. @@ -226,17 +218,13 @@ class AuthorizeRequestsDsl : AbstractRequestMatcherDsl() { when (rule) { is MatcherAuthorizationRule -> requests.requestMatchers(rule.matcher).access(rule.rule) is PatternAuthorizationRule -> { - when (rule.patternType) { - PatternType.ANT -> requests.requestMatchers(rule.httpMethod, rule.pattern).access(rule.rule) - PatternType.MVC -> { - val introspector = requests.applicationContext.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, HandlerMappingIntrospector::class.java) - val mvcMatcher = MvcRequestMatcher.Builder(introspector) - .servletPath(rule.servletPath) - .pattern(rule.pattern) - mvcMatcher.setMethod(rule.httpMethod) - requests.requestMatchers(mvcMatcher).access(rule.rule) - } + var builder = requests.applicationContext.getBeanProvider( + PathPatternRequestMatcher.Builder::class.java) + .getIfUnique(PathPatternRequestMatcher::withDefaults); + if (rule.servletPath != null) { + builder = builder.basePath(rule.servletPath) } + requests.requestMatchers(builder.matcher(rule.httpMethod, rule.pattern)).access(rule.rule) } } } diff --git a/config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt b/config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt index b1246a122a..461fe9168c 100644 --- a/config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt +++ b/config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt @@ -73,7 +73,6 @@ operator fun HttpSecurity.invoke(httpConfiguration: HttpSecurityDsl.() -> Unit) */ @SecurityMarker class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecurityDsl.() -> Unit) { - private val HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector" var authenticationManager: AuthenticationManager? = null val context: ApplicationContext = http.getSharedObject(ApplicationContext::class.java) diff --git a/config/src/main/kotlin/org/springframework/security/config/annotation/web/RequiresChannelDsl.kt b/config/src/main/kotlin/org/springframework/security/config/annotation/web/RequiresChannelDsl.kt index e57aaf19a0..fe7f4e78de 100644 --- a/config/src/main/kotlin/org/springframework/security/config/annotation/web/RequiresChannelDsl.kt +++ b/config/src/main/kotlin/org/springframework/security/config/annotation/web/RequiresChannelDsl.kt @@ -20,11 +20,9 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configurers.ChannelSecurityConfigurer import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl import org.springframework.security.web.access.channel.ChannelProcessor -import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher import org.springframework.security.web.util.matcher.AnyRequestMatcher import org.springframework.security.web.util.matcher.RequestMatcher -import org.springframework.util.ClassUtils -import org.springframework.web.servlet.handler.HandlerMappingIntrospector /** * A Kotlin DSL to configure [HttpSecurity] channel security using idiomatic @@ -38,12 +36,7 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector class RequiresChannelDsl : AbstractRequestMatcherDsl() { private val channelSecurityRules = mutableListOf() - private val HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector" - private val HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector" - private val MVC_PRESENT = ClassUtils.isPresent( - HANDLER_MAPPING_INTROSPECTOR, - RequiresChannelDsl::class.java.classLoader) - private val PATTERN_TYPE = if (MVC_PRESENT) PatternType.MVC else PatternType.ANT + private val PATTERN_TYPE = PatternType.PATH var channelProcessors: List? = null @@ -121,17 +114,13 @@ class RequiresChannelDsl : AbstractRequestMatcherDsl() { when (rule) { is MatcherAuthorizationRule -> channelSecurity.requestMatchers(rule.matcher).requires(rule.rule) is PatternAuthorizationRule -> { - when (rule.patternType) { - PatternType.ANT -> channelSecurity.requestMatchers(rule.pattern).requires(rule.rule) - PatternType.MVC -> { - val introspector = channelSecurity.applicationContext.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, HandlerMappingIntrospector::class.java) - val mvcMatcher = MvcRequestMatcher.Builder(introspector) - .servletPath(rule.servletPath) - .pattern(rule.pattern) - mvcMatcher.setMethod(rule.httpMethod) - channelSecurity.requestMatchers(mvcMatcher).requires(rule.rule) - } + var builder = channelSecurity.applicationContext.getBeanProvider( + PathPatternRequestMatcher.Builder::class.java) + .getIfUnique(PathPatternRequestMatcher::withDefaults); + if (rule.servletPath != null) { + builder = builder.basePath(rule.servletPath) } + channelSecurity.requestMatchers(builder.matcher(rule.httpMethod, rule.pattern)).requires(rule.rule) } } } diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc index 323b785386..48433204db 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc @@ -1183,7 +1183,7 @@ hsts-options.attlist &= attribute preload {xsd:boolean}? cors = -## Element for configuration of CorsFilter. If no CorsFilter or CorsConfigurationSource is specified a HandlerMappingIntrospector is used as the CorsConfigurationSource +## Element for configuration of CorsFilter. A CorsConfigurationSource must be specified element cors { cors-options.attlist } cors-options.attlist &= ref? diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd index 676b55a13d..def6b63892 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd @@ -3317,8 +3317,7 @@ - Element for configuration of CorsFilter. If no CorsFilter or CorsConfigurationSource is - specified a HandlerMappingIntrospector is used as the CorsConfigurationSource + Element for configuration of CorsFilter. A CorsConfigurationSource must be specified diff --git a/config/src/test/java/org/springframework/security/config/FilterChainProxyConfigTests.java b/config/src/test/java/org/springframework/security/config/FilterChainProxyConfigTests.java index e2f81e3e17..ba9a6fa5ce 100644 --- a/config/src/test/java/org/springframework/security/config/FilterChainProxyConfigTests.java +++ b/config/src/test/java/org/springframework/security/config/FilterChainProxyConfigTests.java @@ -39,6 +39,7 @@ import org.springframework.security.web.servletapi.SecurityContextHolderAwareReq import org.springframework.security.web.util.matcher.AnyRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.util.pattern.PathPattern; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -120,7 +121,7 @@ public class FilterChainProxyConfigTests { private String getPattern(SecurityFilterChain chain) { RequestMatcher requestMatcher = ((DefaultSecurityFilterChain) chain).getRequestMatcher(); - return (String) ReflectionTestUtils.getField(requestMatcher, "pattern"); + return ((PathPattern) ReflectionTestUtils.getField(requestMatcher, "pattern")).getPatternString(); } private void checkPathAndFilterOrder(FilterChainProxy filterChainProxy) { diff --git a/config/src/test/java/org/springframework/security/config/annotation/issue50/SecurityConfig.java b/config/src/test/java/org/springframework/security/config/annotation/issue50/SecurityConfig.java index 4b338c116d..a2b12f0a83 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/issue50/SecurityConfig.java +++ b/config/src/test/java/org/springframework/security/config/annotation/issue50/SecurityConfig.java @@ -32,7 +32,7 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UsernameNotFoundException; 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.util.Assert; /** @@ -52,7 +52,7 @@ public class SecurityConfig { // @formatter:off http .authorizeRequests((requests) -> requests - .requestMatchers(new AntPathRequestMatcher("/*")).permitAll()) + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/*")).permitAll()) .authenticationProvider(authenticationProvider()); // @formatter:on return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryAnyMatcherTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryAnyMatcherTests.java index 0a0b970968..fc26059e48 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryAnyMatcherTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryAnyMatcherTests.java @@ -24,12 +24,11 @@ import org.springframework.context.annotation.Configuration; import org.springframework.mock.web.MockServletContext; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean; 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.security.web.util.matcher.RegexRequestMatcher; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -88,7 +87,7 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests { http .authorizeRequests((requests) -> requests .anyRequest().authenticated() - .requestMatchers(new AntPathRequestMatcher("/demo/**")).permitAll()); + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/demo/**")).permitAll()); return http.build(); // @formatter:on } @@ -100,12 +99,17 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests { static class MvcMatchersAfterAnyRequestConfig { @Bean - SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + + @Bean + SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { // @formatter:off http .authorizeRequests((requests) -> requests .anyRequest().authenticated() - .requestMatchers(new MvcRequestMatcher(introspector, "/demo/**")).permitAll()); + .requestMatchers(builder.matcher("/demo/**")).permitAll()); return http.build(); // @formatter:on } @@ -156,7 +160,7 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests { http .authorizeRequests((requests) -> requests .anyRequest().authenticated() - .requestMatchers(new AntPathRequestMatcher("/**")).permitAll()); + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/**")).permitAll()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryNoMvcTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryNoMvcTests.java index 4d7c9a18ff..7c943e01e6 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryNoMvcTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryNoMvcTests.java @@ -21,9 +21,10 @@ import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.context.support.GenericApplicationContext; import org.springframework.http.HttpMethod; import org.springframework.security.test.support.ClassPathExclusions; -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; import static org.assertj.core.api.Assertions.assertThat; @@ -41,22 +42,25 @@ public class AbstractRequestMatcherRegistryNoMvcTests { @BeforeEach public void setUp() { this.matcherRegistry = new TestRequestMatcherRegistry(); + GenericApplicationContext context = new GenericApplicationContext(); + context.refresh(); + this.matcherRegistry.setApplicationContext(context); } @Test - public void requestMatchersWhenPatternAndMvcNotPresentThenReturnAntPathRequestMatcherType() { + public void requestMatchersWhenPatternAndMvcNotPresentThenReturnPathPatternRequestMatcherType() { List requestMatchers = this.matcherRegistry.requestMatchers("/path"); assertThat(requestMatchers).isNotEmpty(); assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class); + assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class); } @Test - public void requestMatchersWhenHttpMethodAndPatternAndMvcNotPresentThenReturnAntPathRequestMatcherType() { + public void requestMatchersWhenHttpMethodAndPatternAndMvcNotPresentThenReturnPathPatternRequestMatcherType() { List requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET, "/path"); assertThat(requestMatchers).isNotEmpty(); assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class); + assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class); } @Test @@ -64,7 +68,7 @@ public class AbstractRequestMatcherRegistryNoMvcTests { List requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET); assertThat(requestMatchers).isNotEmpty(); assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class); + assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class); } private static class TestRequestMatcherRegistry extends AbstractRequestMatcherRegistry> { diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryTests.java index 70f383c203..e098d11b38 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryTests.java @@ -16,47 +16,30 @@ package org.springframework.security.config.annotation.web; -import java.util.ArrayList; import java.util.List; +import java.util.stream.Stream; import jakarta.servlet.DispatcherType; -import jakarta.servlet.Servlet; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.core.ResolvableType; import org.springframework.http.HttpMethod; -import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.security.config.ObjectPostProcessor; -import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.DispatcherServletDelegatingRequestMatcher; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.test.SpringTestContext; -import org.springframework.security.web.servlet.MockServletContext; -import org.springframework.security.web.servlet.TestMockHttpServletMappings; -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.security.web.util.matcher.DispatcherTypeRequestMatcher; import org.springframework.security.web.util.matcher.RegexRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.InstanceOfAssertFactories.type; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; /** * Tests for {@link AbstractRequestMatcherRegistry}. @@ -86,9 +69,13 @@ public class AbstractRequestMatcherRegistryTests { ObjectProvider> given = this.context.getBeanProvider(type); given(given).willReturn(postProcessors); given(postProcessors.getObject()).willReturn(NO_OP_OBJECT_POST_PROCESSOR); - given(this.context.getServletContext()).willReturn(MockServletContext.mvc()); + given(this.context.getBeanProvider(any(Class.class))).willReturn(new ObjectProvider<>() { + @Override + public Stream stream() { + return Stream.of(); + } + }); this.matcherRegistry.setApplicationContext(this.context); - mockMvcIntrospector(true); } @Test @@ -110,24 +97,25 @@ public class AbstractRequestMatcherRegistryTests { } @Test - public void antMatchersWhenHttpMethodAndPatternParamsThenReturnAntPathRequestMatcherType() { + public void pathPatternWhenHttpMethodAndPatternParamsThenReturnPathPatternRequestMatcherType() { List requestMatchers = this.matcherRegistry - .requestMatchers(new AntPathRequestMatcher("/a.*", HttpMethod.GET.name())); + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/a.*")); assertThat(requestMatchers).isNotEmpty(); assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class); + assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class); } @Test - public void antMatchersWhenPatternParamThenReturnAntPathRequestMatcherType() { - List requestMatchers = this.matcherRegistry.requestMatchers(new AntPathRequestMatcher("/a.*")); + public void pathPatternWhenPatternParamThenReturnPathPatternRequestMatcherType() { + List requestMatchers = this.matcherRegistry + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/a.*")); assertThat(requestMatchers).isNotEmpty(); assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class); + assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class); } @Test - public void dispatcherTypeMatchersWhenHttpMethodAndPatternParamsThenReturnAntPathRequestMatcherType() { + public void dispatcherTypeMatchersWhenHttpMethodAndPatternParamsThenReturnPathPatternRequestMatcherType() { List requestMatchers = this.matcherRegistry.dispatcherTypeMatchers(HttpMethod.GET, DispatcherType.ASYNC); assertThat(requestMatchers).isNotEmpty(); @@ -136,7 +124,7 @@ public class AbstractRequestMatcherRegistryTests { } @Test - public void dispatcherMatchersWhenPatternParamThenReturnAntPathRequestMatcherType() { + public void dispatcherMatchersWhenPatternParamThenReturnPathPatternRequestMatcherType() { List requestMatchers = this.matcherRegistry.dispatcherTypeMatchers(DispatcherType.INCLUDE); assertThat(requestMatchers).isNotEmpty(); assertThat(requestMatchers).hasSize(1); @@ -144,252 +132,36 @@ public class AbstractRequestMatcherRegistryTests { } @Test - public void requestMatchersWhenPatternAndMvcPresentThenReturnMvcRequestMatcherType() { + public void requestMatchersWhenPatternAndMvcPresentThenReturnPathPatternRequestMatcherType() { List requestMatchers = this.matcherRegistry.requestMatchers("/path"); assertThat(requestMatchers).isNotEmpty(); assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).isExactlyInstanceOf(MvcRequestMatcher.class); + assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class); } @Test - public void requestMatchersWhenHttpMethodAndPatternAndMvcPresentThenReturnMvcRequestMatcherType() { + public void requestMatchersWhenHttpMethodAndPatternAndMvcPresentThenReturnPathPatternRequestMatcherType() { List requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET, "/path"); assertThat(requestMatchers).isNotEmpty(); assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).isExactlyInstanceOf(MvcRequestMatcher.class); + assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class); } @Test - public void requestMatchersWhenHttpMethodAndMvcPresentThenReturnMvcRequestMatcherType() { + public void requestMatchersWhenHttpMethodAndMvcPresentThenReturnPathPatternRequestMatcherType() { List requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET); assertThat(requestMatchers).isNotEmpty(); assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).isExactlyInstanceOf(MvcRequestMatcher.class); - } - - @Test - public void requestMatchersWhenMvcPresentInClassPathAndMvcIntrospectorBeanNotAvailableThenException() { - mockMvcIntrospector(false); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.matcherRegistry.requestMatchers("/path")) - .withMessageContaining( - "Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext"); - } - - @Test - public void requestMatchersWhenNoDispatcherServletThenAntPathRequestMatcherType() { - mockMvcIntrospector(true); - MockServletContext servletContext = new MockServletContext(); - given(this.context.getServletContext()).willReturn(servletContext); - MockHttpServletRequest request = new MockHttpServletRequest(); - List requestMatchers = this.matcherRegistry.requestMatchers("/**"); - assertThat(requestMatchers).isNotEmpty(); - assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class)) - .extracting((matcher) -> matcher.requestMatcher(request)) - .isInstanceOf(AntPathRequestMatcher.class); - servletContext.addServlet("servletOne", Servlet.class).addMapping("/one"); - servletContext.addServlet("servletTwo", Servlet.class).addMapping("/two"); - requestMatchers = this.matcherRegistry.requestMatchers("/**"); - assertThat(requestMatchers).isNotEmpty(); - assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class)) - .extracting((matcher) -> matcher.requestMatcher(request)) - .isInstanceOf(AntPathRequestMatcher.class); - servletContext.addServlet("servletOne", Servlet.class); - servletContext.addServlet("servletTwo", Servlet.class); - requestMatchers = this.matcherRegistry.requestMatchers("/**"); - assertThat(requestMatchers).isNotEmpty(); - assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class)) - .extracting((matcher) -> matcher.requestMatcher(request)) - .isInstanceOf(AntPathRequestMatcher.class); - } - - // gh-14418 - @Test - public void requestMatchersWhenNoDispatcherServletMockMvcThenMvcRequestMatcherType() throws Exception { - MockServletContext servletContext = new MockServletContext(); - try (SpringTestContext spring = new SpringTestContext(this)) { - spring.register(MockMvcConfiguration.class) - .postProcessor((context) -> context.setServletContext(servletContext)) - .autowire(); - this.matcherRegistry.setApplicationContext(spring.getContext()); - MockMvc mvc = MockMvcBuilders.webAppContextSetup(spring.getContext()).build(); - MockHttpServletRequest request = mvc.perform(get("/")).andReturn().getRequest(); - List requestMatchers = this.matcherRegistry.requestMatchers("/**"); - assertThat(requestMatchers).isNotEmpty(); - assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class)) - .extracting((matcher) -> matcher.requestMatcher(request)) - .isInstanceOf(MvcRequestMatcher.class); - servletContext.addServlet("servletOne", Servlet.class).addMapping("/one"); - servletContext.addServlet("servletTwo", Servlet.class).addMapping("/two"); - requestMatchers = this.matcherRegistry.requestMatchers("/**"); - assertThat(requestMatchers).isNotEmpty(); - assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class)) - .extracting((matcher) -> matcher.requestMatcher(request)) - .isInstanceOf(MvcRequestMatcher.class); - servletContext.addServlet("servletOne", Servlet.class); - servletContext.addServlet("servletTwo", Servlet.class); - requestMatchers = this.matcherRegistry.requestMatchers("/**"); - assertThat(requestMatchers).isNotEmpty(); - assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class)) - .extracting((matcher) -> matcher.requestMatcher(request)) - .isInstanceOf(MvcRequestMatcher.class); - } - } - - @Test - public void requestMatchersWhenAmbiguousServletsThenException() { - mockMvcIntrospector(true); - MockServletContext servletContext = new MockServletContext(); - given(this.context.getServletContext()).willReturn(servletContext); - servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/"); - servletContext.addServlet("servletTwo", DispatcherServlet.class).addMapping("/servlet/*"); - assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> this.matcherRegistry.requestMatchers("/**")); - } - - @Test - public void requestMatchersWhenMultipleDispatcherServletMappingsThenException() { - mockMvcIntrospector(true); - MockServletContext servletContext = new MockServletContext(); - given(this.context.getServletContext()).willReturn(servletContext); - servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/", "/mvc/*"); - assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> this.matcherRegistry.requestMatchers("/**")); - } - - @Test - public void requestMatchersWhenPathDispatcherServletAndOtherServletsThenException() { - mockMvcIntrospector(true); - MockServletContext servletContext = new MockServletContext(); - given(this.context.getServletContext()).willReturn(servletContext); - servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*"); - servletContext.addServlet("default", Servlet.class).addMapping("/"); - assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> this.matcherRegistry.requestMatchers("/**")); - } - - @Test - public void requestMatchersWhenUnmappableServletsThenSkips() { - mockMvcIntrospector(true); - MockServletContext servletContext = new MockServletContext(); - given(this.context.getServletContext()).willReturn(servletContext); - servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/"); - servletContext.addServlet("servletTwo", Servlet.class); - List requestMatchers = this.matcherRegistry.requestMatchers("/**"); - assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).isInstanceOf(MvcRequestMatcher.class); - } - - @Test - public void requestMatchersWhenOnlyDispatcherServletThenAllows() { - MockServletContext servletContext = new MockServletContext(); - given(this.context.getServletContext()).willReturn(servletContext); - servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*"); - List requestMatchers = this.matcherRegistry.requestMatchers("/**"); - assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).isInstanceOf(MvcRequestMatcher.class); - } - - @Test - public void requestMatchersWhenImplicitServletsThenAllows() { - mockMvcIntrospector(true); - MockServletContext servletContext = new MockServletContext(); - given(this.context.getServletContext()).willReturn(servletContext); - servletContext.addServlet("defaultServlet", Servlet.class); - servletContext.addServlet("jspServlet", Servlet.class).addMapping("*.jsp", "*.jspx"); - servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/"); - List requestMatchers = this.matcherRegistry.requestMatchers("/**"); - assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).isInstanceOf(DispatcherServletDelegatingRequestMatcher.class); - } - - @Test - public void requestMatchersWhenPathBasedNonDispatcherServletThenAllows() { - MockServletContext servletContext = new MockServletContext(); - given(this.context.getServletContext()).willReturn(servletContext); - servletContext.addServlet("path", Servlet.class).addMapping("/services/*"); - servletContext.addServlet("default", DispatcherServlet.class).addMapping("/"); - List requestMatchers = this.matcherRegistry.requestMatchers("/services/*"); - assertThat(requestMatchers).hasSize(1); - assertThat(requestMatchers.get(0)).isInstanceOf(DispatcherServletDelegatingRequestMatcher.class); - MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/services/endpoint"); - request.setHttpServletMapping(TestMockHttpServletMappings.defaultMapping()); - assertThat(requestMatchers.get(0).matcher(request).isMatch()).isTrue(); - request.setHttpServletMapping(TestMockHttpServletMappings.path(request, "/services")); - request.setServletPath("/services"); - request.setPathInfo("/endpoint"); - assertThat(requestMatchers.get(0).matcher(request).isMatch()).isTrue(); - } - - @Test - public void matchesWhenDispatcherServletThenMvc() { - MockServletContext servletContext = new MockServletContext(); - servletContext.addServlet("default", DispatcherServlet.class).addMapping("/"); - servletContext.addServlet("path", Servlet.class).addMapping("/services/*"); - MvcRequestMatcher mvc = mock(MvcRequestMatcher.class); - AntPathRequestMatcher ant = mock(AntPathRequestMatcher.class); - RequestMatcher requestMatcher = new DispatcherServletDelegatingRequestMatcher(ant, mvc); - MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/services/endpoint"); - request.setHttpServletMapping(TestMockHttpServletMappings.defaultMapping()); - assertThat(requestMatcher.matches(request)).isFalse(); - verify(mvc).matches(request); - verifyNoInteractions(ant); - request.setHttpServletMapping(TestMockHttpServletMappings.path(request, "/services")); - assertThat(requestMatcher.matches(request)).isFalse(); - verify(ant).matches(request); - verifyNoMoreInteractions(mvc); - } - - @Test - public void matchesWhenNoMappingThenException() { - MockServletContext servletContext = new MockServletContext(); - servletContext.addServlet("default", DispatcherServlet.class).addMapping("/"); - servletContext.addServlet("path", Servlet.class).addMapping("/services/*"); - MvcRequestMatcher mvc = mock(MvcRequestMatcher.class); - AntPathRequestMatcher ant = mock(AntPathRequestMatcher.class); - RequestMatcher requestMatcher = new DispatcherServletDelegatingRequestMatcher(ant, mvc); - MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/services/endpoint"); - assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> requestMatcher.matcher(request)); - } - - private void mockMvcIntrospector(boolean isPresent) { - ApplicationContext context = this.matcherRegistry.getApplicationContext(); - given(context.containsBean("mvcHandlerMappingIntrospector")).willReturn(isPresent); + assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class); } private static class TestRequestMatcherRegistry extends AbstractRequestMatcherRegistry> { - @Override - public List requestMatchers(RequestMatcher... requestMatchers) { - return unwrap(super.requestMatchers(requestMatchers)); - } - @Override protected List chainRequestMatchers(List requestMatchers) { return requestMatchers; } - private List unwrap(List wrappedMatchers) { - List requestMatchers = new ArrayList<>(); - for (RequestMatcher requestMatcher : wrappedMatchers) { - if (requestMatcher instanceof DeferredRequestMatcher) { - DeferredRequestMatcher deferred = (DeferredRequestMatcher) requestMatcher; - WebApplicationContext web = (WebApplicationContext) getApplicationContext(); - requestMatchers.add(deferred.requestMatcher(web.getServletContext())); - } - else { - requestMatchers.add(requestMatcher); - } - } - return requestMatchers; - } - } @Configuration diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/builders/HttpConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/builders/HttpConfigurationTests.java index 7a4cb72b10..1adbaf66b9 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/builders/HttpConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/builders/HttpConfigurationTests.java @@ -39,7 +39,7 @@ import org.springframework.security.core.userdetails.PasswordEncodedUser; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.provisioning.InMemoryUserDetailsManager; 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.test.web.servlet.MockMvc; import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -150,8 +150,8 @@ public class HttpConfigurationTests { // @formatter:off http .securityMatchers((security) -> security - .requestMatchers(new AntPathRequestMatcher("/api/**")) - .requestMatchers(new AntPathRequestMatcher("/oauth/**"))) + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/api/**")) + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/oauth/**"))) .authorizeRequests((requests) -> requests .anyRequest().hasRole("USER")) .httpBasic(withDefaults()); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java index 6aa7666b5d..bf86f97e1a 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java @@ -54,8 +54,8 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; import org.springframework.security.web.context.NullSecurityContextRepository; import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.RegexRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.stereotype.Controller; @@ -195,13 +195,13 @@ public class NamespaceHttpTests { } @Test // http@request-matcher-ref ant - public void configureWhenAntPatternMatchingThenAntPathRequestMatcherUsed() { + public void configureWhenAntPatternMatchingThenPathPatternRequestMatcherUsed() { this.spring.register(RequestMatcherAntConfig.class).autowire(); FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class); assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class); DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains() .get(0); - assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class); + assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(PathPatternRequestMatcher.class); } @Test // http@request-matcher-ref regex @@ -226,21 +226,21 @@ public class NamespaceHttpTests { } @Test // http@security=none - public void configureWhenIgnoredAntPatternsThenAntPathRequestMatcherUsedWithNoFilters() { + public void configureWhenIgnoredAntPatternsThenPathPatternRequestMatcherUsedWithNoFilters() { this.spring.register(SecurityNoneConfig.class).autowire(); FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class); assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class); DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains() .get(0); - assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class); - assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern()) - .isEqualTo("/resources/**"); + assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(PathPatternRequestMatcher.class); + assertThat(securityFilterChain.getRequestMatcher()) + .isEqualTo(PathPatternRequestMatcher.withDefaults().matcher("/resources/**")); assertThat(securityFilterChain.getFilters()).isEmpty(); assertThat(filterChainProxy.getFilterChains().get(1)).isInstanceOf(DefaultSecurityFilterChain.class); securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains().get(1); - assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class); - assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern()) - .isEqualTo("/public/**"); + assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(PathPatternRequestMatcher.class); + assertThat(securityFilterChain.getRequestMatcher()) + .isEqualTo(PathPatternRequestMatcher.withDefaults().matcher("/public/**")); assertThat(securityFilterChain.getFilters()).isEmpty(); } @@ -482,7 +482,7 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatcher(new AntPathRequestMatcher("/api/**")); + .securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/api/**")); return http.build(); // @formatter:on } @@ -534,8 +534,9 @@ public class NamespaceHttpTests { @Bean WebSecurityCustomizer webSecurityCustomizer() { + PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withDefaults(); return (web) -> web.ignoring() - .requestMatchers(new AntPathRequestMatcher("/resources/**"), new AntPathRequestMatcher("/public/**")); + .requestMatchers(builder.matcher("/resources/**"), builder.matcher("/public/**")); } @Bean diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityFilterChainValidatorTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityFilterChainValidatorTests.java index 450a3dfdc1..62845140c6 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityFilterChainValidatorTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityFilterChainValidatorTests.java @@ -31,7 +31,7 @@ import org.springframework.security.web.UnreachableFilterChainException; import org.springframework.security.web.access.ExceptionTranslationFilter; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.util.matcher.AnyRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.security.web.util.matcher.RequestMatchers; @@ -49,6 +49,8 @@ public class WebSecurityFilterChainValidatorTests { private final WebSecurityFilterChainValidator validator = new WebSecurityFilterChainValidator(); + private final PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withDefaults(); + @Mock private AnonymousAuthenticationFilter authenticationFilter; @@ -60,7 +62,7 @@ public class WebSecurityFilterChainValidatorTests { @Test void validateWhenFilterSecurityInterceptorConfiguredThenValidates() { - SecurityFilterChain chain = new DefaultSecurityFilterChain(AntPathRequestMatcher.antMatcher("/api"), + SecurityFilterChain chain = new DefaultSecurityFilterChain(this.builder.matcher("/api"), this.authenticationFilter, this.exceptionTranslationFilter, this.authorizationInterceptor); FilterChainProxy proxy = new FilterChainProxy(List.of(chain)); @@ -69,7 +71,7 @@ public class WebSecurityFilterChainValidatorTests { @Test void validateWhenAnyRequestMatcherIsPresentThenUnreachableFilterChainException() { - SecurityFilterChain chain1 = new DefaultSecurityFilterChain(AntPathRequestMatcher.antMatcher("/api"), + SecurityFilterChain chain1 = new DefaultSecurityFilterChain(this.builder.matcher("/api"), this.authenticationFilter, this.exceptionTranslationFilter, this.authorizationInterceptor); SecurityFilterChain chain2 = new DefaultSecurityFilterChain(AnyRequestMatcher.INSTANCE, this.authenticationFilter, this.exceptionTranslationFilter, this.authorizationInterceptor); @@ -84,9 +86,9 @@ public class WebSecurityFilterChainValidatorTests { @Test void validateWhenSameRequestMatchersArePresentThenUnreachableFilterChainException() { - SecurityFilterChain chain1 = new DefaultSecurityFilterChain(AntPathRequestMatcher.antMatcher("/api"), + SecurityFilterChain chain1 = new DefaultSecurityFilterChain(this.builder.matcher("/api"), this.authenticationFilter, this.exceptionTranslationFilter, this.authorizationInterceptor); - SecurityFilterChain chain2 = new DefaultSecurityFilterChain(AntPathRequestMatcher.antMatcher("/api"), + SecurityFilterChain chain2 = new DefaultSecurityFilterChain(this.builder.matcher("/api"), this.authenticationFilter, this.exceptionTranslationFilter, this.authorizationInterceptor); List chains = new ArrayList<>(); chains.add(chain2); @@ -99,10 +101,12 @@ public class WebSecurityFilterChainValidatorTests { @Test void validateWhenSameComposedRequestMatchersArePresentThenUnreachableFilterChainException() { - RequestMatcher matcher1 = RequestMatchers.anyOf(RequestMatchers.allOf(AntPathRequestMatcher.antMatcher("/api"), - AntPathRequestMatcher.antMatcher("*.do")), AntPathRequestMatcher.antMatcher("/admin")); - RequestMatcher matcher2 = RequestMatchers.anyOf(RequestMatchers.allOf(AntPathRequestMatcher.antMatcher("/api"), - AntPathRequestMatcher.antMatcher("*.do")), AntPathRequestMatcher.antMatcher("/admin")); + RequestMatcher matcher1 = RequestMatchers.anyOf( + RequestMatchers.allOf(this.builder.matcher("/api"), this.builder.matcher("/*.do")), + this.builder.matcher("/admin")); + RequestMatcher matcher2 = RequestMatchers.anyOf( + RequestMatchers.allOf(this.builder.matcher("/api"), this.builder.matcher("/*.do")), + this.builder.matcher("/admin")); SecurityFilterChain chain1 = new DefaultSecurityFilterChain(matcher1, this.authenticationFilter, this.exceptionTranslationFilter, this.authorizationInterceptor); SecurityFilterChain chain2 = new DefaultSecurityFilterChain(matcher2, this.authenticationFilter, diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java index 2b58af889f..fb3389e86c 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java @@ -37,17 +37,17 @@ import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockServletContext; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; +import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean; import org.springframework.security.core.userdetails.PasswordEncodedUser; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandler; -import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.security.config.Customizer.withDefaults; @@ -130,8 +130,13 @@ public class WebSecurityTests { static class MvcMatcherConfig { @Bean - WebSecurityCustomizer webSecurityCustomizer(HandlerMappingIntrospector introspector) { - return (web) -> web.ignoring().requestMatchers(new MvcRequestMatcher(introspector, "/path")); + PathPatternRequestMatcherBuilderFactoryBean pathPatternRequestMatcherBuilder() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + + @Bean + WebSecurityCustomizer webSecurityCustomizer(PathPatternRequestMatcher.Builder builder) { + return (web) -> web.ignoring().requestMatchers(builder.matcher("/path")); } @Bean @@ -168,9 +173,15 @@ public class WebSecurityTests { static class MvcMatcherServletPathConfig { @Bean - WebSecurityCustomizer webSecurityCustomizer(HandlerMappingIntrospector introspector) { - MvcRequestMatcher.Builder builder = new MvcRequestMatcher.Builder(introspector).servletPath("/spring"); - return (web) -> web.ignoring().requestMatchers(builder.pattern("/path")).requestMatchers("/notused"); + PathPatternRequestMatcherBuilderFactoryBean pathPatternRequestMatcherBuilder() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + + @Bean + WebSecurityCustomizer webSecurityCustomizer(PathPatternRequestMatcher.Builder builder) { + return (web) -> web.ignoring() + .requestMatchers(builder.basePath("/spring").matcher("/path")) + .requestMatchers("/notused"); } @Bean diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/AuthorizationManagerWebInvocationPrivilegeEvaluatorConfigTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/AuthorizationManagerWebInvocationPrivilegeEvaluatorConfigTests.java index 90297c75ef..866cd95503 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/AuthorizationManagerWebInvocationPrivilegeEvaluatorConfigTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/AuthorizationManagerWebInvocationPrivilegeEvaluatorConfigTests.java @@ -26,20 +26,19 @@ import org.springframework.security.authentication.TestAuthentication; import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners; import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer; -import org.springframework.security.web.access.HandlerMappingIntrospectorRequestTransformer; import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; /** - * Checks that HandlerMappingIntrospectorRequestTransformer is autowired into + * Checks that + * {@link org.springframework.security.web.access.PathPatternRequestTransformer} is + * autowired into * {@link org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator}. * * @author Rob Winch @@ -59,20 +58,8 @@ public class AuthorizationManagerWebInvocationPrivilegeEvaluatorConfigTests { WebInvocationPrivilegeEvaluator wipe; @Test - void mvcEnabledConfigThenHandlerMappingIntrospectorRequestTransformerBeanExists() { - this.spring.register(MvcEnabledConfig.class).autowire(); - assertThat(this.requestTransformer).isInstanceOf(HandlerMappingIntrospectorRequestTransformer.class); - } - - @Test - void mvcNotEnabledThenNoRequestTransformerBeanExists() { - this.spring.register(MvcNotEnabledConfig.class).autowire(); - assertThat(this.requestTransformer).isNull(); - } - - @Test - void mvcNotEnabledAndTransformerThenWIPEDelegatesToTransformer() { - this.spring.register(MvcNotEnabledConfig.class, TransformerConfig.class).autowire(); + void webAndTransformerThenWIPEDelegatesToTransformer() { + this.spring.register(WebConfig.class, TransformerConfig.class).autowire(); this.wipe.isAllowed("/uri", TestAuthentication.authenticatedUser()); @@ -90,15 +77,8 @@ public class AuthorizationManagerWebInvocationPrivilegeEvaluatorConfigTests { } @Configuration - @EnableWebMvc @EnableWebSecurity - static class MvcEnabledConfig { - - } - - @Configuration - @EnableWebSecurity - static class MvcNotEnabledConfig { + static class WebConfig { } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HandlerMappingIntrospectorCacheFilterConfigTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HandlerMappingIntrospectorCacheFilterConfigTests.java deleted file mode 100644 index 865b99ee21..0000000000 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HandlerMappingIntrospectorCacheFilterConfigTests.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2002-2023 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.web.configuration; - -import java.io.IOException; - -import jakarta.servlet.Filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; -import jakarta.servlet.http.HttpServletRequest; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.test.SpringTestContext; -import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.stereotype.Component; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector.CachedResult; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; - -/** - * @author Rob Winch - */ -@ContextConfiguration -@WebAppConfiguration -@ExtendWith({ SpringExtension.class }) -@SecurityTestExecutionListeners -class HandlerMappingIntrospectorCacheFilterConfigTests { - - @Autowired - WebApplicationContext context; - - MockMvc mockMvc; - - public final SpringTestContext spring = new SpringTestContext(this); - - @Autowired(required = false) - MvcEnabledConfig.CaptureHandlerMappingIntrospectorCache captureCacheFilter; - - @Autowired(required = false) - HandlerMappingIntrospector hmi; - - @Test - @WithMockUser - void hmiIsCached() throws Exception { - this.spring.register(MvcEnabledConfig.class).autowire(); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(springSecurity()) - .addFilter(this.captureCacheFilter) - .build(); - this.mockMvc.perform(get("/")); - assertThat(this.captureCacheFilter.cachedResult).isNotNull(); - } - - @Test - @WithMockUser - void configurationLoadsIfNoHMI() { - // no BeanCreationException due to missing HandlerMappingIntrospector - this.spring.register(MvcNotEnabledConfig.class).autowire(); - // ensure assumption of HandlerMappingIntrospector is null is true - assertThat(this.hmi).isNull(); - } - - @Configuration - @EnableWebMvc - @EnableWebSecurity - static class MvcEnabledConfig { - - @Component - static class CaptureHandlerMappingIntrospectorCache implements Filter { - - final HandlerMappingIntrospector hmi; - - private CachedResult cachedResult; - - CaptureHandlerMappingIntrospectorCache(HandlerMappingIntrospector hmi) { - this.hmi = hmi; - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - // capture the old cached value to check that caching has already occurred - this.cachedResult = this.hmi.setCache((HttpServletRequest) request); - chain.doFilter(request, response); - } - - } - - } - - @Configuration - @EnableWebSecurity - static class MvcNotEnabledConfig { - - } - -} diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java index 311bae361d..450e3b2396 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java @@ -63,7 +63,6 @@ import org.springframework.security.web.access.RequestMatcherDelegatingWebInvoca import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.test.web.servlet.MockMvc; import org.springframework.util.ClassUtils; import org.springframework.web.bind.annotation.GetMapping; @@ -106,14 +105,13 @@ public class WebSecurityConfigurationTests { FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class); List filterChains = filterChainProxy.getFilterChains(); assertThat(filterChains).hasSize(4); - MockHttpServletRequest request = new MockHttpServletRequest("GET", ""); - request.setServletPath("/role1/**"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/role1/**"); assertThat(filterChains.get(0).matches(request)).isTrue(); - request.setServletPath("/role2/**"); + request = new MockHttpServletRequest("GET", "/role2/**"); assertThat(filterChains.get(1).matches(request)).isTrue(); - request.setServletPath("/role3/**"); + request = new MockHttpServletRequest("GET", "/role3/**"); assertThat(filterChains.get(2).matches(request)).isTrue(); - request.setServletPath("/**"); + request = new MockHttpServletRequest("GET", "/**"); assertThat(filterChains.get(3).matches(request)).isTrue(); } @@ -123,10 +121,9 @@ public class WebSecurityConfigurationTests { FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class); List filterChains = filterChainProxy.getFilterChains(); assertThat(filterChains).hasSize(2); - MockHttpServletRequest request = new MockHttpServletRequest("GET", ""); - request.setServletPath("/role1/**"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/role1/**"); assertThat(filterChains.get(0).matches(request)).isTrue(); - request.setServletPath("/role2/**"); + request = new MockHttpServletRequest("GET", "/role2/**"); assertThat(filterChains.get(1).matches(request)).isTrue(); } @@ -240,14 +237,13 @@ public class WebSecurityConfigurationTests { FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class); List filterChains = filterChainProxy.getFilterChains(); assertThat(filterChains).hasSize(3); - MockHttpServletRequest request = new MockHttpServletRequest("GET", ""); - request.setServletPath("/ignore1"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/ignore1"); assertThat(filterChains.get(0).matches(request)).isTrue(); assertThat(filterChains.get(0).getFilters()).isEmpty(); - request.setServletPath("/ignore2"); + request = new MockHttpServletRequest("GET", "/ignore2"); assertThat(filterChains.get(1).matches(request)).isTrue(); assertThat(filterChains.get(1).getFilters()).isEmpty(); - request.setServletPath("/test/**"); + request = new MockHttpServletRequest("GET", "/test/**"); assertThat(filterChains.get(2).matches(request)).isTrue(); } @@ -257,16 +253,15 @@ public class WebSecurityConfigurationTests { FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class); List filterChains = filterChainProxy.getFilterChains(); assertThat(filterChains).hasSize(3); - MockHttpServletRequest request = new MockHttpServletRequest("GET", ""); - request.setServletPath("/ignore1"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/ignore1"); assertThat(filterChains.get(0).matches(request)).isTrue(); assertThat(filterChains.get(0).getFilters()).isEmpty(); - request.setServletPath("/ignore2"); + request = new MockHttpServletRequest("GET", "/ignore2"); assertThat(filterChains.get(1).matches(request)).isTrue(); assertThat(filterChains.get(1).getFilters()).isEmpty(); - request.setServletPath("/role1/**"); + request = new MockHttpServletRequest("GET", "/role1/**"); assertThat(filterChains.get(2).matches(request)).isTrue(); - request.setServletPath("/test/**"); + request = new MockHttpServletRequest("GET", "/test/**"); assertThat(filterChains.get(2).matches(request)).isFalse(); } @@ -276,11 +271,10 @@ public class WebSecurityConfigurationTests { FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class); List filterChains = filterChainProxy.getFilterChains(); assertThat(filterChains).hasSize(3); - MockHttpServletRequest request = new MockHttpServletRequest("GET", ""); - request.setServletPath("/ignore1"); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/ignore1"); assertThat(filterChains.get(0).matches(request)).isTrue(); assertThat(filterChains.get(0).getFilters()).isEmpty(); - request.setServletPath("/ignore2"); + request = new MockHttpServletRequest("GET", "/ignore2"); assertThat(filterChains.get(1).matches(request)).isTrue(); assertThat(filterChains.get(1).getFilters()).isEmpty(); } @@ -420,7 +414,7 @@ public class WebSecurityConfigurationTests { SecurityFilterChain filterChain1(HttpSecurity http) throws Exception { // @formatter:off return http - .securityMatcher(new AntPathRequestMatcher("/role1/**")) + .securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/role1/**")) .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("1") ) @@ -433,7 +427,7 @@ public class WebSecurityConfigurationTests { SecurityFilterChain filterChain2(HttpSecurity http) throws Exception { // @formatter:off return http - .securityMatcher(new AntPathRequestMatcher("/role2/**")) + .securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/role2/**")) .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("2") ) @@ -446,7 +440,7 @@ public class WebSecurityConfigurationTests { SecurityFilterChain filterChain3(HttpSecurity http) throws Exception { // @formatter:off return http - .securityMatcher(new AntPathRequestMatcher("/role3/**")) + .securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/role3/**")) .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("3") ) @@ -477,7 +471,7 @@ public class WebSecurityConfigurationTests { SecurityFilterChain securityFilterChain1(HttpSecurity http) throws Exception { // @formatter:off return http - .securityMatcher(new AntPathRequestMatcher("/role1/**")) + .securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/role1/**")) .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("1") ) @@ -734,7 +728,7 @@ public class WebSecurityConfigurationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .securityMatcher(new AntPathRequestMatcher("/role1/**")) + .securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/role1/**")) .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("1") ) @@ -773,7 +767,7 @@ public class WebSecurityConfigurationTests { public SecurityFilterChain path1(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/path1/**"))) + .securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/path1/**"))) .authorizeRequests((requests) -> requests.anyRequest().authenticated()); // @formatter:on return http.build(); @@ -797,7 +791,7 @@ public class WebSecurityConfigurationTests { public SecurityFilterChain path1(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/path1/**"))) + .securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/path1/**"))) .authorizeRequests((requests) -> requests.anyRequest().authenticated()); // @formatter:on return http.build(); @@ -822,7 +816,7 @@ public class WebSecurityConfigurationTests { public SecurityFilterChain notAuthorized(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/user"))) + .securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/user"))) .authorizeRequests((requests) -> requests.anyRequest().hasRole("USER")); // @formatter:on return http.build(); @@ -833,7 +827,7 @@ public class WebSecurityConfigurationTests { public SecurityFilterChain path1(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/admin"))) + .securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/admin"))) .authorizeRequests((requests) -> requests.anyRequest().hasRole("ADMIN")); // @formatter:on return http.build(); @@ -864,7 +858,7 @@ public class WebSecurityConfigurationTests { public SecurityFilterChain notAuthorized(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/user"))) + .securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/user"))) .authorizeRequests((requests) -> requests.anyRequest().hasRole("USER")); // @formatter:on return http.build(); @@ -875,7 +869,7 @@ public class WebSecurityConfigurationTests { public SecurityFilterChain admin(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/admin"))) + .securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/admin"))) .authorizeRequests((requests) -> requests.anyRequest().hasRole("ADMIN")); // @formatter:on return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistryTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistryTests.java index e34de7c883..d04ca12251 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistryTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistryTests.java @@ -22,7 +22,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; 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.RegexRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; @@ -55,19 +55,20 @@ public class AbstractConfigAttributeRequestMatcherRegistryTests { } @Test - public void testGetRequestMatcherIsTypeAntPathRequestMatcher() { + public void testGetRequestMatcherIsTypePathPatternRequestMatcher() { List requestMatchers = this.registry - .requestMatchers(new AntPathRequestMatcher("/a.*", HttpMethod.GET.name())); + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/a.*")); for (RequestMatcher requestMatcher : requestMatchers) { - assertThat(requestMatcher).isInstanceOf(AntPathRequestMatcher.class); + assertThat(requestMatcher).isInstanceOf(PathPatternRequestMatcher.class); } } @Test - public void testRequestMatcherIsTypeAntPathRequestMatcher() { - List requestMatchers = this.registry.requestMatchers(new AntPathRequestMatcher("/a.*")); + public void testRequestMatcherIsTypePathPatternRequestMatcher() { + List requestMatchers = this.registry + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/a.*")); for (RequestMatcher requestMatcher : requestMatchers) { - assertThat(requestMatcher).isInstanceOf(AntPathRequestMatcher.class); + assertThat(requestMatcher).isInstanceOf(PathPatternRequestMatcher.class); } } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java index b2bd973bee..20507ab65f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java @@ -68,7 +68,6 @@ import org.springframework.security.web.access.expression.WebExpressionAuthoriza import org.springframework.security.web.access.intercept.AuthorizationFilter; import org.springframework.security.web.access.intercept.RequestAuthorizationContext; import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager; -import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.stereotype.Component; import org.springframework.test.web.servlet.MockMvc; @@ -81,7 +80,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -148,7 +146,7 @@ public class AuthorizeHttpRequestsConfigurerTests { public void configureWhenMvcMatcherAfterAnyRequestThenException() { assertThatExceptionOfType(BeanCreationException.class) .isThrownBy(() -> this.spring.register(AfterAnyRequestConfig.class).autowire()) - .withMessageContaining("Can't configure mvcMatchers after anyRequest"); + .withMessageContaining("Can't configure requestMatchers after anyRequest"); } @Test @@ -689,7 +687,7 @@ public class AuthorizeHttpRequestsConfigurerTests { @Test public void requestMatchersWhenMultipleDispatcherServletsAndPathBeanThenAllows() throws Exception { - this.spring.register(MvcRequestMatcherBuilderConfig.class, BasicController.class) + this.spring.register(PathPatternRequestMatcherBuilderConfig.class, BasicController.class) .postProcessor((context) -> context.getServletContext() .addServlet("otherDispatcherServlet", DispatcherServlet.class) .addMapping("/mvc")) @@ -1063,13 +1061,16 @@ public class AuthorizeHttpRequestsConfigurerTests { static class ServletPathConfig { @Bean - SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { - MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector) - .servletPath("/spring"); + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + + @Bean + SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { // @formatter:off return http .authorizeHttpRequests((authorize) -> authorize - .requestMatchers(mvcMatcherBuilder.pattern("/")).hasRole("ADMIN") + .requestMatchers(builder.basePath("/spring").matcher("/")).hasRole("ADMIN") ) .build(); // @formatter:on @@ -1358,7 +1359,7 @@ public class AuthorizeHttpRequestsConfigurerTests { @Configuration @EnableWebSecurity @EnableWebMvc - static class MvcRequestMatcherBuilderConfig { + static class PathPatternRequestMatcherBuilderConfig { @Bean SecurityFilterChain security(HttpSecurity http) throws Exception { diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java index 992dc0de1f..03a8f48e44 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java @@ -33,6 +33,7 @@ import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextImpl; @@ -42,13 +43,12 @@ import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.springframework.security.web.servlet.MockServletContext; -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.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; +import org.springframework.web.util.pattern.PathPatternParser; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.spy; @@ -111,10 +111,12 @@ public class AuthorizeRequestsTests { public void antMatchersPathVariables() throws Exception { loadConfig(AntPatchersPathVariables.class); this.request.setServletPath("/user/user"); + this.request.setRequestURI("/user/user"); this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); this.setup(); this.request.setServletPath("/user/deny"); + this.request.setRequestURI("/user/deny"); this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN); } @@ -124,10 +126,12 @@ public class AuthorizeRequestsTests { public void antMatchersPathVariablesCaseInsensitive() throws Exception { loadConfig(AntPatchersPathVariables.class); this.request.setServletPath("/USER/user"); + this.request.setRequestURI("/USER/user"); this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); this.setup(); this.request.setServletPath("/USER/deny"); + this.request.setRequestURI("/USER/deny"); this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN); } @@ -137,10 +141,12 @@ public class AuthorizeRequestsTests { public void antMatchersPathVariablesCaseInsensitiveCamelCaseVariables() throws Exception { loadConfig(AntMatchersPathVariablesCamelCaseVariables.class); this.request.setServletPath("/USER/user"); + this.request.setRequestURI("/USER/user"); this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); this.setup(); this.request.setServletPath("/USER/deny"); + this.request.setRequestURI("/USER/deny"); this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN); } @@ -199,7 +205,7 @@ public class AuthorizeRequestsTests { // @formatter:off http .authorizeRequests((requests) -> requests - .requestMatchers(new AntPathRequestMatcher("/**", HttpMethod.POST.name())).denyAll()); + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/**")).denyAll()); // @formatter:on return http.build(); } @@ -220,7 +226,7 @@ public class AuthorizeRequestsTests { // @formatter:off http .authorizeRequests((authorize) -> authorize - .requestMatchers(new AntPathRequestMatcher("/**", HttpMethod.POST.name())).denyAll() + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/**")).denyAll() ); // @formatter:on return http.build(); @@ -239,10 +245,13 @@ public class AuthorizeRequestsTests { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + PathPatternParser parser = new PathPatternParser(); + parser.setCaseSensitive(false); + PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withPathPatternParser(parser); // @formatter:off http .authorizeRequests((requests) -> requests - .requestMatchers(new AntPathRequestMatcher("/user/{user}", null, false)).access("#user == 'user'") + .requestMatchers(builder.matcher("/user/{user}")).access("#user == 'user'") .anyRequest().denyAll()); // @formatter:on return http.build(); @@ -261,10 +270,13 @@ public class AuthorizeRequestsTests { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + PathPatternParser parser = new PathPatternParser(); + parser.setCaseSensitive(false); + PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withPathPatternParser(parser); // @formatter:off http .authorizeRequests((requests) -> requests - .requestMatchers(new AntPathRequestMatcher("/user/{userName}", null, false)).access("#userName == 'user'") + .requestMatchers(builder.matcher("/user/{userName}")).access("#userName == 'user'") .anyRequest().denyAll()); // @formatter:on return http.build(); @@ -378,14 +390,18 @@ public class AuthorizeRequestsTests { static class MvcMatcherServletPathConfig { @Bean - SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { - MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector) - .servletPath("/spring"); + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + + @Bean + SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { + PathPatternRequestMatcher.Builder spring = builder.basePath("/spring"); // @formatter:off http .httpBasic(withDefaults()) .authorizeRequests((requests) -> requests - .requestMatchers(mvcMatcherBuilder.pattern("/path")).denyAll()); + .requestMatchers(spring.matcher("/path")).denyAll()); // @formatter:on return http.build(); } @@ -413,14 +429,18 @@ public class AuthorizeRequestsTests { static class MvcMatcherServletPathInLambdaConfig { @Bean - SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { - MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector) - .servletPath("/spring"); + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + + @Bean + SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { + PathPatternRequestMatcher.Builder spring = builder.basePath("/spring"); // @formatter:off http .httpBasic(withDefaults()) .authorizeRequests((authorize) -> authorize - .requestMatchers(mvcMatcherBuilder.pattern("/path")).denyAll() + .requestMatchers(spring.matcher("/path")).denyAll() ); // @formatter:on return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java index 377445bb0a..20bb13e739 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java @@ -28,7 +28,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; 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.security.web.util.matcher.RequestMatcher; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.bind.annotation.RequestMapping; @@ -109,7 +109,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests { // @formatter:off http .csrf((csrf) -> csrf - .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/path")) + .requireCsrfProtectionMatcher(PathPatternRequestMatcher.withDefaults().matcher("/path")) .ignoringRequestMatchers(this.requestMatcher)); return http.build(); // @formatter:on @@ -129,7 +129,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests { // @formatter:off http .csrf((csrf) -> csrf - .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/path")) + .requireCsrfProtectionMatcher(PathPatternRequestMatcher.withDefaults().matcher("/path")) .ignoringRequestMatchers(this.requestMatcher) ); return http.build(); @@ -149,7 +149,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests { // @formatter:off http .csrf((csrf) -> csrf - .ignoringRequestMatchers(new AntPathRequestMatcher("/no-csrf")) + .ignoringRequestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/no-csrf")) .ignoringRequestMatchers(this.requestMatcher)); return http.build(); // @formatter:on @@ -169,7 +169,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests { // @formatter:off http .csrf((csrf) -> csrf - .ignoringRequestMatchers(new AntPathRequestMatcher("/no-csrf")) + .ignoringRequestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/no-csrf")) .ignoringRequestMatchers(this.requestMatcher) ); return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java index ce08191199..4220b752ac 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java @@ -57,7 +57,7 @@ import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler import org.springframework.security.web.firewall.StrictHttpFirewall; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; -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; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -906,7 +906,7 @@ public class CsrfConfigurerTests { http .formLogin(withDefaults()) .logout((logout) -> logout - .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))); + .logoutRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher("/logout"))); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java index 46d0fbe54a..93af0fe725 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java @@ -128,8 +128,7 @@ public class DefaultFiltersTests { public void defaultFiltersPermitAll() throws IOException, ServletException { this.spring.register(DefaultFiltersConfigPermitAll.class, UserDetailsServiceConfig.class); MockHttpServletResponse response = new MockHttpServletResponse(); - MockHttpServletRequest request = new MockHttpServletRequest("POST", ""); - request.setServletPath("/logout"); + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/logout"); CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN"); CsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); repository.saveToken(csrfToken, request, response); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java index ad1de31fe2..e20a47c00a 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java @@ -32,7 +32,7 @@ import org.springframework.security.test.context.support.WithMockUser; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.access.AccessDeniedHandlerImpl; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.util.matcher.AnyRequestMatcher; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; @@ -92,7 +92,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests { .exceptionHandling((handling) -> handling .defaultAccessDeniedHandlerFor( this.teapotDeniedHandler, - new AntPathRequestMatcher("/hello/**")) + PathPatternRequestMatcher.withDefaults().matcher("/hello/**")) .defaultAccessDeniedHandlerFor( new AccessDeniedHandlerImpl(), AnyRequestMatcher.INSTANCE)); @@ -119,7 +119,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests { .exceptionHandling((exceptionHandling) -> exceptionHandling .defaultAccessDeniedHandlerFor( this.teapotDeniedHandler, - new AntPathRequestMatcher("/hello/**") + PathPatternRequestMatcher.withDefaults().matcher("/hello/**") ) .defaultAccessDeniedHandlerFor( new AccessDeniedHandlerImpl(), @@ -148,7 +148,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests { .exceptionHandling((handling) -> handling .defaultAccessDeniedHandlerFor( this.teapotDeniedHandler, - new AntPathRequestMatcher("/hello/**"))); + PathPatternRequestMatcher.withDefaults().matcher("/hello/**"))); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java index 85d7838988..c970ae7509 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java @@ -32,16 +32,16 @@ import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockServletContext; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.security.config.Customizer.withDefaults; @@ -167,16 +167,20 @@ public class HttpSecurityRequestMatchersTests { @EnableWebMvc static class MultiMvcMatcherInLambdaConfig { + @Bean + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + @Bean @Order(Ordered.HIGHEST_PRECEDENCE) - SecurityFilterChain first(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { - MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector); + SecurityFilterChain first(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { // @formatter:off http .securityMatchers((requests) -> requests - .requestMatchers(mvcMatcherBuilder.pattern("/test-1")) - .requestMatchers(mvcMatcherBuilder.pattern("/test-2")) - .requestMatchers(mvcMatcherBuilder.pattern("/test-3")) + .requestMatchers(builder.matcher("/test-1")) + .requestMatchers(builder.matcher("/test-2")) + .requestMatchers(builder.matcher("/test-3")) ) .authorizeRequests((authorize) -> authorize.anyRequest().denyAll()) .httpBasic(withDefaults()); @@ -185,12 +189,11 @@ public class HttpSecurityRequestMatchersTests { } @Bean - SecurityFilterChain second(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { - MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector); + SecurityFilterChain second(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { // @formatter:off http .securityMatchers((requests) -> requests - .requestMatchers(mvcMatcherBuilder.pattern("/test-1")) + .requestMatchers(builder.matcher("/test-1")) ) .authorizeRequests((authorize) -> authorize .anyRequest().permitAll() @@ -216,16 +219,20 @@ public class HttpSecurityRequestMatchersTests { @EnableWebMvc static class MultiMvcMatcherConfig { + @Bean + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + @Bean @Order(Ordered.HIGHEST_PRECEDENCE) - SecurityFilterChain first(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { - MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector); + SecurityFilterChain first(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { // @formatter:off http .securityMatchers((security) -> security - .requestMatchers(mvcMatcherBuilder.pattern("/test-1")) - .requestMatchers(mvcMatcherBuilder.pattern("/test-2")) - .requestMatchers(mvcMatcherBuilder.pattern("/test-3"))) + .requestMatchers(builder.matcher("/test-1")) + .requestMatchers(builder.matcher("/test-2")) + .requestMatchers(builder.matcher("/test-3"))) .authorizeRequests((requests) -> requests .anyRequest().denyAll()) .httpBasic(withDefaults()); @@ -234,12 +241,11 @@ public class HttpSecurityRequestMatchersTests { } @Bean - SecurityFilterChain second(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { - MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector); + SecurityFilterChain second(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { // @formatter:off http .securityMatchers((security) -> security - .requestMatchers(mvcMatcherBuilder.pattern("/test-1"))) + .requestMatchers(builder.matcher("/test-1"))) .authorizeRequests((requests) -> requests .anyRequest().permitAll()); // @formatter:on @@ -264,10 +270,15 @@ public class HttpSecurityRequestMatchersTests { static class MvcMatcherConfig { @Bean - SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + + @Bean + SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { // @formatter:off http - .securityMatcher(new MvcRequestMatcher(introspector, "/path")) + .securityMatcher(builder.matcher("/path")) .httpBasic(withDefaults()) .authorizeRequests((requests) -> requests .anyRequest().denyAll()); @@ -298,11 +309,16 @@ public class HttpSecurityRequestMatchersTests { static class RequestMatchersMvcMatcherConfig { @Bean - SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + + @Bean + SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { // @formatter:off http .securityMatchers((security) -> security - .requestMatchers(new MvcRequestMatcher(introspector, "/path"))) + .requestMatchers(builder.matcher("/path"))) .httpBasic(withDefaults()) .authorizeRequests((requests) -> requests .anyRequest().denyAll()); @@ -333,11 +349,16 @@ public class HttpSecurityRequestMatchersTests { static class RequestMatchersMvcMatcherInLambdaConfig { @Bean - SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + + @Bean + SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { // @formatter:off http .securityMatchers((secure) -> secure - .requestMatchers(new MvcRequestMatcher(introspector, "/path")) + .requestMatchers(builder.matcher("/path")) ) .httpBasic(withDefaults()) .authorizeRequests((authorize) -> authorize @@ -365,13 +386,16 @@ public class HttpSecurityRequestMatchersTests { static class RequestMatchersMvcMatcherServeltPathConfig { @Bean - SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { - MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector); - mvcMatcherBuilder.servletPath("/spring"); + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + + @Bean + SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { // @formatter:off http .securityMatchers((security) -> security - .requestMatchers(mvcMatcherBuilder.pattern("/path")) + .requestMatchers(builder.basePath("/spring").matcher("/path")) .requestMatchers("/never-match")) .httpBasic(withDefaults()) .authorizeRequests((requests) -> requests @@ -403,13 +427,16 @@ public class HttpSecurityRequestMatchersTests { static class RequestMatchersMvcMatcherServletPathInLambdaConfig { @Bean - SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { - MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector); - mvcMatcherBuilder.servletPath("/spring"); + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + + @Bean + SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { // @formatter:off http .securityMatchers((secure) -> secure - .requestMatchers(mvcMatcherBuilder.pattern("/path")) + .requestMatchers(builder.basePath("/spring").matcher("/path")) .requestMatchers("/never-match") ) .httpBasic(withDefaults()) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersNoMvcTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersNoMvcTests.java index c6afdf3572..a1625bce35 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersNoMvcTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersNoMvcTests.java @@ -37,7 +37,7 @@ import org.springframework.security.test.support.ClassPathExclusions; import org.springframework.security.web.DefaultSecurityFilterChain; 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.security.web.util.matcher.RequestMatcher; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.web.bind.annotation.RequestMapping; @@ -101,7 +101,7 @@ public class HttpSecuritySecurityMatchersNoMvcTests { .findFirst() .get(); assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - assertThat(requestMatchers).hasOnlyElementsOfType(AntPathRequestMatcher.class); + assertThat(requestMatchers).hasOnlyElementsOfType(PathPatternRequestMatcher.class); } public void loadConfig(Class... configs) { diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java index 9de85b6957..ad624affdb 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java @@ -32,6 +32,7 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; @@ -39,12 +40,11 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.servlet.MockServletContext; -import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.security.config.Customizer.withDefaults; @@ -356,14 +356,18 @@ public class HttpSecuritySecurityMatchersTests { static class SecurityMatchersMvcMatcherServletPathConfig { @Bean - SecurityFilterChain appSecurity(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { - MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector) - .servletPath("/spring"); + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + + @Bean + SecurityFilterChain appSecurity(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { + PathPatternRequestMatcher.Builder spring = builder.basePath("/spring"); // @formatter:off http .securityMatchers((security) -> security - .requestMatchers(mvcMatcherBuilder.pattern("/path")) - .requestMatchers(mvcMatcherBuilder.pattern("/never-match")) + .requestMatchers(spring.matcher("/path")) + .requestMatchers(spring.matcher("/never-match")) ) .httpBasic(withDefaults()) .authorizeHttpRequests((authorize) -> authorize @@ -391,14 +395,18 @@ public class HttpSecuritySecurityMatchersTests { static class SecurityMatchersMvcMatcherServletPathInLambdaConfig { @Bean - SecurityFilterChain appSecurity(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { - MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector) - .servletPath("/spring"); + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + + @Bean + SecurityFilterChain appSecurity(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { + PathPatternRequestMatcher.Builder spring = builder.basePath("/spring"); // @formatter:off http .securityMatchers((matchers) -> matchers - .requestMatchers(mvcMatcherBuilder.pattern("/path")) - .requestMatchers(mvcMatcherBuilder.pattern("/never-match")) + .requestMatchers(spring.matcher("/path")) + .requestMatchers(spring.matcher("/never-match")) ) .httpBasic(withDefaults()) .authorizeHttpRequests((authorize) -> authorize diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java index 0d02e44132..0831bdc7ce 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java @@ -43,7 +43,6 @@ import org.springframework.security.web.authentication.RememberMeServices; import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices; import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken; import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; @@ -349,7 +348,7 @@ public class NamespaceRememberMeTests { SecurityFilterChain withoutKeyFilterChain(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatcher(new AntPathRequestMatcher("/without-key/**")) + .securityMatcher("/without-key/**") .authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()) .formLogin((login) -> login .loginProcessingUrl("/without-key/login")) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java index d28dca2d42..1aa2919a17 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java @@ -27,7 +27,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; 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.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -79,9 +79,9 @@ public class RequestMatcherConfigurerTests { // @formatter:off http .securityMatchers((security) -> security - .requestMatchers(new AntPathRequestMatcher("/api/**"))) + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/api/**"))) .securityMatchers((security) -> security - .requestMatchers(new AntPathRequestMatcher("/oauth/**"))) + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/oauth/**"))) .authorizeRequests((requests) -> requests .anyRequest().denyAll()); return http.build(); @@ -99,10 +99,10 @@ public class RequestMatcherConfigurerTests { // @formatter:off http .securityMatchers((secure) -> secure - .requestMatchers(new AntPathRequestMatcher("/api/**")) + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/api/**")) ) .securityMatchers((securityMatchers) -> securityMatchers - .requestMatchers(new AntPathRequestMatcher("/oauth/**")) + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/oauth/**")) ) .authorizeRequests((authorize) -> authorize .anyRequest().denyAll() diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java index cd32887961..65d449efe9 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java @@ -78,7 +78,7 @@ public class SessionManagementConfigurerServlet31Tests { @Test public void changeSessionIdThenPreserveParameters() throws Exception { - MockHttpServletRequest request = new MockHttpServletRequest("GET", ""); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/login"); String id = request.getSession().getId(); request.getSession(); request.setServletPath("/login"); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java index d0728428dc..b0359a68b2 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java @@ -33,6 +33,7 @@ import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean; import org.springframework.security.core.userdetails.PasswordEncodedUser; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; @@ -41,12 +42,11 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.servlet.MockServletContext; -import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.security.config.Customizer.withDefaults; @@ -131,14 +131,19 @@ public class UrlAuthorizationConfigurerTests { @EnableWebMvc static class MvcMatcherConfig { + @Bean + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + @Bean SecurityFilterChain filterChain(HttpSecurity http, ApplicationContext context, - HandlerMappingIntrospector introspector) throws Exception { + PathPatternRequestMatcher.Builder builder) throws Exception { // @formatter:off http .httpBasic(withDefaults()) .apply(new UrlAuthorizationConfigurer(context)).getRegistry() - .requestMatchers(new MvcRequestMatcher(introspector, "/path")).hasRole("ADMIN"); + .requestMatchers(builder.matcher("/path")).hasRole("ADMIN"); // @formatter:on return http.build(); } @@ -165,16 +170,20 @@ public class UrlAuthorizationConfigurerTests { @EnableWebMvc static class MvcMatcherServletPathConfig { + @Bean + PathPatternRequestMatcherBuilderFactoryBean pathPattern() { + return new PathPatternRequestMatcherBuilderFactoryBean(); + } + @Bean SecurityFilterChain filterChain(HttpSecurity http, ApplicationContext context, - HandlerMappingIntrospector introspector) throws Exception { - MvcRequestMatcher mvcRequestMatcher = new MvcRequestMatcher(introspector, "/path"); - mvcRequestMatcher.setServletPath("/spring"); + PathPatternRequestMatcher.Builder builder) throws Exception { + PathPatternRequestMatcher.Builder spring = builder.basePath("/spring"); // @formatter:off http .httpBasic(withDefaults()) .apply(new UrlAuthorizationConfigurer(context)).getRegistry() - .requestMatchers(mvcRequestMatcher).hasRole("ADMIN"); + .requestMatchers(builder.matcher("/path")).hasRole("ADMIN"); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java index cc1a30a381..f361eacfd5 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java @@ -185,7 +185,7 @@ public class OAuth2LoginConfigurerTests { @BeforeEach public void setup() { - this.request = new MockHttpServletRequest("GET", ""); + this.request = new MockHttpServletRequest("GET", "/login/oauth2/code/google"); this.request.setServletPath("/login/oauth2/code/google"); this.response = new MockHttpServletResponse(); this.filterChain = new MockFilterChain(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurerTests.java index 36c2d0895c..72c638807f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurerTests.java @@ -38,6 +38,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.http.HttpMethod; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpSession; @@ -76,7 +77,7 @@ import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.logout.LogoutFilter; import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.RequestPostProcessor; @@ -620,7 +621,7 @@ public class Saml2LogoutConfigurerTests { .saml2Logout((saml2) -> saml2.addObjectPostProcessor(new ObjectPostProcessor() { @Override public O postProcess(O filter) { - filter.setLogoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET")); + filter.setLogoutRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/logout")); return filter; } })); diff --git a/config/src/test/java/org/springframework/security/config/aot/hint/WebMvcSecurityConfigurationRuntimeHintsTests.java b/config/src/test/java/org/springframework/security/config/aot/hint/WebMvcSecurityConfigurationRuntimeHintsTests.java index 906deec0e9..57f9a82750 100644 --- a/config/src/test/java/org/springframework/security/config/aot/hint/WebMvcSecurityConfigurationRuntimeHintsTests.java +++ b/config/src/test/java/org/springframework/security/config/aot/hint/WebMvcSecurityConfigurationRuntimeHintsTests.java @@ -53,12 +53,4 @@ class WebMvcSecurityConfigurationRuntimeHintsTests { .withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(this.hints); } - @Test - void handlerMappingIntrospectorCacheFilterFactoryBeanHasHints() { - assertThat(RuntimeHintsPredicates.reflection() - .onType(TypeReference - .of("org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$HandlerMappingIntrospectorCacheFilterFactoryBean")) - .withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(this.hints); - } - } diff --git a/config/src/test/java/org/springframework/security/config/http/DefaultFilterChainValidatorTests.java b/config/src/test/java/org/springframework/security/config/http/DefaultFilterChainValidatorTests.java index d75ce815d5..48568cbf04 100644 --- a/config/src/test/java/org/springframework/security/config/http/DefaultFilterChainValidatorTests.java +++ b/config/src/test/java/org/springframework/security/config/http/DefaultFilterChainValidatorTests.java @@ -44,7 +44,7 @@ import org.springframework.security.web.access.intercept.FilterInvocationSecurit import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.util.matcher.AnyRequestMatcher; import org.springframework.test.util.ReflectionTestUtils; @@ -144,12 +144,13 @@ public class DefaultFilterChainValidatorTests { @Test void validateWhenSameRequestMatchersArePresentThenUnreachableFilterChainException() { + PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withDefaults(); AnonymousAuthenticationFilter authenticationFilter = mock(AnonymousAuthenticationFilter.class); ExceptionTranslationFilter exceptionTranslationFilter = mock(ExceptionTranslationFilter.class); - SecurityFilterChain chain1 = new DefaultSecurityFilterChain(AntPathRequestMatcher.antMatcher("/api"), - authenticationFilter, exceptionTranslationFilter, this.authorizationInterceptor); - SecurityFilterChain chain2 = new DefaultSecurityFilterChain(AntPathRequestMatcher.antMatcher("/api"), - authenticationFilter, exceptionTranslationFilter, this.authorizationInterceptor); + SecurityFilterChain chain1 = new DefaultSecurityFilterChain(builder.matcher("/api"), authenticationFilter, + exceptionTranslationFilter, this.authorizationInterceptor); + SecurityFilterChain chain2 = new DefaultSecurityFilterChain(builder.matcher("/api"), authenticationFilter, + exceptionTranslationFilter, this.authorizationInterceptor); List chains = new ArrayList<>(); chains.add(chain2); chains.add(chain1); diff --git a/config/src/test/java/org/springframework/security/config/http/FilterSecurityMetadataSourceBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/http/FilterSecurityMetadataSourceBeanDefinitionParserTests.java index 21972bac10..dd6c1264d3 100644 --- a/config/src/test/java/org/springframework/security/config/http/FilterSecurityMetadataSourceBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/http/FilterSecurityMetadataSourceBeanDefinitionParserTests.java @@ -92,12 +92,10 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests { public void interceptUrlsSupportPropertyPlaceholders() { System.setProperty("secure.url", "/secure"); System.setProperty("secure.role", "ROLE_A"); - setContext( - "" - + "" - + "" - + " " - + ""); + setContext("" + + "" + + " " + + ""); DefaultFilterInvocationSecurityMetadataSource fids = (DefaultFilterInvocationSecurityMetadataSource) this.appContext .getBean("fids"); Collection cad = fids.getAttributes(createFilterInvocation("/secure", "GET")); @@ -107,8 +105,7 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests { @Test public void parsingWithinFilterSecurityInterceptorIsSuccessful() { // @formatter:off - setContext("" + - "" + setContext("" + "" + " " + " " diff --git a/config/src/test/java/org/springframework/security/config/http/FormLoginConfigTests.java b/config/src/test/java/org/springframework/security/config/http/FormLoginConfigTests.java index 9088bb443f..0665978b43 100644 --- a/config/src/test/java/org/springframework/security/config/http/FormLoginConfigTests.java +++ b/config/src/test/java/org/springframework/security/config/http/FormLoginConfigTests.java @@ -72,7 +72,7 @@ public class FormLoginConfigTests { @Test public void getProtectedPageWhenFormLoginConfiguredThenRedirectsToDefaultLoginPage() throws Exception { - this.spring.configLocations(this.xml("WithAntRequestMatcher")).autowire(); + this.spring.configLocations(this.xml("WithRequestMatcher")).autowire(); // @formatter:off this.mvc.perform(get("/")) .andExpect(redirectedUrl("http://localhost/login")); diff --git a/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java b/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java index f0f983022f..69245d6bac 100644 --- a/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java +++ b/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java @@ -25,7 +25,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.stubbing.Answer; -import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.mock.web.MockServletContext; @@ -38,7 +37,6 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.context.ConfigurableWebApplicationContext; import org.springframework.web.util.WebUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -250,21 +248,6 @@ public class InterceptUrlConfigTests { assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull(); } - @Test - public void requestWhenUsingMvcMatchersThenAuthorizesRequestsAccordingly() throws Exception { - this.spring.configLocations(this.xml("MvcMatchers")).autowire(); - this.mvc.perform(get("/path")).andExpect(status().isUnauthorized()); - } - - @Test - public void requestWhenUsingMvcMatchersAndAuthorizationManagerThenAuthorizesRequestsAccordingly() throws Exception { - this.spring.configLocations(this.xml("MvcMatchersAuthorizationManager")).autowire(); - this.mvc.perform(get("/path")).andExpect(status().isUnauthorized()); - this.mvc.perform(get("/path.html")).andExpect(status().isUnauthorized()); - this.mvc.perform(get("/path/")).andExpect(status().isUnauthorized()); - assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull(); - } - @Test public void requestWhenUsingMvcMatchersAndPathVariablesThenAuthorizesRequestsAccordingly() throws Exception { this.spring.configLocations(this.xml("MvcMatchersPathVariables")).autowire(); @@ -293,48 +276,6 @@ public class InterceptUrlConfigTests { assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull(); } - @Test - public void requestWhenUsingMvcMatchersAndServletPathThenAuthorizesRequestsAccordingly() throws Exception { - this.spring.configLocations(this.xml("MvcMatchersServletPath")).autowire(); - MockServletContext servletContext = mockServletContext("/spring"); - ConfigurableWebApplicationContext context = this.spring.getContext(); - context.setServletContext(servletContext); - // @formatter:off - this.mvc.perform(get("/spring/path").servletPath("/spring")) - .andExpect(status().isUnauthorized()); - // @formatter:on - } - - @Test - public void requestWhenUsingMvcMatchersAndServletPathAndAuthorizationManagerThenAuthorizesRequestsAccordingly() - throws Exception { - this.spring.configLocations(this.xml("MvcMatchersServletPathAuthorizationManager")).autowire(); - MockServletContext servletContext = mockServletContext("/spring"); - ConfigurableWebApplicationContext context = this.spring.getContext(); - context.setServletContext(servletContext); - // @formatter:off - this.mvc.perform(get("/spring/path").servletPath("/spring")) - .andExpect(status().isUnauthorized()); - this.mvc.perform(get("/spring/path.html").servletPath("/spring")) - .andExpect(status().isUnauthorized()); - this.mvc.perform(get("/spring/path/").servletPath("/spring")) - .andExpect(status().isUnauthorized()); - // @formatter:on - assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull(); - } - - @Test - public void configureWhenUsingAntMatcherAndServletPathThenThrowsException() { - assertThatExceptionOfType(BeanDefinitionParsingException.class) - .isThrownBy(() -> this.spring.configLocations(this.xml("AntMatcherServletPath")).autowire()); - } - - @Test - public void configureWhenUsingAntMatcherAndServletPathAndAuthorizationManagerThenThrowsException() { - assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy( - () -> this.spring.configLocations(this.xml("AntMatcherServletPathAuthorizationManager")).autowire()); - } - @Test public void configureWhenUsingRegexMatcherAndServletPathThenThrowsException() { assertThatExceptionOfType(BeanDefinitionParsingException.class) @@ -366,12 +307,6 @@ public class InterceptUrlConfigTests { .isThrownBy(() -> this.spring.configLocations(this.xml("DefaultMatcherServletPath")).autowire()); } - @Test - public void configureWhenUsingDefaultMatcherAndNoIntrospectorBeanThenException() { - assertThatExceptionOfType(BeanCreationException.class) - .isThrownBy(() -> this.spring.configLocations(this.xml("DefaultMatcherNoIntrospectorBean")).autowire()); - } - @Test public void configureWhenUsingDefaultMatcherAndServletPathAndAuthorizationManagerThenNoException() { assertThatNoException() diff --git a/config/src/test/java/org/springframework/security/config/http/customconfigurer/CustomConfigurer.java b/config/src/test/java/org/springframework/security/config/http/customconfigurer/CustomConfigurer.java index 1c2ca465fa..0cd8908c15 100644 --- a/config/src/test/java/org/springframework/security/config/http/customconfigurer/CustomConfigurer.java +++ b/config/src/test/java/org/springframework/security/config/http/customconfigurer/CustomConfigurer.java @@ -22,7 +22,7 @@ import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer; import org.springframework.security.web.DefaultSecurityFilterChain; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; /** * @author Rob Winch @@ -44,7 +44,7 @@ public class CustomConfigurer extends SecurityConfigurerAdapter requests - .requestMatchers(new AntPathRequestMatcher(this.permitAllPattern)).permitAll() + .requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(this.permitAllPattern)).permitAll() .anyRequest().authenticated()); // @formatter:on if (http.getConfigurer(FormLoginConfigurer.class) == null) { diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/CsrfDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/CsrfDslTests.kt index ae6568263d..d631bfa8a0 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/CsrfDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/CsrfDslTests.kt @@ -43,7 +43,7 @@ import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler import org.springframework.security.web.csrf.CsrfTokenRequestHandler import org.springframework.security.web.csrf.DefaultCsrfToken import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository -import org.springframework.security.web.util.matcher.AntPathRequestMatcher +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.get import org.springframework.test.web.servlet.post @@ -176,7 +176,7 @@ class CsrfDslTests { open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { http { csrf { - requireCsrfProtectionMatcher = AntPathRequestMatcher("/test1") + requireCsrfProtectionMatcher = PathPatternRequestMatcher.withDefaults().matcher("/test1") } } return http.build() @@ -247,8 +247,8 @@ class CsrfDslTests { open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { http { csrf { - requireCsrfProtectionMatcher = AntPathRequestMatcher("/**") - ignoringRequestMatchers(AntPathRequestMatcher("/test2")) + requireCsrfProtectionMatcher = PathPatternRequestMatcher.withDefaults().matcher("/**") + ignoringRequestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/test2")) } } return http.build() @@ -279,7 +279,7 @@ class CsrfDslTests { open fun filterChain(http: HttpSecurity): SecurityFilterChain { http { csrf { - requireCsrfProtectionMatcher = AntPathRequestMatcher("/**") + requireCsrfProtectionMatcher = PathPatternRequestMatcher.withDefaults().matcher("/**") ignoringRequestMatchers("/test2") } } diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/ExceptionHandlingDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/ExceptionHandlingDslTests.kt index ed3e409cff..8d99a850df 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/ExceptionHandlingDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/ExceptionHandlingDslTests.kt @@ -32,7 +32,7 @@ import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequ import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.access.AccessDeniedHandlerImpl import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint -import org.springframework.security.web.util.matcher.AntPathRequestMatcher +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.get import org.springframework.web.servlet.config.annotation.EnableWebMvc @@ -195,6 +195,7 @@ class ExceptionHandlingDslTests { customAccessDeniedHandler1.setErrorPage("/access-denied1") val customAccessDeniedHandler2 = AccessDeniedHandlerImpl() customAccessDeniedHandler2.setErrorPage("/access-denied2") + val builder = PathPatternRequestMatcher.withDefaults() http { authorizeRequests { authorize("/admin1", hasAuthority("ROLE_ADMIN")) @@ -202,8 +203,8 @@ class ExceptionHandlingDslTests { authorize(anyRequest, authenticated) } exceptionHandling { - defaultAccessDeniedHandlerFor(customAccessDeniedHandler1, AntPathRequestMatcher("/admin1")) - defaultAccessDeniedHandlerFor(customAccessDeniedHandler2, AntPathRequestMatcher("/admin2")) + defaultAccessDeniedHandlerFor(customAccessDeniedHandler1, builder.matcher("/admin1")) + defaultAccessDeniedHandlerFor(customAccessDeniedHandler2, builder.matcher("/admin2")) } } return http.build() @@ -264,13 +265,14 @@ class ExceptionHandlingDslTests { open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { val customAuthenticationEntryPoint1 = LoginUrlAuthenticationEntryPoint("/custom-login1") val customAuthenticationEntryPoint2 = LoginUrlAuthenticationEntryPoint("/custom-login2") + val builder = PathPatternRequestMatcher.withDefaults(); http { authorizeRequests { authorize(anyRequest, authenticated) } exceptionHandling { - defaultAuthenticationEntryPointFor(customAuthenticationEntryPoint1, AntPathRequestMatcher("/secured1")) - defaultAuthenticationEntryPointFor(customAuthenticationEntryPoint2, AntPathRequestMatcher("/secured2")) + defaultAuthenticationEntryPointFor(customAuthenticationEntryPoint1, builder.matcher("/secured1")) + defaultAuthenticationEntryPointFor(customAuthenticationEntryPoint2, builder.matcher("/secured2")) } } return http.build() diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/LogoutDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/LogoutDslTests.kt index 7697ca4d67..3b1b71d7c1 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/LogoutDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/LogoutDslTests.kt @@ -40,7 +40,7 @@ import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.authentication.logout.LogoutHandler import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler import org.springframework.security.web.context.HttpSessionSecurityContextRepository -import org.springframework.security.web.util.matcher.AntPathRequestMatcher +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.post @@ -102,7 +102,7 @@ class LogoutDslTests { open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { http { logout { - logoutRequestMatcher = AntPathRequestMatcher("/custom/logout") + logoutRequestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/custom/logout") } } return http.build() @@ -307,8 +307,8 @@ class LogoutDslTests { open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { http { logout { - logoutRequestMatcher = AntPathRequestMatcher("/logout/**") - defaultLogoutSuccessHandlerFor(SimpleUrlLogoutSuccessHandler(), AntPathRequestMatcher("/logout/custom")) + logoutRequestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/logout/**") + defaultLogoutSuccessHandlerFor(SimpleUrlLogoutSuccessHandler(), PathPatternRequestMatcher.withDefaults().matcher("/logout/custom")) } } return http.build() diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/RememberMeDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/RememberMeDslTests.kt index b73b41f50d..011547f74e 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/RememberMeDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/RememberMeDslTests.kt @@ -51,7 +51,6 @@ import org.springframework.security.web.authentication.RememberMeServices import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository -import org.springframework.security.web.util.matcher.AntPathRequestMatcher import org.springframework.test.web.servlet.MockHttpServletRequestDsl import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.get @@ -472,7 +471,7 @@ internal class RememberMeDslTests { @Order(0) open fun securityFilterChainWithoutKey(http: HttpSecurity): SecurityFilterChain { http { - securityMatcher(AntPathRequestMatcher("/without-key/**")) + securityMatcher("/without-key/**") formLogin { loginProcessingUrl = "/without-key/login" } diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/headers/HttpStrictTransportSecurityDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/headers/HttpStrictTransportSecurityDslTests.kt index 3edda23411..9158dea686 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/headers/HttpStrictTransportSecurityDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/headers/HttpStrictTransportSecurityDslTests.kt @@ -29,7 +29,7 @@ import org.springframework.security.config.test.SpringTestContext import org.springframework.security.config.test.SpringTestContextExtension import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.server.header.StrictTransportSecurityServerHttpHeadersWriter -import org.springframework.security.web.util.matcher.AntPathRequestMatcher +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.get @@ -148,7 +148,7 @@ class HttpStrictTransportSecurityDslTests { headers { defaultsDisabled = true httpStrictTransportSecurity { - requestMatcher = AntPathRequestMatcher("/secure/**") + requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/secure/**") } } } diff --git a/config/src/test/resources/org/springframework/security/config/http/CsrfBeanDefinitionParserTests-RegisterDataValueProcessorOnyIfNotRegistered.xml b/config/src/test/resources/org/springframework/security/config/http/CsrfBeanDefinitionParserTests-RegisterDataValueProcessorOnyIfNotRegistered.xml index 38a8cbfc8c..b2796585d2 100644 --- a/config/src/test/resources/org/springframework/security/config/http/CsrfBeanDefinitionParserTests-RegisterDataValueProcessorOnyIfNotRegistered.xml +++ b/config/src/test/resources/org/springframework/security/config/http/CsrfBeanDefinitionParserTests-RegisterDataValueProcessorOnyIfNotRegistered.xml @@ -43,7 +43,7 @@ http://www.springframework.org/schema/security https://www.springframework.org/s - - + + diff --git a/config/src/test/resources/org/springframework/security/config/http/CsrfConfigTests-CsrfEnabled.xml b/config/src/test/resources/org/springframework/security/config/http/CsrfConfigTests-CsrfEnabled.xml index 5f29d2e71a..d75bb16307 100644 --- a/config/src/test/resources/org/springframework/security/config/http/CsrfConfigTests-CsrfEnabled.xml +++ b/config/src/test/resources/org/springframework/security/config/http/CsrfConfigTests-CsrfEnabled.xml @@ -30,7 +30,7 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/FormLoginConfigTests-WithAntRequestMatcher.xml b/config/src/test/resources/org/springframework/security/config/http/FormLoginConfigTests-WithRequestMatcher.xml similarity index 92% rename from config/src/test/resources/org/springframework/security/config/http/FormLoginConfigTests-WithAntRequestMatcher.xml rename to config/src/test/resources/org/springframework/security/config/http/FormLoginConfigTests-WithRequestMatcher.xml index b1fa269cf8..917656f861 100644 --- a/config/src/test/resources/org/springframework/security/config/http/FormLoginConfigTests-WithAntRequestMatcher.xml +++ b/config/src/test/resources/org/springframework/security/config/http/FormLoginConfigTests-WithRequestMatcher.xml @@ -24,7 +24,7 @@ http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/FormLoginConfigTests-WithSuccessAndFailureHandlers.xml b/config/src/test/resources/org/springframework/security/config/http/FormLoginConfigTests-WithSuccessAndFailureHandlers.xml index 63ba250e94..c88cbc620f 100644 --- a/config/src/test/resources/org/springframework/security/config/http/FormLoginConfigTests-WithSuccessAndFailureHandlers.xml +++ b/config/src/test/resources/org/springframework/security/config/http/FormLoginConfigTests-WithSuccessAndFailureHandlers.xml @@ -24,7 +24,7 @@ http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/HttpInterceptUrlTests-interceptUrlWhenRequestMatcherRefThenWorks.xml b/config/src/test/resources/org/springframework/security/config/http/HttpInterceptUrlTests-interceptUrlWhenRequestMatcherRefThenWorks.xml index 6bb85a6b92..fb011f12f2 100644 --- a/config/src/test/resources/org/springframework/security/config/http/HttpInterceptUrlTests-interceptUrlWhenRequestMatcherRefThenWorks.xml +++ b/config/src/test/resources/org/springframework/security/config/http/HttpInterceptUrlTests-interceptUrlWhenRequestMatcherRefThenWorks.xml @@ -16,8 +16,12 @@ - + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-AuthorizationManagerFilterAllDispatcherTypes.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-AuthorizationManagerFilterAllDispatcherTypes.xml index aefa2c96a4..01d7e07a44 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-AuthorizationManagerFilterAllDispatcherTypes.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-AuthorizationManagerFilterAllDispatcherTypes.xml @@ -33,15 +33,15 @@ - + - - + + - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-CamelCasePathVariables.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-CamelCasePathVariables.xml index 75e70f4d73..9438a8df38 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-CamelCasePathVariables.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-CamelCasePathVariables.xml @@ -33,5 +33,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-CamelCasePathVariablesAuthorizationManager.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-CamelCasePathVariablesAuthorizationManager.xml index b0c837f42d..a1f9e770e7 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-CamelCasePathVariablesAuthorizationManager.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-CamelCasePathVariablesAuthorizationManager.xml @@ -33,5 +33,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-DefaultMatcherServletPath.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-DefaultMatcherServletPath.xml index 3149fb4876..009e1ed78f 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-DefaultMatcherServletPath.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-DefaultMatcherServletPath.xml @@ -30,5 +30,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-DefaultMatcherServletPathAuthorizationManager.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-DefaultMatcherServletPathAuthorizationManager.xml index 9044cf02e1..a17b11b18e 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-DefaultMatcherServletPathAuthorizationManager.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-DefaultMatcherServletPathAuthorizationManager.xml @@ -30,5 +30,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-FilterAllDispatcherTypesFalse.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-FilterAllDispatcherTypesFalse.xml index 9cc9f57a58..f3c09d2a9d 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-FilterAllDispatcherTypesFalse.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-FilterAllDispatcherTypesFalse.xml @@ -33,15 +33,15 @@ - + - - + + - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PatchMethod.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PatchMethod.xml index 03cdff6a8a..cba0afb23e 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PatchMethod.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PatchMethod.xml @@ -33,5 +33,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PatchMethodAuthorizationManager.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PatchMethodAuthorizationManager.xml index 9b8b31c49a..1701630e38 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PatchMethodAuthorizationManager.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PatchMethodAuthorizationManager.xml @@ -33,5 +33,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PathVariables.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PathVariables.xml index 862f7d99a8..fd6aba58d0 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PathVariables.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PathVariables.xml @@ -33,5 +33,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PathVariablesAuthorizationManager.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PathVariablesAuthorizationManager.xml index 17e62ece6a..c4d93378eb 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PathVariablesAuthorizationManager.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-PathVariablesAuthorizationManager.xml @@ -33,5 +33,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-Sec2256.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-Sec2256.xml index ffff9b3032..a32c00f350 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-Sec2256.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-Sec2256.xml @@ -34,5 +34,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-Sec2256AuthorizationManager.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-Sec2256AuthorizationManager.xml index 31b3400262..1363e89152 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-Sec2256AuthorizationManager.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-Sec2256AuthorizationManager.xml @@ -34,5 +34,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-TypeConversionPathVariables.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-TypeConversionPathVariables.xml index e15c53e7e8..5c66f73a0c 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-TypeConversionPathVariables.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-TypeConversionPathVariables.xml @@ -34,5 +34,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-TypeConversionPathVariablesAuthorizationManager.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-TypeConversionPathVariablesAuthorizationManager.xml index a3886876c8..ffc443b102 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-TypeConversionPathVariablesAuthorizationManager.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-TypeConversionPathVariablesAuthorizationManager.xml @@ -34,5 +34,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-AnonymousDisabled.xml b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-AnonymousDisabled.xml index 37262122d5..c9c175d33d 100644 --- a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-AnonymousDisabled.xml +++ b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-AnonymousDisabled.xml @@ -32,5 +32,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-AnonymousEndpoints.xml b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-AnonymousEndpoints.xml index 8beeec94a1..20ece21448 100644 --- a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-AnonymousEndpoints.xml +++ b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-AnonymousEndpoints.xml @@ -31,5 +31,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-CustomHttpBasicEntryPointRef.xml b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-CustomHttpBasicEntryPointRef.xml index 8168a807e9..328e79b84b 100644 --- a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-CustomHttpBasicEntryPointRef.xml +++ b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-CustomHttpBasicEntryPointRef.xml @@ -34,5 +34,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-CustomRequestMatcher.xml b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-CustomRequestMatcher.xml index b03b8d7ee9..d54f58d917 100644 --- a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-CustomRequestMatcher.xml +++ b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-CustomRequestMatcher.xml @@ -32,7 +32,7 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-NoSecurityForPattern.xml b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-NoSecurityForPattern.xml index d8e1e7511e..f86a895522 100644 --- a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-NoSecurityForPattern.xml +++ b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-NoSecurityForPattern.xml @@ -29,5 +29,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-OncePerRequest.xml b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-OncePerRequest.xml index dfecf7ebe8..63f472c1da 100644 --- a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-OncePerRequest.xml +++ b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-OncePerRequest.xml @@ -31,5 +31,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-OncePerRequestTrue.xml b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-OncePerRequestTrue.xml index 47787c9c84..35973a4780 100644 --- a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-OncePerRequestTrue.xml +++ b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-OncePerRequestTrue.xml @@ -31,5 +31,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-ProtectedLoginPage.xml b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-ProtectedLoginPage.xml index c05b23c20a..36263b2f39 100644 --- a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-ProtectedLoginPage.xml +++ b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-ProtectedLoginPage.xml @@ -30,5 +30,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-ProtectedLoginPageAuthorizationManager.xml b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-ProtectedLoginPageAuthorizationManager.xml index 4d93a59162..f5b082d198 100644 --- a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-ProtectedLoginPageAuthorizationManager.xml +++ b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-ProtectedLoginPageAuthorizationManager.xml @@ -30,5 +30,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/MultiHttpBlockConfigTests-DistinctHttpElements.xml b/config/src/test/resources/org/springframework/security/config/http/MultiHttpBlockConfigTests-DistinctHttpElements.xml index e1bc1587af..8d8ff13553 100644 --- a/config/src/test/resources/org/springframework/security/config/http/MultiHttpBlockConfigTests-DistinctHttpElements.xml +++ b/config/src/test/resources/org/springframework/security/config/http/MultiHttpBlockConfigTests-DistinctHttpElements.xml @@ -35,5 +35,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/MultiHttpBlockConfigTests-IdenticallyPatternedHttpElements.xml b/config/src/test/resources/org/springframework/security/config/http/MultiHttpBlockConfigTests-IdenticallyPatternedHttpElements.xml index b41948934f..e5ef1ea59f 100644 --- a/config/src/test/resources/org/springframework/security/config/http/MultiHttpBlockConfigTests-IdenticallyPatternedHttpElements.xml +++ b/config/src/test/resources/org/springframework/security/config/http/MultiHttpBlockConfigTests-IdenticallyPatternedHttpElements.xml @@ -33,5 +33,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/MultiHttpBlockConfigTests-Sec1937.xml b/config/src/test/resources/org/springframework/security/config/http/MultiHttpBlockConfigTests-Sec1937.xml index ec034128a5..d7cef81eb3 100644 --- a/config/src/test/resources/org/springframework/security/config/http/MultiHttpBlockConfigTests-Sec1937.xml +++ b/config/src/test/resources/org/springframework/security/config/http/MultiHttpBlockConfigTests-Sec1937.xml @@ -50,5 +50,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-AuthenticationManagerResolver.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-AuthenticationManagerResolver.xml index 384ecdca84..aac8f08552 100644 --- a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-AuthenticationManagerResolver.xml +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-AuthenticationManagerResolver.xml @@ -32,5 +32,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-BasicAndResourceServer.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-BasicAndResourceServer.xml index 580b31673d..ef05c2c5ca 100644 --- a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-BasicAndResourceServer.xml +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-BasicAndResourceServer.xml @@ -33,5 +33,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-FormAndResourceServer.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-FormAndResourceServer.xml index 8fbc7dd03a..2f579858c0 100644 --- a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-FormAndResourceServer.xml +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-FormAndResourceServer.xml @@ -33,5 +33,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-JwkSetUri.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-JwkSetUri.xml index aac12989e9..ab8a700e20 100644 --- a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-JwkSetUri.xml +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-JwkSetUri.xml @@ -39,5 +39,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-Jwt.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-Jwt.xml index e32bb32125..1d1b002d00 100644 --- a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-Jwt.xml +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-Jwt.xml @@ -32,5 +32,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-JwtCustomSecurityContextHolderStrategy.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-JwtCustomSecurityContextHolderStrategy.xml index d0ac087211..f22ca3e3ac 100644 --- a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-JwtCustomSecurityContextHolderStrategy.xml +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-JwtCustomSecurityContextHolderStrategy.xml @@ -38,5 +38,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-MultipleIssuers.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-MultipleIssuers.xml index cba1d26936..6ea749cb8a 100644 --- a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-MultipleIssuers.xml +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-MultipleIssuers.xml @@ -39,5 +39,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-OpaqueToken.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-OpaqueToken.xml index 9458e0d6e1..c050ec9e02 100644 --- a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-OpaqueToken.xml +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-OpaqueToken.xml @@ -30,5 +30,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-OpaqueTokenAndAuthenticationConverter.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-OpaqueTokenAndAuthenticationConverter.xml index b25d16ee9e..99736580ef 100644 --- a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-OpaqueTokenAndAuthenticationConverter.xml +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-OpaqueTokenAndAuthenticationConverter.xml @@ -34,5 +34,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-AccessDeniedPage.xml b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-AccessDeniedPage.xml index d801c8c663..1d7ef08691 100644 --- a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-AccessDeniedPage.xml +++ b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-AccessDeniedPage.xml @@ -34,5 +34,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-AccessDeniedPageWithSpEL.xml b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-AccessDeniedPageWithSpEL.xml index 005331dc00..06c505c698 100644 --- a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-AccessDeniedPageWithSpEL.xml +++ b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-AccessDeniedPageWithSpEL.xml @@ -34,5 +34,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-InterceptUrlAndFormLogin.xml b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-InterceptUrlAndFormLogin.xml index b9280474ca..7fbee4ee21 100644 --- a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-InterceptUrlAndFormLogin.xml +++ b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-InterceptUrlAndFormLogin.xml @@ -39,5 +39,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-InterceptUrlAndFormLoginWithSpEL.xml b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-InterceptUrlAndFormLoginWithSpEL.xml index ebd0289e71..ca6ed2a1ba 100644 --- a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-InterceptUrlAndFormLoginWithSpEL.xml +++ b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-InterceptUrlAndFormLoginWithSpEL.xml @@ -42,5 +42,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-PortMapping.xml b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-PortMapping.xml index e1380cf22e..b6b5052df2 100644 --- a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-PortMapping.xml +++ b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-PortMapping.xml @@ -38,5 +38,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-RequiresChannel.xml b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-RequiresChannel.xml index 167abb9989..f6dcf1256d 100644 --- a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-RequiresChannel.xml +++ b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-RequiresChannel.xml @@ -33,5 +33,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-UnsecuredPattern.xml b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-UnsecuredPattern.xml index 2fbf13881f..1b14632ad1 100644 --- a/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-UnsecuredPattern.xml +++ b/config/src/test/resources/org/springframework/security/config/http/PlaceHolderAndELConfigTests-UnsecuredPattern.xml @@ -35,5 +35,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-DefaultConfig.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-DefaultConfig.xml index e9e1ea4e21..efb6fb756f 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-DefaultConfig.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-DefaultConfig.xml @@ -34,5 +34,5 @@ class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-NegativeTokenValidity.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-NegativeTokenValidity.xml index 738a9f42f8..0d966cb092 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-NegativeTokenValidity.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-NegativeTokenValidity.xml @@ -36,5 +36,5 @@ class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-Sec1827.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-Sec1827.xml index 78b86e2a1e..de888a134d 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-Sec1827.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-Sec1827.xml @@ -36,5 +36,5 @@ class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-Sec2165.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-Sec2165.xml index 2d717a4496..3c8da7de57 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-Sec2165.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-Sec2165.xml @@ -36,5 +36,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-Sec742.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-Sec742.xml index 51e79b3283..ffb5209ae3 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-Sec742.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-Sec742.xml @@ -37,5 +37,5 @@ class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-SecureCookie.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-SecureCookie.xml index faeeddcedc..97ee0e38af 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-SecureCookie.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-SecureCookie.xml @@ -36,5 +36,5 @@ class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-TokenValidity.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-TokenValidity.xml index 6042ea290e..e7da2cdbb4 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-TokenValidity.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-TokenValidity.xml @@ -36,5 +36,5 @@ class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithAuthenticationSuccessHandler.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithAuthenticationSuccessHandler.xml index f66b683c46..fe722ca85e 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithAuthenticationSuccessHandler.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithAuthenticationSuccessHandler.xml @@ -43,5 +43,5 @@ class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithDataSource.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithDataSource.xml index 0677224c0e..ab7e778955 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithDataSource.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithDataSource.xml @@ -38,5 +38,5 @@ class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithRememberMeCookie.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithRememberMeCookie.xml index 5dbfac6d8f..819f889f94 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithRememberMeCookie.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithRememberMeCookie.xml @@ -30,5 +30,5 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithRememberMeParameter.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithRememberMeParameter.xml index c3f2cb9574..27c01d9907 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithRememberMeParameter.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithRememberMeParameter.xml @@ -34,5 +34,5 @@ class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithSecurityContextHolderStrategy.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithSecurityContextHolderStrategy.xml index 369a5e1417..3bba2b6c82 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithSecurityContextHolderStrategy.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithSecurityContextHolderStrategy.xml @@ -40,5 +40,5 @@ class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithServicesRef.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithServicesRef.xml index e6e11567ab..d8045766bb 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithServicesRef.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithServicesRef.xml @@ -44,5 +44,5 @@ class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithTokenRepository.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithTokenRepository.xml index 520c9a142d..c293e31a24 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithTokenRepository.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithTokenRepository.xml @@ -48,5 +48,5 @@ class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithUserDetailsService.xml b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithUserDetailsService.xml index 457f9807ee..f6578985bf 100644 --- a/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithUserDetailsService.xml +++ b/config/src/test/resources/org/springframework/security/config/http/RememberMeConfigTests-WithUserDetailsService.xml @@ -41,5 +41,5 @@ name="basicController" class="org.springframework.security.config.http.RememberMeConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/SecurityContextHolderAwareRequestConfigTests-MultiHttp.xml b/config/src/test/resources/org/springframework/security/config/http/SecurityContextHolderAwareRequestConfigTests-MultiHttp.xml index 1b9bff3c77..168ec42a06 100644 --- a/config/src/test/resources/org/springframework/security/config/http/SecurityContextHolderAwareRequestConfigTests-MultiHttp.xml +++ b/config/src/test/resources/org/springframework/security/config/http/SecurityContextHolderAwareRequestConfigTests-MultiHttp.xml @@ -55,6 +55,6 @@ - - + + diff --git a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-CreateSessionIfRequired.xml b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-CreateSessionIfRequired.xml index f659f8841a..dc857e8227 100644 --- a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-CreateSessionIfRequired.xml +++ b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-CreateSessionIfRequired.xml @@ -33,5 +33,5 @@ class="org.springframework.security.config.http.SessionManagementConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-CreateSessionNever.xml b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-CreateSessionNever.xml index 45280f776e..0b52466d23 100644 --- a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-CreateSessionNever.xml +++ b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-CreateSessionNever.xml @@ -33,5 +33,5 @@ class="org.springframework.security.config.http.SessionManagementConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-CreateSessionStateless.xml b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-CreateSessionStateless.xml index 968c474575..5a4d2fa840 100644 --- a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-CreateSessionStateless.xml +++ b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-CreateSessionStateless.xml @@ -33,5 +33,5 @@ class="org.springframework.security.config.http.SessionManagementConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-NoSessionManagementFilter.xml b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-NoSessionManagementFilter.xml index 92ec3ae9c2..91ccdd7929 100644 --- a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-NoSessionManagementFilter.xml +++ b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-NoSessionManagementFilter.xml @@ -34,5 +34,5 @@ class="org.springframework.security.config.http.SessionManagementConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-Sec1208.xml b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-Sec1208.xml index 8cd46c54a2..302eaa5d82 100644 --- a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-Sec1208.xml +++ b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-Sec1208.xml @@ -37,5 +37,5 @@ class="org.springframework.security.config.http.SessionManagementConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-Sec2137.xml b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-Sec2137.xml index 604b4fea11..146472ad7a 100644 --- a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-Sec2137.xml +++ b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-Sec2137.xml @@ -35,5 +35,5 @@ class="org.springframework.security.config.http.SessionManagementConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionAuthenticationStrategyRef.xml b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionAuthenticationStrategyRef.xml index a84edef1dc..5f38701a67 100644 --- a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionAuthenticationStrategyRef.xml +++ b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionAuthenticationStrategyRef.xml @@ -38,5 +38,5 @@ class="org.springframework.security.config.http.SessionManagementConfigTests.TeapotSessionAuthenticationStrategy"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionFixationProtectionMigrateSession.xml b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionFixationProtectionMigrateSession.xml index 9e4deb3fa1..cb7e12c228 100644 --- a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionFixationProtectionMigrateSession.xml +++ b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionFixationProtectionMigrateSession.xml @@ -35,5 +35,5 @@ class="org.springframework.security.config.http.SessionManagementConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionFixationProtectionNone.xml b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionFixationProtectionNone.xml index 62a808bafa..dbd35d0ede 100644 --- a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionFixationProtectionNone.xml +++ b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionFixationProtectionNone.xml @@ -33,5 +33,5 @@ class="org.springframework.security.config.http.SessionManagementConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionFixationProtectionNoneWithInvalidSessionUrl.xml b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionFixationProtectionNoneWithInvalidSessionUrl.xml index 394b28eef1..30ecc568c7 100644 --- a/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionFixationProtectionNoneWithInvalidSessionUrl.xml +++ b/config/src/test/resources/org/springframework/security/config/http/SessionManagementConfigTests-SessionFixationProtectionNoneWithInvalidSessionUrl.xml @@ -33,5 +33,5 @@ class="org.springframework.security.config.http.SessionManagementConfigTests.BasicController"/> - + diff --git a/config/src/test/resources/org/springframework/security/config/http/handlermappingintrospector.xml b/config/src/test/resources/org/springframework/security/config/http/pathpatternrequestmatcherbuilder.xml similarity index 90% rename from config/src/test/resources/org/springframework/security/config/http/handlermappingintrospector.xml rename to config/src/test/resources/org/springframework/security/config/http/pathpatternrequestmatcherbuilder.xml index 2b730a2465..ac37d5e4cc 100644 --- a/config/src/test/resources/org/springframework/security/config/http/handlermappingintrospector.xml +++ b/config/src/test/resources/org/springframework/security/config/http/pathpatternrequestmatcherbuilder.xml @@ -24,6 +24,6 @@ http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> - + diff --git a/config/src/test/resources/org/springframework/security/util/filtertest-valid.xml b/config/src/test/resources/org/springframework/security/util/filtertest-valid.xml index d12165a7b4..e40f1e9426 100644 --- a/config/src/test/resources/org/springframework/security/util/filtertest-valid.xml +++ b/config/src/test/resources/org/springframework/security/util/filtertest-valid.xml @@ -45,7 +45,7 @@ - + @@ -135,7 +135,7 @@ - + @@ -149,7 +149,7 @@ - + @@ -159,7 +159,7 @@ - + @@ -174,7 +174,5 @@ - - diff --git a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc index 555a1b4323..0311594407 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc @@ -128,7 +128,7 @@ This is helpful when, for example, wanting to run HTTP locally and HTTPS in prod Defines the `RequestMatcher` strategy used in the `FilterChainProxy` and the beans created by the `intercept-url` to match incoming requests. Options are currently `mvc`, `ant`, `regex` and `ciRegex`, for Spring MVC, ant, regular-expression and case-insensitive regular-expression respectively. A separate instance is created for each <> element using its <>, <> and <> attributes. -Ant paths are matched using an `AntPathRequestMatcher`, regular expressions are matched using a `RegexRequestMatcher` and for Spring MVC path matching the `MvcRequestMatcher` is used. +By default, paths are matched using a `PathPatternRequestMatcher`; however, regular expressions are matched using a `RegexRequestMatcher`. See the Javadoc for these classes for more details on exactly how the matching is performed. MVC is the default strategy if Spring MVC is present in the classpath, if not, Ant paths are used. @@ -226,7 +226,8 @@ Defines a reference to a Spring bean of type `AccessDeniedHandler`. [[nsa-cors]] == This element allows for configuring a `CorsFilter`. -If no `CorsFilter` or `CorsConfigurationSource` is specified and Spring MVC is on the classpath, a `HandlerMappingIntrospector` is used as the `CorsConfigurationSource`. +Either a `CorsFilter` or a `CorsConfigurationSource` must be specified. +If Spring MVC is present, then it will attempt to look up its `CorsConfigurationSource`. [[nsa-cors-attributes]] === Attributes diff --git a/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc b/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc index 2d435ff36c..1ab2ba1505 100644 --- a/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc +++ b/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc @@ -1084,7 +1084,7 @@ open class SecurityConfig { <3> Allow access to URLs that start with `/api/admin/` to users with the `ADMIN` role <4> Any other request that doesn't match the rules above, will require authentication -The `securityMatcher(s)` and `requestMatcher(s)` methods will decide which `RequestMatcher` implementation fits best for your application: If {spring-framework-reference-url}web.html#spring-web[Spring MVC] is in the classpath, then javadoc:org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher[] will be used, otherwise, javadoc:org.springframework.security.web.util.matcher.AntPathRequestMatcher[] will be used. +The `securityMatcher(s)` and `requestMatcher(s)` methods will construct ``RequestMatcher``s using a javadoc:org.springframework.security.web.util.matcher.PathPatternRequestMatcher.Builder[] bean, if available. You can read more about the Spring MVC integration xref:servlet/integrations/mvc.adoc[here]. If you want to use a specific `RequestMatcher`, just pass an implementation to the `securityMatcher` and/or `requestMatcher` methods: @@ -1095,7 +1095,7 @@ Java:: + [source,java,role="primary"] ---- -import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher; <1> +import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.withDefaults; <1> import static org.springframework.security.web.util.matcher.RegexRequestMatcher.regexMatcher; @Configuration @@ -1107,7 +1107,7 @@ public class SecurityConfig { http .securityMatcher(antMatcher("/api/**")) <2> .authorizeHttpRequests((authorize) -> authorize - .requestMatchers(antMatcher("/api/user/**")).hasRole("USER") <3> + .requestMatchers(withDefaults().matcher("/api/user/**")).hasRole("USER") <3> .requestMatchers(regexMatcher("/api/admin/.*")).hasRole("ADMIN") <4> .requestMatchers(new MyCustomRequestMatcher()).hasRole("SUPERVISOR") <5> .anyRequest().authenticated() @@ -1130,7 +1130,7 @@ Kotlin:: + [source,kotlin,role="secondary"] ---- -import org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher <1> +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.withDefaults <1> import org.springframework.security.web.util.matcher.RegexRequestMatcher.regexMatcher @Configuration @@ -1142,7 +1142,7 @@ open class SecurityConfig { http { securityMatcher(antMatcher("/api/**")) <2> authorizeHttpRequests { - authorize(antMatcher("/api/user/**"), hasRole("USER")) <3> + authorize(withDefaults().matcher("/api/user/**"), hasRole("USER")) <3> authorize(regexMatcher("/api/admin/**"), hasRole("ADMIN")) <4> authorize(MyCustomRequestMatcher(), hasRole("SUPERVISOR")) <5> authorize(anyRequest, authenticated) @@ -1155,9 +1155,9 @@ open class SecurityConfig { ---- ====== -<1> Import the static factory methods from `AntPathRequestMatcher` and `RegexRequestMatcher` to create `RequestMatcher` instances. -<2> Configure `HttpSecurity` to only be applied to URLs that start with `/api/`, using `AntPathRequestMatcher` -<3> Allow access to URLs that start with `/api/user/` to users with the `USER` role, using `AntPathRequestMatcher` +<1> Import the static factory methods from `PathPatternRequestMatcher` and `RegexRequestMatcher` to create `RequestMatcher` instances. +<2> Configure `HttpSecurity` to only be applied to URLs that start with `/api/`, using `PathPatternRequestMatcher` +<3> Allow access to URLs that start with `/api/user/` to users with the `USER` role, using `PathPatternRequestMatcher` <4> Allow access to URLs that start with `/api/admin/` to users with the `ADMIN` role, using `RegexRequestMatcher` <5> Allow access to URLs that match the `MyCustomRequestMatcher` to users with the `SUPERVISOR` role, using a custom `RequestMatcher` diff --git a/docs/modules/ROOT/pages/servlet/configuration/java.adoc b/docs/modules/ROOT/pages/servlet/configuration/java.adoc index a3c09f5732..193ce75c64 100644 --- a/docs/modules/ROOT/pages/servlet/configuration/java.adoc +++ b/docs/modules/ROOT/pages/servlet/configuration/java.adoc @@ -132,7 +132,7 @@ public class MvcWebApplicationInitializer extends ---- The reason for this is that Spring Security needs to be able to inspect some Spring MVC configuration in order to appropriately configure xref:servlet/authorization/authorize-http-requests.adoc#authorizing-endpoints[underlying request matchers], so they need to be in the same application context. -Placing Spring Security in `getRootConfigClasses` places it into a parent application context that may not be able to find Spring MVC's `HandlerMappingIntrospector`. +Placing Spring Security in `getRootConfigClasses` places it into a parent application context that may not be able to find Spring MVC's `PathPatternParser`. ==== Configuring for Multiple Spring MVC Dispatchers diff --git a/docs/modules/ROOT/pages/servlet/exploits/csrf.adoc b/docs/modules/ROOT/pages/servlet/exploits/csrf.adoc index f02350dc6d..33834f12b2 100644 --- a/docs/modules/ROOT/pages/servlet/exploits/csrf.adoc +++ b/docs/modules/ROOT/pages/servlet/exploits/csrf.adoc @@ -1276,7 +1276,7 @@ XML:: - + @@ -1387,7 +1387,7 @@ public class SecurityConfig { http // ... .logout((logout) -> logout - .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) + .logoutRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher("/logout")) ); return http.build(); } @@ -1409,7 +1409,7 @@ class SecurityConfig { http { // ... logout { - logoutRequestMatcher = AntPathRequestMatcher("/logout") + logoutRequestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/logout") } } return http.build() diff --git a/docs/modules/ROOT/pages/servlet/exploits/firewall.adoc b/docs/modules/ROOT/pages/servlet/exploits/firewall.adoc index 29dd8fcf93..e4978ea6ed 100644 --- a/docs/modules/ROOT/pages/servlet/exploits/firewall.adoc +++ b/docs/modules/ROOT/pages/servlet/exploits/firewall.adoc @@ -24,7 +24,7 @@ It is, therefore, essential that a `FilterChainProxy` is used to manage the secu Note that the `servletPath` and `pathInfo` values are decoded by the container, so your application should not have any valid paths that contain semi-colons, as these parts are removed for matching purposes. As mentioned earlier, the default strategy is to use Ant-style paths for matching, and this is likely to be the best choice for most users. -The strategy is implemented in the class `AntPathRequestMatcher`, which uses Spring's `AntPathMatcher` to perform a case-insensitive match of the pattern against the concatenated `servletPath` and `pathInfo`, ignoring the `queryString`. +The strategy is implemented in the class `PathPatternRequestMatcher`, which uses Spring's `PathPattern` to perform a case-insensitive match of the pattern against the concatenated `servletPath` and `pathInfo`, ignoring the `queryString`. If you need a more powerful matching strategy, you can use regular expressions. The strategy implementation is then `RegexRequestMatcher`. diff --git a/docs/modules/ROOT/pages/servlet/exploits/headers.adoc b/docs/modules/ROOT/pages/servlet/exploits/headers.adoc index 5b12c92f74..a36dd804cc 100644 --- a/docs/modules/ROOT/pages/servlet/exploits/headers.adoc +++ b/docs/modules/ROOT/pages/servlet/exploits/headers.adoc @@ -1218,7 +1218,7 @@ public class WebSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - RequestMatcher matcher = new AntPathRequestMatcher("/login"); + RequestMatcher matcher = PathPatternRequestMatcher.withDefaults().matcher("/login"); DelegatingRequestMatcherHeaderWriter headerWriter = new DelegatingRequestMatcherHeaderWriter(matcher,new XFrameOptionsHeaderWriter()); http @@ -1248,7 +1248,7 @@ XML:: - @@ -1268,7 +1268,7 @@ class SecurityConfig { @Bean open fun filterChain(http: HttpSecurity): SecurityFilterChain { - val matcher: RequestMatcher = AntPathRequestMatcher("/login") + val matcher: RequestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/login") val headerWriter = DelegatingRequestMatcherHeaderWriter(matcher, XFrameOptionsHeaderWriter()) http { headers { diff --git a/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc b/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc index a4827bac7b..6ed05712fe 100644 --- a/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc +++ b/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc @@ -698,7 +698,7 @@ If we use XML-based configuration, we can use thexref:servlet/appendix/namespace - + diff --git a/etc/checkstyle/checkstyle.xml b/etc/checkstyle/checkstyle.xml index 9b4b616eb0..e4cbc33131 100644 --- a/etc/checkstyle/checkstyle.xml +++ b/etc/checkstyle/checkstyle.xml @@ -18,7 +18,7 @@ - + diff --git a/itest/context/src/integration-test/resources/filter-chain-performance-app-context.xml b/itest/context/src/integration-test/resources/filter-chain-performance-app-context.xml index 7b6ac0c656..8311103464 100644 --- a/itest/context/src/integration-test/resources/filter-chain-performance-app-context.xml +++ b/itest/context/src/integration-test/resources/filter-chain-performance-app-context.xml @@ -11,13 +11,13 @@ http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd"> - + - + diff --git a/itest/web/src/integration-test/resources/spring/http-security-concurrency.xml b/itest/web/src/integration-test/resources/spring/http-security-concurrency.xml index 310f1bedfe..7ba9243c79 100644 --- a/itest/web/src/integration-test/resources/spring/http-security-concurrency.xml +++ b/itest/web/src/integration-test/resources/spring/http-security-concurrency.xml @@ -47,6 +47,6 @@ - + diff --git a/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4AuthenticationRequestResolverTests.java b/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4AuthenticationRequestResolverTests.java index 2716f0befd..7ba18fb985 100644 --- a/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4AuthenticationRequestResolverTests.java +++ b/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4AuthenticationRequestResolverTests.java @@ -28,7 +28,7 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding; import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations; import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -88,10 +88,11 @@ public class OpenSaml4AuthenticationRequestResolverTests { @Test void resolveWhenCustomAuthenticationUrlTHenUses() { + PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withDefaults(); RelyingPartyRegistrationResolver relyingParties = mock(RelyingPartyRegistrationResolver.class); given(relyingParties.resolve(any(), any())).willReturn(this.registration); OpenSaml4AuthenticationRequestResolver resolver = new OpenSaml4AuthenticationRequestResolver(relyingParties); - resolver.setRequestMatcher(new AntPathRequestMatcher("/custom/authentication/{registrationId}")); + resolver.setRequestMatcher(builder.matcher("/custom/authentication/{registrationId}")); Saml2RedirectAuthenticationRequest authnRequest = resolver .resolve(givenRequest("/custom/authentication/registration-id")); diff --git a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml5AuthenticationRequestResolverTests.java b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml5AuthenticationRequestResolverTests.java index bf5d059e1a..38b44d5b55 100644 --- a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml5AuthenticationRequestResolverTests.java +++ b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml5AuthenticationRequestResolverTests.java @@ -28,7 +28,7 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding; import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations; import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -91,7 +91,8 @@ public class OpenSaml5AuthenticationRequestResolverTests { RelyingPartyRegistrationResolver relyingParties = mock(RelyingPartyRegistrationResolver.class); given(relyingParties.resolve(any(), any())).willReturn(this.registration); OpenSaml5AuthenticationRequestResolver resolver = new OpenSaml5AuthenticationRequestResolver(relyingParties); - resolver.setRequestMatcher(new AntPathRequestMatcher("/custom/authentication/{registrationId}")); + resolver.setRequestMatcher( + PathPatternRequestMatcher.withDefaults().matcher("/custom/authentication/{registrationId}")); Saml2RedirectAuthenticationRequest authnRequest = resolver .resolve(givenRequest("/custom/authentication/registration-id")); diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/Saml2MetadataFilterTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/Saml2MetadataFilterTests.java index 471ca2a859..1d1b247d63 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/Saml2MetadataFilterTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/Saml2MetadataFilterTests.java @@ -34,7 +34,7 @@ import org.springframework.security.saml2.provider.service.metadata.Saml2Metadat import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -129,7 +129,7 @@ public class Saml2MetadataFilterTests { @Test public void doFilterWhenCustomRequestMatcherThenUses() throws Exception { MockHttpServletRequest request = uri("/path"); - this.filter.setRequestMatcher(new AntPathRequestMatcher("/path")); + this.filter.setRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher("/path")); this.filter.doFilter(request, this.response, this.chain); verifyNoInteractions(this.chain); verify(this.repository).findByRegistrationId("path"); @@ -159,7 +159,7 @@ public class Saml2MetadataFilterTests { RelyingPartyRegistrationResolver resolver = new DefaultRelyingPartyRegistrationResolver( (id) -> this.repository.findByRegistrationId("registration-id")); this.filter = new Saml2MetadataFilter(resolver, this.resolver); - this.filter.setRequestMatcher(new AntPathRequestMatcher("/metadata")); + this.filter.setRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher("/metadata")); MockHttpServletRequest request = uri("/metadata"); this.filter.doFilter(request, this.response, new MockFilterChain()); verify(this.repository).findByRegistrationId("registration-id"); @@ -173,7 +173,7 @@ public class Saml2MetadataFilterTests { given(this.resolver.resolve(any(RelyingPartyRegistration.class))).willReturn("metadata"); this.filter = new Saml2MetadataFilter((id) -> this.repository.findByRegistrationId("registration-id"), this.resolver); - this.filter.setRequestMatcher(new AntPathRequestMatcher("/metadata")); + this.filter.setRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher("/metadata")); MockHttpServletRequest request = uri("/metadata"); this.filter.doFilter(request, this.response, new MockFilterChain()); verify(this.repository).findByRegistrationId("registration-id"); diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilterTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilterTests.java index 9e4b4d3269..ac31a34f32 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilterTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilterTests.java @@ -43,7 +43,7 @@ import org.springframework.security.saml2.provider.service.web.Saml2Authenticati import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter; import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.security.web.authentication.WebAuthenticationDetails; -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; import static org.assertj.core.api.Assertions.assertThat; @@ -225,7 +225,7 @@ public class Saml2WebSsoAuthenticationFilterTests { given(this.repository.findByRegistrationId("registration-id")).willReturn(registration); given(this.authenticationManager.authenticate(authentication)).willReturn(authentication); String loginProcessingUrl = "/{registrationId}/login/saml2/sso"; - RequestMatcher matcher = new AntPathRequestMatcher(loginProcessingUrl); + RequestMatcher matcher = PathPatternRequestMatcher.withDefaults().matcher(loginProcessingUrl); DefaultRelyingPartyRegistrationResolver delegate = new DefaultRelyingPartyRegistrationResolver(this.repository); RelyingPartyRegistrationResolver resolver = (request, id) -> { String registrationId = matcher.matcher(request).getVariables().get("registrationId"); diff --git a/test/src/test/java/org/springframework/security/test/web/support/WebTestUtilsTests.java b/test/src/test/java/org/springframework/security/test/web/support/WebTestUtilsTests.java index f1d973e5f6..93076b1408 100644 --- a/test/src/test/java/org/springframework/security/test/web/support/WebTestUtilsTests.java +++ b/test/src/test/java/org/springframework/security/test/web/support/WebTestUtilsTests.java @@ -41,7 +41,7 @@ import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.security.web.csrf.CsrfFilter; import org.springframework.security.web.csrf.CsrfTokenRepository; import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.util.matcher.AnyRequestMatcher; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; @@ -226,7 +226,7 @@ public class WebTestUtilsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatcher(new AntPathRequestMatcher("/willnotmatchthis")); + .securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/willnotmatchthis")); return http.build(); // @formatter:on } diff --git a/web/src/main/java/org/springframework/security/web/FilterChainProxy.java b/web/src/main/java/org/springframework/security/web/FilterChainProxy.java index c71ea74930..46ce8d11b3 100644 --- a/web/src/main/java/org/springframework/security/web/FilterChainProxy.java +++ b/web/src/main/java/org/springframework/security/web/FilterChainProxy.java @@ -34,6 +34,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.core.log.LogMessage; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; +import org.springframework.security.web.access.PathPatternRequestTransformer; import org.springframework.security.web.firewall.FirewalledRequest; import org.springframework.security.web.firewall.HttpFirewall; import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandler; @@ -258,7 +259,9 @@ public class FilterChainProxy extends GenericFilterBean { * @return matching filter list */ public List getFilters(String url) { - return getFilters(this.firewall.getFirewalledRequest(new FilterInvocation(url, "GET").getRequest())); + PathPatternRequestTransformer requestTransformer = new PathPatternRequestTransformer(); + HttpServletRequest transformed = requestTransformer.transform(new FilterInvocation(url, "GET").getRequest()); + return getFilters(this.firewall.getFirewalledRequest(transformed)); } /** diff --git a/web/src/main/java/org/springframework/security/web/access/HandlerMappingIntrospectorRequestTransformer.java b/web/src/main/java/org/springframework/security/web/access/HandlerMappingIntrospectorRequestTransformer.java deleted file mode 100644 index f78ad46a50..0000000000 --- a/web/src/main/java/org/springframework/security/web/access/HandlerMappingIntrospectorRequestTransformer.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2002-2023 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.web.access; - -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; - -import jakarta.servlet.DispatcherType; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletRequestWrapper; - -import org.springframework.util.Assert; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; - -/** - * Transforms by passing it into - * {@link HandlerMappingIntrospector#setCache(HttpServletRequest)}. Before, it wraps the - * {@link HttpServletRequest} to ensure that the methods needed work since some methods by - * default throw {@link UnsupportedOperationException}. - * - * @author Rob Winch - * @deprecated please use {@link PathPatternRequestTransformer} instead - */ -@Deprecated(forRemoval = true) -public class HandlerMappingIntrospectorRequestTransformer - implements AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer { - - private final HandlerMappingIntrospector introspector; - - public HandlerMappingIntrospectorRequestTransformer(HandlerMappingIntrospector introspector) { - Assert.notNull(introspector, "introspector canot be null"); - this.introspector = introspector; - } - - @Override - public HttpServletRequest transform(HttpServletRequest request) { - CacheableRequestWrapper cacheableRequest = new CacheableRequestWrapper(request); - this.introspector.setCache(cacheableRequest); - return cacheableRequest; - } - - static final class CacheableRequestWrapper extends HttpServletRequestWrapper { - - private final Map attributes = new HashMap<>(); - - /** - * Constructs a request object wrapping the given request. - * @param request the {@link HttpServletRequest} to be wrapped. - * @throws IllegalArgumentException if the request is null - */ - CacheableRequestWrapper(HttpServletRequest request) { - super(request); - } - - @Override - public DispatcherType getDispatcherType() { - return DispatcherType.REQUEST; - } - - @Override - public Enumeration getAttributeNames() { - return Collections.enumeration(this.attributes.keySet()); - } - - @Override - public Object getAttribute(String name) { - return this.attributes.get(name); - } - - @Override - public void setAttribute(String name, Object o) { - this.attributes.put(name, o); - } - - @Override - public void removeAttribute(String name) { - this.attributes.remove(name); - } - - } - -} diff --git a/web/src/main/java/org/springframework/security/web/access/intercept/DefaultFilterInvocationSecurityMetadataSource.java b/web/src/main/java/org/springframework/security/web/access/intercept/DefaultFilterInvocationSecurityMetadataSource.java index db0f11ea60..d7954abdf0 100644 --- a/web/src/main/java/org/springframework/security/web/access/intercept/DefaultFilterInvocationSecurityMetadataSource.java +++ b/web/src/main/java/org/springframework/security/web/access/intercept/DefaultFilterInvocationSecurityMetadataSource.java @@ -86,7 +86,7 @@ public class DefaultFilterInvocationSecurityMetadataSource implements FilterInvo @Override public Collection getAttributes(Object object) { - final HttpServletRequest request = ((FilterInvocation) object).getRequest(); + final HttpServletRequest request = getHttpServletRequest(object); int count = 0; for (Map.Entry> entry : this.requestMap.entrySet()) { if (entry.getKey().matches(request)) { @@ -107,4 +107,14 @@ public class DefaultFilterInvocationSecurityMetadataSource implements FilterInvo return FilterInvocation.class.isAssignableFrom(clazz); } + private HttpServletRequest getHttpServletRequest(Object object) { + if (object instanceof FilterInvocation invocation) { + return invocation.getHttpRequest(); + } + if (object instanceof HttpServletRequest request) { + return request; + } + throw new IllegalArgumentException("object must be of type FilterInvocation or HttpServletRequest"); + } + } diff --git a/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java index 16a737a9f7..d96302acbd 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java @@ -46,7 +46,7 @@ import org.springframework.security.web.authentication.session.NullAuthenticated import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; import org.springframework.security.web.context.RequestAttributeSecurityContextRepository; import org.springframework.security.web.context.SecurityContextRepository; -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; import org.springframework.util.Assert; import org.springframework.web.filter.GenericFilterBean; @@ -395,7 +395,7 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt * @param filterProcessesUrl */ public void setFilterProcessesUrl(String filterProcessesUrl) { - setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(filterProcessesUrl)); + setRequiresAuthenticationRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher(filterProcessesUrl)); } public final void setRequiresAuthenticationRequestMatcher(RequestMatcher requestMatcher) { diff --git a/web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserFilter.java b/web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserFilter.java index 335262b05c..a7fe5fe599 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserFilter.java @@ -65,11 +65,9 @@ import org.springframework.security.web.context.RequestAttributeSecurityContextR import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.util.UrlUtils; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; import org.springframework.web.filter.GenericFilterBean; -import org.springframework.web.util.UrlPathHelper; /** * Switch User processing filter responsible for user context switching. @@ -129,9 +127,9 @@ public class SwitchUserFilter extends GenericFilterBean implements ApplicationEv protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); - private RequestMatcher exitUserMatcher = createMatcher("/logout/impersonate", true); + private RequestMatcher exitUserMatcher = createMatcher("/logout/impersonate"); - private RequestMatcher switchUserMatcher = createMatcher("/login/impersonate", true); + private RequestMatcher switchUserMatcher = createMatcher("/login/impersonate"); private String targetUrl; @@ -408,7 +406,7 @@ public class SwitchUserFilter extends GenericFilterBean implements ApplicationEv public void setExitUserUrl(String exitUserUrl) { Assert.isTrue(UrlUtils.isValidRedirectUrl(exitUserUrl), "exitUserUrl cannot be empty and must be a valid redirect URL"); - this.exitUserMatcher = createMatcher(exitUserUrl, false); + this.exitUserMatcher = createMatcher(exitUserUrl); } /** @@ -428,7 +426,7 @@ public class SwitchUserFilter extends GenericFilterBean implements ApplicationEv public void setSwitchUserUrl(String switchUserUrl) { Assert.isTrue(UrlUtils.isValidRedirectUrl(switchUserUrl), "switchUserUrl cannot be empty and must be a valid redirect URL"); - this.switchUserMatcher = createMatcher(switchUserUrl, false); + this.switchUserMatcher = createMatcher(switchUserUrl); } /** @@ -547,11 +545,8 @@ public class SwitchUserFilter extends GenericFilterBean implements ApplicationEv this.securityContextRepository = securityContextRepository; } - private static RequestMatcher createMatcher(String pattern, boolean usePathPatterns) { - if (usePathPatterns) { - return PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, pattern); - } - return new AntPathRequestMatcher(pattern, "POST", true, new UrlPathHelper()); + private static RequestMatcher createMatcher(String pattern) { + return PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, pattern); } } diff --git a/web/src/main/java/org/springframework/security/web/servlet/util/matcher/MvcRequestMatcher.java b/web/src/main/java/org/springframework/security/web/servlet/util/matcher/MvcRequestMatcher.java deleted file mode 100644 index 51e36d28a8..0000000000 --- a/web/src/main/java/org/springframework/security/web/servlet/util/matcher/MvcRequestMatcher.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2002-2022 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.web.servlet.util.matcher; - -import java.util.Map; -import java.util.Objects; - -import jakarta.servlet.http.HttpServletRequest; - -import org.springframework.http.HttpMethod; -import org.springframework.security.web.util.matcher.RequestMatcher; -import org.springframework.security.web.util.matcher.RequestVariablesExtractor; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.PathMatcher; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; -import org.springframework.web.servlet.handler.MatchableHandlerMapping; -import org.springframework.web.servlet.handler.RequestMatchResult; -import org.springframework.web.util.UrlPathHelper; - -/** - * A {@link RequestMatcher} that uses Spring MVC's {@link HandlerMappingIntrospector} to - * match the path and extract variables. - * - *

- * It is important to understand that Spring MVC's matching is relative to the servlet - * path. This means if you have mapped any servlet to a path that starts with "/" and is - * greater than one, you should also specify the {@link #setServletPath(String)} attribute - * to differentiate mappings. - *

- * - * @author Rob Winch - * @author Eddú Meléndez - * @author Evgeniy Cheban - * @since 4.1.1 - * @deprecated Please use {@link PathPatternRequestMatcher} instead - */ -@Deprecated(forRemoval = true) -public class MvcRequestMatcher implements RequestMatcher, RequestVariablesExtractor { - - private final DefaultMatcher defaultMatcher = new DefaultMatcher(); - - private final HandlerMappingIntrospector introspector; - - private final String pattern; - - private HttpMethod method; - - private String servletPath; - - public MvcRequestMatcher(HandlerMappingIntrospector introspector, String pattern) { - this.introspector = introspector; - this.pattern = pattern; - } - - @Override - public boolean matches(HttpServletRequest request) { - if (notMatchMethodOrServletPath(request)) { - return false; - } - MatchableHandlerMapping mapping = getMapping(request); - if (mapping == null) { - return this.defaultMatcher.matches(request); - } - RequestMatchResult matchResult = mapping.match(request, this.pattern); - return matchResult != null; - } - - @Override - @Deprecated - public Map extractUriTemplateVariables(HttpServletRequest request) { - return matcher(request).getVariables(); - } - - @Override - public MatchResult matcher(HttpServletRequest request) { - if (notMatchMethodOrServletPath(request)) { - return MatchResult.notMatch(); - } - MatchableHandlerMapping mapping = getMapping(request); - if (mapping == null) { - return this.defaultMatcher.matcher(request); - } - RequestMatchResult result = mapping.match(request, this.pattern); - return (result != null) ? MatchResult.match(result.extractUriTemplateVariables()) : MatchResult.notMatch(); - } - - private boolean notMatchMethodOrServletPath(HttpServletRequest request) { - return this.method != null && !this.method.name().equals(request.getMethod()) - || this.servletPath != null && !this.servletPath.equals(request.getServletPath()); - } - - private MatchableHandlerMapping getMapping(HttpServletRequest request) { - try { - return this.introspector.getMatchableHandlerMapping(request); - } - catch (Throwable ex) { - return null; - } - } - - /** - * @param method the method to set - */ - public void setMethod(HttpMethod method) { - this.method = method; - } - - /** - * The servlet path to match on. The default is undefined which means any servlet - * path. - * @param servletPath the servletPath to set - */ - public void setServletPath(String servletPath) { - this.servletPath = servletPath; - } - - protected final String getServletPath() { - return this.servletPath; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MvcRequestMatcher that = (MvcRequestMatcher) o; - return Objects.equals(this.pattern, that.pattern) && Objects.equals(this.method, that.method) - && Objects.equals(this.servletPath, that.servletPath); - } - - @Override - public int hashCode() { - return Objects.hash(this.pattern, this.method, this.servletPath); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("Mvc [pattern='").append(this.pattern).append("'"); - if (this.servletPath != null) { - sb.append(", servletPath='").append(this.servletPath).append("'"); - } - if (this.method != null) { - sb.append(", ").append(this.method); - } - sb.append("]"); - return sb.toString(); - } - - private class DefaultMatcher implements RequestMatcher { - - private final UrlPathHelper pathHelper = new UrlPathHelper(); - - private final PathMatcher pathMatcher = new AntPathMatcher(); - - @Override - public boolean matches(HttpServletRequest request) { - String lookupPath = this.pathHelper.getLookupPathForRequest(request); - return matches(lookupPath); - } - - private boolean matches(String lookupPath) { - return this.pathMatcher.match(MvcRequestMatcher.this.pattern, lookupPath); - } - - @Override - public MatchResult matcher(HttpServletRequest request) { - String lookupPath = this.pathHelper.getLookupPathForRequest(request); - if (matches(lookupPath)) { - Map variables = this.pathMatcher - .extractUriTemplateVariables(MvcRequestMatcher.this.pattern, lookupPath); - return MatchResult.match(variables); - } - return MatchResult.notMatch(); - } - - } - - /** - * A builder for {@link MvcRequestMatcher} - * - * @author Marcus Da Coregio - * @since 5.8 - */ - public static final class Builder { - - private final HandlerMappingIntrospector introspector; - - private String servletPath; - - /** - * Construct a new instance of this builder - */ - public Builder(HandlerMappingIntrospector introspector) { - this.introspector = introspector; - } - - /** - * Sets the servlet path to be used by the {@link MvcRequestMatcher} generated by - * this builder - * @param servletPath the servlet path to use - * @return the {@link Builder} for further configuration - */ - public Builder servletPath(String servletPath) { - this.servletPath = servletPath; - return this; - } - - /** - * Creates an {@link MvcRequestMatcher} that uses the provided pattern to match - * @param pattern the pattern used to match - * @return the generated {@link MvcRequestMatcher} - */ - public MvcRequestMatcher pattern(String pattern) { - return pattern(null, pattern); - } - - /** - * Creates an {@link MvcRequestMatcher} that uses the provided pattern and HTTP - * method to match - * @param method the {@link HttpMethod}, can be null - * @param pattern the patterns used to match - * @return the generated {@link MvcRequestMatcher} - */ - public MvcRequestMatcher pattern(HttpMethod method, String pattern) { - MvcRequestMatcher mvcRequestMatcher = new MvcRequestMatcher(this.introspector, pattern); - mvcRequestMatcher.setServletPath(this.servletPath); - mvcRequestMatcher.setMethod(method); - return mvcRequestMatcher; - } - - } - -} diff --git a/web/src/main/java/org/springframework/security/web/util/matcher/AntPathRequestMatcher.java b/web/src/main/java/org/springframework/security/web/util/matcher/AntPathRequestMatcher.java deleted file mode 100644 index 0df94264f6..0000000000 --- a/web/src/main/java/org/springframework/security/web/util/matcher/AntPathRequestMatcher.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright 2002-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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.web.util.matcher; - -import java.util.Collections; -import java.util.Locale; -import java.util.Map; - -import jakarta.servlet.http.HttpServletRequest; - -import org.springframework.http.HttpMethod; -import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; -import org.springframework.web.util.UrlPathHelper; - -/** - * Matcher which compares a pre-defined ant-style pattern against the URL ( - * {@code servletPath + pathInfo}) of an {@code HttpServletRequest}. The query string of - * the URL is ignored and matching is case-insensitive or case-sensitive depending on the - * arguments passed into the constructor. - *

- * Using a pattern value of {@code /**} or {@code **} is treated as a universal match, - * which will match any request. Patterns which end with {@code /**} (and have no other - * wildcards) are optimized by using a substring match — a pattern of - * {@code /aaa/**} will match {@code /aaa}, {@code /aaa/} and any sub-directories, such as - * {@code /aaa/bbb/ccc}. - *

- *

- * For all other cases, Spring's {@link AntPathMatcher} is used to perform the match. See - * the Spring documentation for this class for comprehensive information on the syntax - * used. - *

- * - * @author Luke Taylor - * @author Rob Winch - * @author Eddú Meléndez - * @author Evgeniy Cheban - * @author Manuel Jordan - * @since 3.1 - * @see org.springframework.util.AntPathMatcher - * @deprecated please use {@link PathPatternRequestMatcher} instead - */ -@Deprecated(forRemoval = true) -public final class AntPathRequestMatcher implements RequestMatcher, RequestVariablesExtractor { - - private static final String MATCH_ALL = "/**"; - - private final Matcher matcher; - - private final String pattern; - - private final HttpMethod httpMethod; - - private final boolean caseSensitive; - - private final UrlPathHelper urlPathHelper; - - /** - * Creates a matcher with the specific pattern which will match all HTTP methods in a - * case-sensitive manner. - * @param pattern the ant pattern to use for matching - * @since 5.8 - */ - public static AntPathRequestMatcher antMatcher(String pattern) { - Assert.hasText(pattern, "pattern cannot be empty"); - return new AntPathRequestMatcher(pattern); - } - - /** - * Creates a matcher that will match all request with the supplied HTTP method in a - * case-sensitive manner. - * @param method the HTTP method. The {@code matches} method will return false if the - * incoming request doesn't have the same method. - * @since 5.8 - */ - public static AntPathRequestMatcher antMatcher(HttpMethod method) { - Assert.notNull(method, "method cannot be null"); - return new AntPathRequestMatcher(MATCH_ALL, method.name()); - } - - /** - * Creates a matcher with the supplied pattern and HTTP method in a case-sensitive - * manner. - * @param method the HTTP method. The {@code matches} method will return false if the - * incoming request doesn't have the same method. - * @param pattern the ant pattern to use for matching - * @since 5.8 - */ - public static AntPathRequestMatcher antMatcher(HttpMethod method, String pattern) { - Assert.notNull(method, "method cannot be null"); - Assert.hasText(pattern, "pattern cannot be empty"); - return new AntPathRequestMatcher(pattern, method.name()); - } - - /** - * Creates a matcher with the specific pattern which will match all HTTP methods in a - * case sensitive manner. - * @param pattern the ant pattern to use for matching - */ - public AntPathRequestMatcher(String pattern) { - this(pattern, null); - } - - /** - * Creates a matcher with the supplied pattern and HTTP method in a case sensitive - * manner. - * @param pattern the ant pattern to use for matching - * @param httpMethod the HTTP method. The {@code matches} method will return false if - * the incoming request doesn't have the same method. - */ - public AntPathRequestMatcher(String pattern, String httpMethod) { - this(pattern, httpMethod, true); - } - - /** - * Creates a matcher with the supplied pattern which will match the specified Http - * method - * @param pattern the ant pattern to use for matching - * @param httpMethod the HTTP method. The {@code matches} method will return false if - * the incoming request doesn't doesn't have the same method. - * @param caseSensitive true if the matcher should consider case, else false - */ - public AntPathRequestMatcher(String pattern, String httpMethod, boolean caseSensitive) { - this(pattern, httpMethod, caseSensitive, null); - } - - /** - * Creates a matcher with the supplied pattern which will match the specified Http - * method - * @param pattern the ant pattern to use for matching - * @param httpMethod the HTTP method. The {@code matches} method will return false if - * the incoming request doesn't have the same method. - * @param caseSensitive true if the matcher should consider case, else false - * @param urlPathHelper if non-null, will be used for extracting the path from the - * HttpServletRequest - */ - public AntPathRequestMatcher(String pattern, String httpMethod, boolean caseSensitive, - UrlPathHelper urlPathHelper) { - Assert.hasText(pattern, "Pattern cannot be null or empty"); - this.caseSensitive = caseSensitive; - if (pattern.equals(MATCH_ALL) || pattern.equals("**")) { - pattern = MATCH_ALL; - this.matcher = null; - } - else { - // If the pattern ends with {@code /**} and has no other wildcards or path - // variables, then optimize to a sub-path match - if (pattern.endsWith(MATCH_ALL) - && (pattern.indexOf('?') == -1 && pattern.indexOf('{') == -1 && pattern.indexOf('}') == -1) - && pattern.indexOf("*") == pattern.length() - 2) { - this.matcher = new SubpathMatcher(pattern.substring(0, pattern.length() - 3), caseSensitive); - } - else { - this.matcher = new SpringAntMatcher(pattern, caseSensitive); - } - } - this.pattern = pattern; - this.httpMethod = StringUtils.hasText(httpMethod) ? HttpMethod.valueOf(httpMethod) : null; - this.urlPathHelper = urlPathHelper; - } - - /** - * Returns true if the configured pattern (and HTTP-Method) match those of the - * supplied request. - * @param request the request to match against. The ant pattern will be matched - * against the {@code servletPath} + {@code pathInfo} of the request. - */ - @Override - public boolean matches(HttpServletRequest request) { - if (this.httpMethod != null && StringUtils.hasText(request.getMethod()) - && this.httpMethod != HttpMethod.valueOf(request.getMethod())) { - return false; - } - if (this.pattern.equals(MATCH_ALL)) { - return true; - } - String url = getRequestPath(request); - return this.matcher.matches(url); - } - - @Override - @Deprecated - public Map extractUriTemplateVariables(HttpServletRequest request) { - return matcher(request).getVariables(); - } - - @Override - public MatchResult matcher(HttpServletRequest request) { - if (!matches(request)) { - return MatchResult.notMatch(); - } - if (this.matcher == null) { - return MatchResult.match(); - } - String url = getRequestPath(request); - return MatchResult.match(this.matcher.extractUriTemplateVariables(url)); - } - - private String getRequestPath(HttpServletRequest request) { - if (this.urlPathHelper != null) { - return this.urlPathHelper.getPathWithinApplication(request); - } - String url = request.getServletPath(); - String pathInfo = request.getPathInfo(); - if (pathInfo != null) { - url = StringUtils.hasLength(url) ? url + pathInfo : pathInfo; - } - return url; - } - - public String getPattern() { - return this.pattern; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof AntPathRequestMatcher other)) { - return false; - } - return this.pattern.equals(other.pattern) && this.httpMethod == other.httpMethod - && this.caseSensitive == other.caseSensitive; - } - - @Override - public int hashCode() { - int result = (this.pattern != null) ? this.pattern.hashCode() : 0; - result = 31 * result + ((this.httpMethod != null) ? this.httpMethod.hashCode() : 0); - result = 31 * result + (this.caseSensitive ? 1231 : 1237); - return result; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("Ant [pattern='").append(this.pattern).append("'"); - if (this.httpMethod != null) { - sb.append(", ").append(this.httpMethod); - } - sb.append("]"); - return sb.toString(); - } - - private interface Matcher { - - boolean matches(String path); - - Map extractUriTemplateVariables(String path); - - } - - private static final class SpringAntMatcher implements Matcher { - - private final AntPathMatcher antMatcher; - - private final String pattern; - - private SpringAntMatcher(String pattern, boolean caseSensitive) { - this.pattern = pattern; - this.antMatcher = createMatcher(caseSensitive); - } - - @Override - public boolean matches(String path) { - return this.antMatcher.match(this.pattern, path); - } - - @Override - public Map extractUriTemplateVariables(String path) { - return this.antMatcher.extractUriTemplateVariables(this.pattern, path); - } - - private static AntPathMatcher createMatcher(boolean caseSensitive) { - AntPathMatcher matcher = new AntPathMatcher(); - matcher.setTrimTokens(false); - matcher.setCaseSensitive(caseSensitive); - return matcher; - } - - } - - /** - * Optimized matcher for trailing wildcards - */ - private static final class SubpathMatcher implements Matcher { - - private final String subpath; - - private final int length; - - private final boolean caseSensitive; - - private SubpathMatcher(String subpath, boolean caseSensitive) { - Assert.isTrue(!subpath.contains("*"), "subpath cannot contain \"*\""); - this.subpath = caseSensitive ? subpath : subpath.toLowerCase(Locale.ROOT); - this.length = subpath.length(); - this.caseSensitive = caseSensitive; - } - - @Override - public boolean matches(String path) { - if (!this.caseSensitive) { - path = path.toLowerCase(Locale.ROOT); - } - return path.startsWith(this.subpath) && (path.length() == this.length || path.charAt(this.length) == '/'); - } - - @Override - public Map extractUriTemplateVariables(String path) { - return Collections.emptyMap(); - } - - } - -} diff --git a/web/src/test/java/org/springframework/security/web/RequestMatcherRedirectFilterTests.java b/web/src/test/java/org/springframework/security/web/RequestMatcherRedirectFilterTests.java index 29c8d46abf..1340c36365 100644 --- a/web/src/test/java/org/springframework/security/web/RequestMatcherRedirectFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/RequestMatcherRedirectFilterTests.java @@ -22,7 +22,7 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpStatus; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -37,9 +37,11 @@ import static org.mockito.Mockito.verifyNoInteractions; */ public class RequestMatcherRedirectFilterTests { + private final PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withDefaults(); + @Test public void doFilterWhenRequestMatchThenRedirectToSpecifiedUrl() throws Exception { - RequestMatcherRedirectFilter filter = new RequestMatcherRedirectFilter(new AntPathRequestMatcher("/context"), + RequestMatcherRedirectFilter filter = new RequestMatcherRedirectFilter(this.builder.matcher("/context"), "/test"); MockHttpServletRequest request = new MockHttpServletRequest(); @@ -58,7 +60,7 @@ public class RequestMatcherRedirectFilterTests { @Test public void doFilterWhenRequestNotMatchThenNextFilter() throws Exception { - RequestMatcherRedirectFilter filter = new RequestMatcherRedirectFilter(new AntPathRequestMatcher("/context"), + RequestMatcherRedirectFilter filter = new RequestMatcherRedirectFilter(this.builder.matcher("/context"), "/test"); MockHttpServletRequest request = new MockHttpServletRequest(); @@ -83,21 +85,21 @@ public class RequestMatcherRedirectFilterTests { @Test public void constructWhenRedirectUrlNull() { assertThatIllegalArgumentException() - .isThrownBy(() -> new RequestMatcherRedirectFilter(new AntPathRequestMatcher("/**"), null)) + .isThrownBy(() -> new RequestMatcherRedirectFilter(this.builder.matcher("/**"), null)) .withMessage("redirectUrl cannot be empty"); } @Test public void constructWhenRedirectUrlEmpty() { assertThatIllegalArgumentException() - .isThrownBy(() -> new RequestMatcherRedirectFilter(new AntPathRequestMatcher("/**"), "")) + .isThrownBy(() -> new RequestMatcherRedirectFilter(this.builder.matcher("/**"), "")) .withMessage("redirectUrl cannot be empty"); } @Test public void constructWhenRedirectUrlBlank() { assertThatIllegalArgumentException() - .isThrownBy(() -> new RequestMatcherRedirectFilter(new AntPathRequestMatcher("/**"), " ")) + .isThrownBy(() -> new RequestMatcherRedirectFilter(this.builder.matcher("/**"), " ")) .withMessage("redirectUrl cannot be empty"); } diff --git a/web/src/test/java/org/springframework/security/web/access/HandlerMappingIntrospectorRequestTransformerTests.java b/web/src/test/java/org/springframework/security/web/access/HandlerMappingIntrospectorRequestTransformerTests.java deleted file mode 100644 index 96bf8e9581..0000000000 --- a/web/src/test/java/org/springframework/security/web/access/HandlerMappingIntrospectorRequestTransformerTests.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright 2002-2023 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.web.access; - -import java.util.Collections; - -import jakarta.servlet.DispatcherType; -import jakarta.servlet.http.HttpServletRequest; -import org.assertj.core.api.AssertionsForClassTypes; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; - -/** - * @author Rob Winch - */ -@ExtendWith(MockitoExtension.class) -class HandlerMappingIntrospectorRequestTransformerTests { - - @Mock - HandlerMappingIntrospector hmi; - - HandlerMappingIntrospectorRequestTransformer transformer; - - @BeforeEach - void setup() { - this.transformer = new HandlerMappingIntrospectorRequestTransformer(this.hmi); - } - - @Test - void constructorWhenHmiIsNullThenIllegalArgumentException() { - AssertionsForClassTypes.assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> new HandlerMappingIntrospectorRequestTransformer(null)); - } - - @Test - void transformThenNewRequestPassedToSetCache() { - MockHttpServletRequest request = new MockHttpServletRequest(); - - HttpServletRequest transformedRequest = this.transformer.transform(request); - - ArgumentCaptor requestArg = ArgumentCaptor.forClass(HttpServletRequest.class); - verify(this.hmi).setCache(requestArg.capture()); - assertThat(transformedRequest).isNotEqualTo(request); - } - - @Test - void transformThenResultPassedToSetCache() { - MockHttpServletRequest request = new MockHttpServletRequest(); - - HttpServletRequest transformedRequest = this.transformer.transform(request); - - ArgumentCaptor requestArg = ArgumentCaptor.forClass(HttpServletRequest.class); - verify(this.hmi).setCache(requestArg.capture()); - assertThat(requestArg.getValue()).isEqualTo(transformedRequest); - } - - /** - * The request passed into the transformer does not allow interactions on certain - * methods, we need to ensure that the methods used by - * {@link HandlerMappingIntrospector#setCache(HttpServletRequest)} are overridden. - */ - @Test - void transformThenResultDoesNotDelegateToSetAttribute() { - HttpServletRequest request = mock(HttpServletRequest.class); - - this.transformer.transform(request); - - ArgumentCaptor requestArg = ArgumentCaptor.forClass(HttpServletRequest.class); - verify(this.hmi).setCache(requestArg.capture()); - HttpServletRequest transformedRequest = requestArg.getValue(); - String attrName = "any"; - String attrValue = "value"; - transformedRequest.setAttribute(attrName, attrValue); - verifyNoInteractions(request); - assertThat(transformedRequest.getAttribute(attrName)).isEqualTo(attrValue); - } - - @Test - void transformThenSetAttributeWorks() { - HttpServletRequest request = mock(HttpServletRequest.class); - - this.transformer.transform(request); - - ArgumentCaptor requestArg = ArgumentCaptor.forClass(HttpServletRequest.class); - verify(this.hmi).setCache(requestArg.capture()); - HttpServletRequest transformedRequest = requestArg.getValue(); - String attrName = "any"; - String attrValue = "value"; - transformedRequest.setAttribute(attrName, attrValue); - assertThat(transformedRequest.getAttribute(attrName)).isEqualTo(attrValue); - } - - /** - * The request passed into the transformer does not allow interactions on certain - * methods, we need to ensure that the methods used by - * {@link HandlerMappingIntrospector#setCache(HttpServletRequest)} are overridden. - */ - @Test - void transformThenResultDoesNotDelegateToGetAttribute() { - HttpServletRequest request = mock(HttpServletRequest.class); - - this.transformer.transform(request); - - ArgumentCaptor requestArg = ArgumentCaptor.forClass(HttpServletRequest.class); - verify(this.hmi).setCache(requestArg.capture()); - HttpServletRequest transformedRequest = requestArg.getValue(); - transformedRequest.getAttribute("any"); - verifyNoInteractions(request); - } - - /** - * The request passed into the transformer does not allow interactions on certain - * methods, we need to ensure that the methods used by - * {@link HandlerMappingIntrospector#setCache(HttpServletRequest)} are overridden. - */ - @Test - void transformThenResultDoesNotDelegateToGetAttributeNames() { - HttpServletRequest request = mock(HttpServletRequest.class); - - this.transformer.transform(request); - - ArgumentCaptor requestArg = ArgumentCaptor.forClass(HttpServletRequest.class); - verify(this.hmi).setCache(requestArg.capture()); - HttpServletRequest transformedRequest = requestArg.getValue(); - transformedRequest.getAttributeNames(); - verifyNoInteractions(request); - } - - @Test - void transformThenGetAttributeNamesWorks() { - HttpServletRequest request = mock(HttpServletRequest.class); - - this.transformer.transform(request); - - ArgumentCaptor requestArg = ArgumentCaptor.forClass(HttpServletRequest.class); - verify(this.hmi).setCache(requestArg.capture()); - HttpServletRequest transformedRequest = requestArg.getValue(); - String attrName = "any"; - String attrValue = "value"; - transformedRequest.setAttribute(attrName, attrValue); - assertThat(Collections.list(transformedRequest.getAttributeNames())).containsExactly(attrName); - } - - /** - * The request passed into the transformer does not allow interactions on certain - * methods, we need to ensure that the methods used by - * {@link HandlerMappingIntrospector#setCache(HttpServletRequest)} are overridden. - */ - @Test - void transformThenResultDoesNotDelegateToRemoveAttribute() { - HttpServletRequest request = mock(HttpServletRequest.class); - - this.transformer.transform(request); - - ArgumentCaptor requestArg = ArgumentCaptor.forClass(HttpServletRequest.class); - verify(this.hmi).setCache(requestArg.capture()); - HttpServletRequest transformedRequest = requestArg.getValue(); - transformedRequest.removeAttribute("any"); - verifyNoInteractions(request); - } - - /** - * The request passed into the transformer does not allow interactions on certain - * methods, we need to ensure that the methods used by - * {@link HandlerMappingIntrospector#setCache(HttpServletRequest)} are overridden. - */ - @Test - void transformThenResultDoesNotDelegateToGetDispatcherType() { - HttpServletRequest request = mock(HttpServletRequest.class); - - this.transformer.transform(request); - - ArgumentCaptor requestArg = ArgumentCaptor.forClass(HttpServletRequest.class); - verify(this.hmi).setCache(requestArg.capture()); - HttpServletRequest transformedRequest = requestArg.getValue(); - assertThat(transformedRequest.getDispatcherType()).isEqualTo(DispatcherType.REQUEST); - verifyNoInteractions(request); - } - -} diff --git a/web/src/test/java/org/springframework/security/web/access/intercept/DefaultFilterInvocationSecurityMetadataSourceTests.java b/web/src/test/java/org/springframework/security/web/access/intercept/DefaultFilterInvocationSecurityMetadataSourceTests.java index 8a111bd357..5460be992c 100644 --- a/web/src/test/java/org/springframework/security/web/access/intercept/DefaultFilterInvocationSecurityMetadataSourceTests.java +++ b/web/src/test/java/org/springframework/security/web/access/intercept/DefaultFilterInvocationSecurityMetadataSourceTests.java @@ -22,12 +22,13 @@ import java.util.LinkedHashMap; import jakarta.servlet.FilterChain; import org.junit.jupiter.api.Test; +import org.springframework.http.HttpMethod; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.web.FilterInvocation; -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; import static org.assertj.core.api.Assertions.assertThat; @@ -44,9 +45,9 @@ public class DefaultFilterInvocationSecurityMetadataSourceTests { private Collection def = SecurityConfig.createList("ROLE_ONE"); - private void createFids(String pattern, String method) { + private void createFids(String pattern, HttpMethod method) { LinkedHashMap> requestMap = new LinkedHashMap<>(); - requestMap.put(new AntPathRequestMatcher(pattern, method), this.def); + requestMap.put(PathPatternRequestMatcher.withDefaults().matcher(method, pattern), this.def); this.fids = new DefaultFilterInvocationSecurityMetadataSource(requestMap); } @@ -88,7 +89,7 @@ public class DefaultFilterInvocationSecurityMetadataSourceTests { @Test public void httpMethodLookupSucceeds() { - createFids("/somepage**", "GET"); + createFids("/somepage**", HttpMethod.GET); FilterInvocation fi = createFilterInvocation("/somepage", null, null, "GET"); Collection attrs = this.fids.getAttributes(fi); assertThat(attrs).isEqualTo(this.def); @@ -104,7 +105,7 @@ public class DefaultFilterInvocationSecurityMetadataSourceTests { @Test public void requestWithDifferentHttpMethodDoesntMatch() { - createFids("/somepage**", "GET"); + createFids("/somepage**", HttpMethod.GET); FilterInvocation fi = createFilterInvocation("/somepage", null, null, "POST"); Collection attrs = this.fids.getAttributes(fi); assertThat(attrs).isNull(); @@ -115,8 +116,9 @@ public class DefaultFilterInvocationSecurityMetadataSourceTests { public void mixingPatternsWithAndWithoutHttpMethodsIsSupported() { LinkedHashMap> requestMap = new LinkedHashMap<>(); Collection userAttrs = SecurityConfig.createList("A"); - requestMap.put(new AntPathRequestMatcher("/user/**", null), userAttrs); - requestMap.put(new AntPathRequestMatcher("/teller/**", "GET"), SecurityConfig.createList("B")); + requestMap.put(PathPatternRequestMatcher.withDefaults().matcher("/user/**"), userAttrs); + requestMap.put(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/teller/**"), + SecurityConfig.createList("B")); this.fids = new DefaultFilterInvocationSecurityMetadataSource(requestMap); FilterInvocation fi = createFilterInvocation("/user", null, null, "GET"); Collection attrs = this.fids.getAttributes(fi); diff --git a/web/src/test/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManagerTests.java b/web/src/test/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManagerTests.java index dfb754fed5..e360379c07 100644 --- a/web/src/test/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManagerTests.java +++ b/web/src/test/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManagerTests.java @@ -28,8 +28,7 @@ import org.springframework.security.authorization.AuthorityAuthorizationManager; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.SingleResultAuthorizationManager; import org.springframework.security.core.Authentication; -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.security.web.util.matcher.AnyRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcherEntry; @@ -45,6 +44,8 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; */ public class RequestMatcherDelegatingAuthorizationManagerTests { + private final PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withDefaults(); + @Test public void buildWhenMappingsEmptyThenException() { assertThatIllegalArgumentException() @@ -65,7 +66,7 @@ public class RequestMatcherDelegatingAuthorizationManagerTests { public void addWhenManagerNullThenException() { assertThatIllegalArgumentException() .isThrownBy(() -> RequestMatcherDelegatingAuthorizationManager.builder() - .add(new MvcRequestMatcher(null, "/grant"), null) + .add(this.builder.matcher("/grant"), null) .build()) .withMessage("manager cannot be null"); } @@ -73,8 +74,8 @@ public class RequestMatcherDelegatingAuthorizationManagerTests { @Test public void checkWhenMultipleMappingsConfiguredThenDelegatesMatchingManager() { RequestMatcherDelegatingAuthorizationManager manager = RequestMatcherDelegatingAuthorizationManager.builder() - .add(new MvcRequestMatcher(null, "/grant"), SingleResultAuthorizationManager.permitAll()) - .add(new MvcRequestMatcher(null, "/deny"), SingleResultAuthorizationManager.denyAll()) + .add(this.builder.matcher(null, "/grant"), SingleResultAuthorizationManager.permitAll()) + .add(this.builder.matcher(null, "/deny"), SingleResultAuthorizationManager.denyAll()) .build(); Supplier authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER"); @@ -97,11 +98,11 @@ public class RequestMatcherDelegatingAuthorizationManagerTests { public void checkWhenMultipleMappingsConfiguredWithConsumerThenDelegatesMatchingManager() { RequestMatcherDelegatingAuthorizationManager manager = RequestMatcherDelegatingAuthorizationManager.builder() .mappings((m) -> { - m.add(new RequestMatcherEntry<>(new MvcRequestMatcher(null, "/grant"), + m.add(new RequestMatcherEntry<>(this.builder.matcher("/grant"), SingleResultAuthorizationManager.permitAll())); m.add(new RequestMatcherEntry<>(AnyRequestMatcher.INSTANCE, AuthorityAuthorizationManager.hasRole("ADMIN"))); - m.add(new RequestMatcherEntry<>(new MvcRequestMatcher(null, "/afterAny"), + m.add(new RequestMatcherEntry<>(this.builder.matcher("/afterAny"), SingleResultAuthorizationManager.permitAll())); }) .build(); @@ -156,7 +157,7 @@ public class RequestMatcherDelegatingAuthorizationManagerTests { .isThrownBy(() -> RequestMatcherDelegatingAuthorizationManager.builder() .anyRequest() .authenticated() - .requestMatchers(new AntPathRequestMatcher("/authenticated")) + .requestMatchers(this.builder.matcher("/authenticated")) .authenticated() .build()) .withMessage("Can't configure requestMatchers after anyRequest"); diff --git a/web/src/test/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilterTests.java index 00e4de0614..70cf88853b 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilterTests.java @@ -47,7 +47,7 @@ import org.springframework.security.web.authentication.session.SessionAuthentica import org.springframework.security.web.context.RequestAttributeSecurityContextRepository; import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.security.web.firewall.DefaultHttpFirewall; -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; import org.springframework.test.util.ReflectionTestUtils; @@ -239,7 +239,8 @@ public class AbstractAuthenticationProcessingFilterTests { MockHttpServletResponse response = new MockHttpServletResponse(); // Setup our test object, to grant access MockAuthenticationFilter filter = new MockAuthenticationFilter( - new AntPathRequestMatcher("/j_eradicate_corona_virus"), mock(AuthenticationManager.class)); + PathPatternRequestMatcher.withDefaults().matcher("/j_eradicate_corona_virus"), + mock(AuthenticationManager.class)); filter.setSessionAuthenticationStrategy(mock(SessionAuthenticationStrategy.class)); filter.setAuthenticationSuccessHandler(this.successHandler); filter.setAuthenticationFailureHandler(this.failureHandler); @@ -273,7 +274,7 @@ public class AbstractAuthenticationProcessingFilterTests { filter.setAuthenticationManager(mock(AuthenticationManager.class)); filter.setAuthenticationSuccessHandler(this.successHandler); assertThatIllegalArgumentException().isThrownBy(() -> filter.setFilterProcessesUrl(null)) - .withMessage("Pattern cannot be null or empty"); + .withMessage("pattern cannot be null"); } @Test diff --git a/web/src/test/java/org/springframework/security/web/authentication/RequestMatcherDelegatingAuthenticationManagerResolverTests.java b/web/src/test/java/org/springframework/security/web/authentication/RequestMatcherDelegatingAuthenticationManagerResolverTests.java index de9e3e2561..4dbf8acccc 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/RequestMatcherDelegatingAuthenticationManagerResolverTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/RequestMatcherDelegatingAuthenticationManagerResolverTests.java @@ -23,7 +23,7 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -44,8 +44,8 @@ public class RequestMatcherDelegatingAuthenticationManagerResolverTests { public void resolveWhenMatchesThenReturnsAuthenticationManager() { RequestMatcherDelegatingAuthenticationManagerResolver resolver = RequestMatcherDelegatingAuthenticationManagerResolver .builder() - .add(new AntPathRequestMatcher("/one/**"), this.one) - .add(new AntPathRequestMatcher("/two/**"), this.two) + .add(PathPatternRequestMatcher.withDefaults().matcher("/one/**"), this.one) + .add(PathPatternRequestMatcher.withDefaults().matcher("/two/**"), this.two) .build(); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/one/location"); @@ -57,8 +57,8 @@ public class RequestMatcherDelegatingAuthenticationManagerResolverTests { public void resolveWhenDoesNotMatchThenReturnsDefaultAuthenticationManager() { RequestMatcherDelegatingAuthenticationManagerResolver resolver = RequestMatcherDelegatingAuthenticationManagerResolver .builder() - .add(new AntPathRequestMatcher("/one/**"), this.one) - .add(new AntPathRequestMatcher("/two/**"), this.two) + .add(PathPatternRequestMatcher.withDefaults().matcher("/one/**"), this.one) + .add(PathPatternRequestMatcher.withDefaults().matcher("/two/**"), this.two) .build(); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/wrong/location"); diff --git a/web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java index 5598b5543d..c725b8eb9d 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java @@ -41,7 +41,7 @@ import org.springframework.security.web.WebAttributes; import org.springframework.security.web.authentication.ForwardAuthenticationFailureHandler; import org.springframework.security.web.authentication.ForwardAuthenticationSuccessHandler; import org.springframework.security.web.context.SecurityContextRepository; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -60,6 +60,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; */ public class AbstractPreAuthenticatedProcessingFilterTests { + private final PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withDefaults(); + private AbstractPreAuthenticatedProcessingFilter filter; @BeforeEach @@ -367,7 +369,7 @@ public class AbstractPreAuthenticatedProcessingFilterTests { MockHttpServletResponse response = new MockHttpServletResponse(); MockFilterChain chain = new MockFilterChain(); ConcretePreAuthenticatedProcessingFilter filter = new ConcretePreAuthenticatedProcessingFilter(); - filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/no-matching")); + filter.setRequiresAuthenticationRequestMatcher(this.builder.matcher("/no-matching")); AuthenticationManager am = mock(AuthenticationManager.class); filter.setAuthenticationManager(am); filter.afterPropertiesSet(); @@ -381,7 +383,7 @@ public class AbstractPreAuthenticatedProcessingFilterTests { MockHttpServletResponse response = new MockHttpServletResponse(); MockFilterChain chain = new MockFilterChain(); ConcretePreAuthenticatedProcessingFilter filter = new ConcretePreAuthenticatedProcessingFilter(); - filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/**")); + filter.setRequiresAuthenticationRequestMatcher(this.builder.matcher("/**")); AuthenticationManager am = mock(AuthenticationManager.class); filter.setAuthenticationManager(am); filter.afterPropertiesSet(); diff --git a/web/src/test/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilterTests.java index faf9f17db4..389756b41b 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilterTests.java @@ -46,7 +46,7 @@ import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.security.web.authentication.WebAuthenticationDetails; import org.springframework.security.web.context.RequestAttributeSecurityContextRepository; import org.springframework.security.web.context.SecurityContextRepository; -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; import org.springframework.web.util.WebUtils; @@ -531,7 +531,7 @@ public class BasicAuthenticationFilterTests { static class TestAuthenticationConverter implements AuthenticationConverter { - private final RequestMatcher matcher = AntPathRequestMatcher.antMatcher("/ignored"); + private final RequestMatcher matcher = PathPatternRequestMatcher.withDefaults().matcher("/ignored"); private final BasicAuthenticationConverter delegate = new BasicAuthenticationConverter(); diff --git a/web/src/test/java/org/springframework/security/web/servlet/util/matcher/MvcRequestMatcherTests.java b/web/src/test/java/org/springframework/security/web/servlet/util/matcher/MvcRequestMatcherTests.java deleted file mode 100644 index 047f42604c..0000000000 --- a/web/src/test/java/org/springframework/security/web/servlet/util/matcher/MvcRequestMatcherTests.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright 2012-2022 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.web.servlet.util.matcher; - -import java.util.Collections; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import org.springframework.http.HttpMethod; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.web.HttpRequestMethodNotSupportedException; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; -import org.springframework.web.servlet.handler.MatchableHandlerMapping; -import org.springframework.web.servlet.handler.RequestMatchResult; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.verifyNoMoreInteractions; - -/** - * @author Rob Winch - * @author Eddú Meléndez - * @author Evgeniy Cheban - */ -@ExtendWith(MockitoExtension.class) -public class MvcRequestMatcherTests { - - @Mock - HandlerMappingIntrospector introspector; - - @Mock - MatchableHandlerMapping mapping; - - @Mock - RequestMatchResult result; - - @Captor - ArgumentCaptor pattern; - - MockHttpServletRequest request; - - MvcRequestMatcher matcher; - - @BeforeEach - public void setup() { - this.request = new MockHttpServletRequest(); - this.request.setMethod("GET"); - this.request.setServletPath("/path"); - this.matcher = new MvcRequestMatcher(this.introspector, "/path"); - } - - @Test - public void extractUriTemplateVariablesSuccess() throws Exception { - this.matcher = new MvcRequestMatcher(this.introspector, "/{p}"); - given(this.introspector.getMatchableHandlerMapping(this.request)).willReturn(null); - assertThat(this.matcher.extractUriTemplateVariables(this.request)).containsEntry("p", "path"); - assertThat(this.matcher.matcher(this.request).getVariables()).containsEntry("p", "path"); - } - - @Test - public void extractUriTemplateVariablesFail() throws Exception { - given(this.result.extractUriTemplateVariables()).willReturn(Collections.emptyMap()); - given(this.introspector.getMatchableHandlerMapping(this.request)).willReturn(this.mapping); - given(this.mapping.match(eq(this.request), this.pattern.capture())).willReturn(this.result); - assertThat(this.matcher.extractUriTemplateVariables(this.request)).isEmpty(); - assertThat(this.matcher.matcher(this.request).getVariables()).isEmpty(); - } - - @Test - public void extractUriTemplateVariablesDefaultSuccess() throws Exception { - this.matcher = new MvcRequestMatcher(this.introspector, "/{p}"); - given(this.introspector.getMatchableHandlerMapping(this.request)).willReturn(null); - assertThat(this.matcher.extractUriTemplateVariables(this.request)).containsEntry("p", "path"); - assertThat(this.matcher.matcher(this.request).getVariables()).containsEntry("p", "path"); - } - - @Test - public void extractUriTemplateVariablesDefaultFail() throws Exception { - this.matcher = new MvcRequestMatcher(this.introspector, "/nomatch/{p}"); - given(this.introspector.getMatchableHandlerMapping(this.request)).willReturn(null); - assertThat(this.matcher.extractUriTemplateVariables(this.request)).isEmpty(); - assertThat(this.matcher.matcher(this.request).getVariables()).isEmpty(); - } - - @Test - public void matchesServletPathTrue() throws Exception { - given(this.introspector.getMatchableHandlerMapping(this.request)).willReturn(this.mapping); - given(this.mapping.match(eq(this.request), this.pattern.capture())).willReturn(this.result); - this.matcher.setServletPath("/spring"); - this.request.setServletPath("/spring"); - assertThat(this.matcher.matches(this.request)).isTrue(); - assertThat(this.pattern.getValue()).isEqualTo("/path"); - } - - @Test - public void matchesServletPathFalse() { - this.matcher.setServletPath("/spring"); - this.request.setServletPath("/"); - assertThat(this.matcher.matches(this.request)).isFalse(); - } - - @Test - public void matchesPathOnlyTrue() throws Exception { - given(this.introspector.getMatchableHandlerMapping(this.request)).willReturn(this.mapping); - given(this.mapping.match(eq(this.request), this.pattern.capture())).willReturn(this.result); - assertThat(this.matcher.matches(this.request)).isTrue(); - assertThat(this.pattern.getValue()).isEqualTo("/path"); - } - - @Test - public void matchesDefaultMatches() throws Exception { - given(this.introspector.getMatchableHandlerMapping(this.request)).willReturn(null); - assertThat(this.matcher.matches(this.request)).isTrue(); - } - - @Test - public void matchesDefaultDoesNotMatch() throws Exception { - this.request.setServletPath("/other"); - given(this.introspector.getMatchableHandlerMapping(this.request)).willReturn(null); - assertThat(this.matcher.matches(this.request)).isFalse(); - } - - @Test - public void matchesPathOnlyFalse() throws Exception { - given(this.introspector.getMatchableHandlerMapping(this.request)).willReturn(this.mapping); - assertThat(this.matcher.matches(this.request)).isFalse(); - } - - @Test - public void matchesMethodAndPathTrue() throws Exception { - this.matcher.setMethod(HttpMethod.GET); - given(this.introspector.getMatchableHandlerMapping(this.request)).willReturn(this.mapping); - given(this.mapping.match(eq(this.request), this.pattern.capture())).willReturn(this.result); - assertThat(this.matcher.matches(this.request)).isTrue(); - assertThat(this.pattern.getValue()).isEqualTo("/path"); - } - - @Test - public void matchesMethodAndPathFalseMethod() { - this.matcher.setMethod(HttpMethod.POST); - assertThat(this.matcher.matches(this.request)).isFalse(); - // method compare should be done first since faster - verifyNoMoreInteractions(this.introspector); - } - - /** - * Malicious users can specify any HTTP Method to create a stacktrace and try to - * expose useful information about the system. We should ensure we ignore invalid HTTP - * methods. - */ - @Test - public void matchesInvalidMethodOnRequest() { - this.matcher.setMethod(HttpMethod.GET); - this.request.setMethod("invalid"); - assertThat(this.matcher.matches(this.request)).isFalse(); - // method compare should be done first since faster - verifyNoMoreInteractions(this.introspector); - } - - @Test - public void matchesMethodAndPathFalsePath() throws Exception { - this.matcher.setMethod(HttpMethod.GET); - given(this.introspector.getMatchableHandlerMapping(this.request)).willReturn(this.mapping); - assertThat(this.matcher.matches(this.request)).isFalse(); - } - - @Test - public void matchesGetMatchableHandlerMappingNull() { - assertThat(this.matcher.matches(this.request)).isTrue(); - } - - @Test - public void matchesGetMatchableHandlerMappingThrows() throws Exception { - given(this.introspector.getMatchableHandlerMapping(this.request)) - .willThrow(new HttpRequestMethodNotSupportedException(this.request.getMethod())); - assertThat(this.matcher.matches(this.request)).isTrue(); - } - - @Test - public void toStringWhenAll() { - this.matcher.setMethod(HttpMethod.GET); - this.matcher.setServletPath("/spring"); - assertThat(this.matcher.toString()).isEqualTo("Mvc [pattern='/path', servletPath='/spring', GET]"); - } - - @Test - public void toStringWhenHttpMethod() { - this.matcher.setMethod(HttpMethod.GET); - assertThat(this.matcher.toString()).isEqualTo("Mvc [pattern='/path', GET]"); - } - - @Test - public void toStringWhenServletPath() { - this.matcher.setServletPath("/spring"); - assertThat(this.matcher.toString()).isEqualTo("Mvc [pattern='/path', servletPath='/spring']"); - } - - @Test - public void toStringWhenOnlyPattern() { - assertThat(this.matcher.toString()).isEqualTo("Mvc [pattern='/path']"); - } - - @Test - public void matcherWhenMethodNotMatchesThenNotMatchResult() { - this.matcher.setMethod(HttpMethod.POST); - assertThat(this.matcher.matcher(this.request).isMatch()).isFalse(); - } - - @Test - public void matcherWhenMethodMatchesThenMatchResult() { - this.matcher.setMethod(HttpMethod.GET); - assertThat(this.matcher.matcher(this.request).isMatch()).isTrue(); - } - - @Test - public void matcherWhenServletPathNotMatchesThenNotMatchResult() { - this.matcher.setServletPath("/spring"); - assertThat(this.matcher.matcher(this.request).isMatch()).isFalse(); - } - - @Test - public void matcherWhenServletPathMatchesThenMatchResult() { - this.matcher.setServletPath("/path"); - assertThat(this.matcher.matcher(this.request).isMatch()).isTrue(); - } - - @Test - public void builderWhenServletPathThenServletPathPresent() { - MvcRequestMatcher matcher = new MvcRequestMatcher.Builder(this.introspector).servletPath("/path") - .pattern("/endpoint"); - assertThat(matcher.getServletPath()).isEqualTo("/path"); - assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/endpoint"); - assertThat(ReflectionTestUtils.getField(matcher, "method")).isNull(); - } - - @Test - public void builderWhenPatternThenPatternPresent() { - MvcRequestMatcher matcher = new MvcRequestMatcher.Builder(this.introspector).pattern("/endpoint"); - assertThat(matcher.getServletPath()).isNull(); - assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/endpoint"); - assertThat(ReflectionTestUtils.getField(matcher, "method")).isNull(); - } - - @Test - public void builderWhenMethodAndPatternThenMethodAndPatternPresent() { - MvcRequestMatcher matcher = new MvcRequestMatcher.Builder(this.introspector).pattern(HttpMethod.GET, - "/endpoint"); - assertThat(matcher.getServletPath()).isNull(); - assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/endpoint"); - assertThat(ReflectionTestUtils.getField(matcher, "method")).isEqualTo(HttpMethod.GET); - } - -} diff --git a/web/src/test/java/org/springframework/security/web/util/matcher/AndRequestMatcherTests.java b/web/src/test/java/org/springframework/security/web/util/matcher/AndRequestMatcherTests.java index 62b3781790..4dc56d8773 100644 --- a/web/src/test/java/org/springframework/security/web/util/matcher/AndRequestMatcherTests.java +++ b/web/src/test/java/org/springframework/security/web/util/matcher/AndRequestMatcherTests.java @@ -27,6 +27,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher.MatchResult; import static org.assertj.core.api.Assertions.assertThat; @@ -59,7 +60,7 @@ public class AndRequestMatcherTests { @Test public void constructorListOfDoesNotThrowNullPointer() { - new AndRequestMatcher(List.of(new AntPathRequestMatcher("/test"))); + new AndRequestMatcher(List.of(PathPatternRequestMatcher.withDefaults().matcher("/test"))); } @Test diff --git a/web/src/test/java/org/springframework/security/web/util/matcher/AntPathRequestMatcherTests.java b/web/src/test/java/org/springframework/security/web/util/matcher/AntPathRequestMatcherTests.java deleted file mode 100644 index 09c4d194a7..0000000000 --- a/web/src/test/java/org/springframework/security/web/util/matcher/AntPathRequestMatcherTests.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright 2002-2022 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.web.util.matcher; - -import jakarta.servlet.http.HttpServletRequest; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import org.springframework.http.HttpMethod; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.web.util.UrlPathHelper; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.mockito.BDDMockito.given; -import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher; - -/** - * @author Luke Taylor - * @author Rob Winch - * @author Evgeniy Cheban - */ -@ExtendWith(MockitoExtension.class) -public class AntPathRequestMatcherTests { - - @Mock - private HttpServletRequest request; - - @Test - public void matchesWhenUrlPathHelperThenMatchesOnRequestUri() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/foo/bar", null, true, new UrlPathHelper()); - MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo/bar"); - assertThat(matcher.matches(request)).isTrue(); - } - - @Test - public void singleWildcardMatchesAnyPath() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/**"); - assertThat(matcher.getPattern()).isEqualTo("/**"); - assertThat(matcher.matches(createRequest("/blah"))).isTrue(); - matcher = new AntPathRequestMatcher("**"); - assertThat(matcher.matches(createRequest("/blah"))).isTrue(); - assertThat(matcher.matches(createRequest(""))).isTrue(); - } - - @Test - public void trailingWildcardMatchesCorrectly() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/blah/blAh/**", null, false); - assertThat(matcher.matches(createRequest("/BLAH/blah"))).isTrue(); - assertThat(matcher.matches(createRequest("/blah/bleh"))).isFalse(); - assertThat(matcher.matches(createRequest("/blah/blah/"))).isTrue(); - assertThat(matcher.matches(createRequest("/blah/blah/xxx"))).isTrue(); - assertThat(matcher.matches(createRequest("/blah/blaha"))).isFalse(); - assertThat(matcher.matches(createRequest("/blah/bleh/"))).isFalse(); - MockHttpServletRequest request = createRequest("/blah/"); - request.setPathInfo("blah/bleh"); - assertThat(matcher.matches(request)).isTrue(); - matcher = new AntPathRequestMatcher("/bl?h/blAh/**", null, false); - assertThat(matcher.matches(createRequest("/BLAH/Blah/aaa/"))).isTrue(); - assertThat(matcher.matches(createRequest("/bleh/Blah"))).isTrue(); - matcher = new AntPathRequestMatcher("/blAh/**/blah/**", null, false); - assertThat(matcher.matches(createRequest("/blah/blah"))).isTrue(); - assertThat(matcher.matches(createRequest("/blah/bleh"))).isFalse(); - assertThat(matcher.matches(createRequest("/blah/aaa/blah/bbb"))).isTrue(); - } - - @Test - public void trailingWildcardWithVariableMatchesCorrectly() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/{id}/blAh/**", null, false); - assertThat(matcher.matches(createRequest("/1234/blah"))).isTrue(); - assertThat(matcher.matches(createRequest("/4567/bleh"))).isFalse(); - assertThat(matcher.matches(createRequest("/paskos/blah/"))).isTrue(); - assertThat(matcher.matches(createRequest("/12345/blah/xxx"))).isTrue(); - assertThat(matcher.matches(createRequest("/12345/blaha"))).isFalse(); - assertThat(matcher.matches(createRequest("/paskos/bleh/"))).isFalse(); - } - - @Test - public void nontrailingWildcardWithVariableMatchesCorrectly() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/**/{id}"); - assertThat(matcher.matches(createRequest("/blah/1234"))).isTrue(); - assertThat(matcher.matches(createRequest("/bleh/4567"))).isTrue(); - assertThat(matcher.matches(createRequest("/paskos/blah/"))).isFalse(); - assertThat(matcher.matches(createRequest("/12345/blah/xxx"))).isTrue(); - assertThat(matcher.matches(createRequest("/12345/blaha"))).isTrue(); - assertThat(matcher.matches(createRequest("/paskos/bleh/"))).isFalse(); - } - - @Test - public void requestHasNullMethodMatches() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/something/*", "GET"); - HttpServletRequest request = createRequestWithNullMethod("/something/here"); - assertThat(matcher.matches(request)).isTrue(); - } - - // SEC-2084 - @Test - public void requestHasNullMethodNoMatch() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/something/*", "GET"); - HttpServletRequest request = createRequestWithNullMethod("/nomatch"); - assertThat(matcher.matches(request)).isFalse(); - } - - @Test - public void requestHasNullMethodAndNullMatcherMatches() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/something/*"); - MockHttpServletRequest request = createRequest("/something/here"); - request.setMethod(null); - assertThat(matcher.matches(request)).isTrue(); - } - - @Test - public void requestHasNullMethodAndNullMatcherNoMatch() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/something/*"); - MockHttpServletRequest request = createRequest("/nomatch"); - request.setMethod(null); - assertThat(matcher.matches(request)).isFalse(); - } - - @Test - public void exactMatchOnlyMatchesIdenticalPath() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/login.html"); - assertThat(matcher.matches(createRequest("/login.html"))).isTrue(); - assertThat(matcher.matches(createRequest("/login.html/"))).isFalse(); - assertThat(matcher.matches(createRequest("/login.html/blah"))).isFalse(); - } - - @Test - public void httpMethodSpecificMatchOnlyMatchesRequestsWithCorrectMethod() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/blah", "GET"); - MockHttpServletRequest request = createRequest("/blah"); - request.setMethod("GET"); - assertThat(matcher.matches(request)).isTrue(); - request.setMethod("POST"); - assertThat(matcher.matches(request)).isFalse(); - } - - @Test - public void caseSensitive() { - MockHttpServletRequest request = createRequest("/UPPER"); - assertThat(new AntPathRequestMatcher("/upper", null, true).matches(request)).isFalse(); - assertThat(new AntPathRequestMatcher("/upper", "POST", true).matches(request)).isFalse(); - assertThat(new AntPathRequestMatcher("/upper", "GET", true).matches(request)).isFalse(); - assertThat(new AntPathRequestMatcher("/upper", null, false).matches(request)).isTrue(); - assertThat(new AntPathRequestMatcher("/upper", "POST", false).matches(request)).isTrue(); - } - - @Test - public void spacesInPathSegmentsAreNotIgnored() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/path/*/bar"); - MockHttpServletRequest request = createRequest("/path /foo/bar"); - assertThat(matcher.matches(request)).isFalse(); - matcher = new AntPathRequestMatcher("/path/foo"); - request = createRequest("/path /foo"); - assertThat(matcher.matches(request)).isFalse(); - } - - @Test - public void equalsBehavesCorrectly() { - // Both universal wildcard options should be equal - assertThat(new AntPathRequestMatcher("**")).isEqualTo(new AntPathRequestMatcher("/**")); - assertThat(new AntPathRequestMatcher("/xyz")).isEqualTo(new AntPathRequestMatcher("/xyz")); - assertThat(new AntPathRequestMatcher("/xyz", "POST")).isEqualTo(new AntPathRequestMatcher("/xyz", "POST")); - assertThat(new AntPathRequestMatcher("/xyz", "POST")).isNotEqualTo(new AntPathRequestMatcher("/xyz", "GET")); - assertThat(new AntPathRequestMatcher("/xyz")).isNotEqualTo(new AntPathRequestMatcher("/xxx")); - assertThat(new AntPathRequestMatcher("/xyz").equals(AnyRequestMatcher.INSTANCE)).isFalse(); - assertThat(new AntPathRequestMatcher("/xyz", "GET", false)) - .isNotEqualTo(new AntPathRequestMatcher("/xyz", "GET", true)); - } - - @Test - public void toStringIsOk() { - new AntPathRequestMatcher("/blah").toString(); - new AntPathRequestMatcher("/blah", "GET").toString(); - } - - // SEC-2831 - @Test - public void matchesWithInvalidMethod() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/blah", "GET"); - MockHttpServletRequest request = createRequest("/blah"); - request.setMethod("INVALID"); - assertThat(matcher.matches(request)).isFalse(); - } - - // gh-9285 - @Test - public void matcherWhenMatchAllPatternThenMatchResult() { - AntPathRequestMatcher matcher = new AntPathRequestMatcher("/**"); - MockHttpServletRequest request = createRequest("/blah"); - assertThat(matcher.matcher(request).isMatch()).isTrue(); - } - - @Test - public void staticAntMatcherWhenPatternProvidedThenPattern() { - AntPathRequestMatcher matcher = antMatcher("/path"); - assertThat(matcher.getPattern()).isEqualTo("/path"); - } - - @Test - public void staticAntMatcherWhenMethodProvidedThenMatchAll() { - AntPathRequestMatcher matcher = antMatcher(HttpMethod.GET); - assertThat(ReflectionTestUtils.getField(matcher, "httpMethod")).isEqualTo(HttpMethod.GET); - } - - @Test - public void staticAntMatcherWhenMethodAndPatternProvidedThenMatchAll() { - AntPathRequestMatcher matcher = antMatcher(HttpMethod.POST, "/path"); - assertThat(matcher.getPattern()).isEqualTo("/path"); - assertThat(ReflectionTestUtils.getField(matcher, "httpMethod")).isEqualTo(HttpMethod.POST); - } - - @Test - public void staticAntMatcherWhenMethodNullThenException() { - assertThatIllegalArgumentException().isThrownBy(() -> antMatcher((HttpMethod) null)) - .withMessage("method cannot be null"); - } - - @Test - public void staticAntMatcherWhenPatternNullThenException() { - assertThatIllegalArgumentException().isThrownBy(() -> antMatcher((String) null)) - .withMessage("pattern cannot be empty"); - } - - @Test - public void forMethodWhenMethodThenMatches() { - AntPathRequestMatcher matcher = antMatcher(HttpMethod.POST); - MockHttpServletRequest request = createRequest("/path"); - assertThat(matcher.matches(request)).isTrue(); - request.setServletPath("/another-path/second"); - assertThat(matcher.matches(request)).isTrue(); - request.setMethod("GET"); - assertThat(matcher.matches(request)).isFalse(); - } - - private HttpServletRequest createRequestWithNullMethod(String path) { - given(this.request.getServletPath()).willReturn(path); - return this.request; - } - - private MockHttpServletRequest createRequest(String path) { - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setQueryString("doesntMatter"); - request.setServletPath(path); - request.setMethod("POST"); - return request; - } - -} diff --git a/web/src/test/java/org/springframework/security/web/util/matcher/OrRequestMatcherTests.java b/web/src/test/java/org/springframework/security/web/util/matcher/OrRequestMatcherTests.java index 72dd4162bd..4a1bc7ccb6 100644 --- a/web/src/test/java/org/springframework/security/web/util/matcher/OrRequestMatcherTests.java +++ b/web/src/test/java/org/springframework/security/web/util/matcher/OrRequestMatcherTests.java @@ -27,6 +27,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher.MatchResult; import static org.assertj.core.api.Assertions.assertThat; @@ -60,7 +61,7 @@ public class OrRequestMatcherTests { @Test public void constructorListOfDoesNotThrowNullPointer() { - new OrRequestMatcher(List.of(new AntPathRequestMatcher("/test"))); + new OrRequestMatcher(List.of(PathPatternRequestMatcher.withDefaults().matcher("/test"))); } @Test