From c4d23f2b4971820dfdcf8d1da7bd3c13722ac4bf Mon Sep 17 00:00:00 2001 From: Marcus Da Coregio Date: Tue, 4 Oct 2022 13:29:39 -0300 Subject: [PATCH] Use MvcRequestMatcher by default if Spring MVC is present Closes gh-11899 --- .../http/AuthorizationFilterParser.java | 4 +-- .../http/FilterChainBeanDefinitionParser.java | 4 +-- ...FilterChainMapBeanDefinitionDecorator.java | 4 +-- ...nvocationSecurityMetadataSourceParser.java | 2 +- .../config/http/HttpConfigurationBuilder.java | 2 +- .../HttpSecurityBeanDefinitionParser.java | 4 +-- .../security/config/http/MatcherType.java | 22 +++++++++++-- .../config/FilterChainProxyConfigTests.java | 12 ++++--- ...tadataSourceBeanDefinitionParserTests.java | 18 +++++----- .../config/http/InterceptUrlConfigTests.java | 18 +++++++--- ...erDataValueProcessorOnyIfNotRegistered.xml | 18 ++++++++++ .../http/CsrfConfigTests-CsrfEnabled.xml | 5 +-- ...tUrlConfigTests-CamelCasePathVariables.xml | 5 +-- ...lCasePathVariablesAuthorizationManager.xml | 5 +-- ...Tests-DefaultMatcherNoIntrospectorBean.xml | 33 +++++++++++++++++++ ...lConfigTests-DefaultMatcherServletPath.xml | 5 +-- ...MatcherServletPathAuthorizationManager.xml | 5 +-- .../InterceptUrlConfigTests-PatchMethod.xml | 5 +-- ...gTests-PatchMethodAuthorizationManager.xml | 5 +-- .../InterceptUrlConfigTests-PathVariables.xml | 5 +-- ...ests-PathVariablesAuthorizationManager.xml | 5 +-- .../http/InterceptUrlConfigTests-Sec2256.xml | 5 +-- ...onfigTests-Sec2256AuthorizationManager.xml | 5 +-- ...onfigTests-TypeConversionPathVariables.xml | 5 +-- ...rsionPathVariablesAuthorizationManager.xml | 5 +-- .../MiscHttpConfigTests-AnonymousDisabled.xml | 5 +-- ...MiscHttpConfigTests-AnonymousEndpoints.xml | 5 +-- ...nfigTests-CustomHttpBasicEntryPointRef.xml | 5 +-- ...scHttpConfigTests-NoSecurityForPattern.xml | 5 +-- .../MiscHttpConfigTests-OncePerRequest.xml | 5 +-- ...MiscHttpConfigTests-ProtectedLoginPage.xml | 5 +-- ...ProtectedLoginPageAuthorizationManager.xml | 5 +-- ...pBlockConfigTests-DistinctHttpElements.xml | 5 +-- ...Tests-IdenticallyPatternedHttpElements.xml | 5 +-- .../MultiHttpBlockConfigTests-Sec1937.xml | 6 ++-- ...serTests-AuthenticationManagerResolver.xml | 5 +-- ...tionParserTests-BasicAndResourceServer.xml | 5 +-- ...itionParserTests-FormAndResourceServer.xml | 5 +-- ...verBeanDefinitionParserTests-JwkSetUri.xml | 5 +-- ...rceServerBeanDefinitionParserTests-Jwt.xml | 5 +-- ...nDefinitionParserTests-MultipleIssuers.xml | 5 +-- ...rBeanDefinitionParserTests-OpaqueToken.xml | 5 +-- ...-OpaqueTokenAndAuthenticationConverter.xml | 5 +-- ...olderAndELConfigTests-AccessDeniedPage.xml | 5 +-- ...ELConfigTests-AccessDeniedPageWithSpEL.xml | 5 +-- ...ELConfigTests-InterceptUrlAndFormLogin.xml | 5 +-- ...Tests-InterceptUrlAndFormLoginWithSpEL.xml | 5 +-- ...laceHolderAndELConfigTests-PortMapping.xml | 5 +-- ...HolderAndELConfigTests-RequiresChannel.xml | 5 +-- ...olderAndELConfigTests-UnsecuredPattern.xml | 5 +-- .../RememberMeConfigTests-DefaultConfig.xml | 5 +-- ...berMeConfigTests-NegativeTokenValidity.xml | 5 +-- .../http/RememberMeConfigTests-Sec1827.xml | 5 +-- .../http/RememberMeConfigTests-Sec2165.xml | 5 +-- .../http/RememberMeConfigTests-Sec742.xml | 5 +-- .../RememberMeConfigTests-SecureCookie.xml | 5 +-- .../RememberMeConfigTests-TokenValidity.xml | 5 +-- ...Tests-WithAuthenticationSuccessHandler.xml | 5 +-- .../RememberMeConfigTests-WithDataSource.xml | 5 +-- ...mberMeConfigTests-WithRememberMeCookie.xml | 5 +-- ...rMeConfigTests-WithRememberMeParameter.xml | 5 +-- ...ests-WithSecurityContextHolderStrategy.xml | 5 +-- .../RememberMeConfigTests-WithServicesRef.xml | 5 +-- ...emberMeConfigTests-WithTokenRepository.xml | 5 +-- ...erMeConfigTests-WithUserDetailsService.xml | 6 ++-- ...olderAwareRequestConfigTests-MultiHttp.xml | 4 ++- ...entConfigTests-CreateSessionIfRequired.xml | 5 +-- ...nagementConfigTests-CreateSessionNever.xml | 5 +-- ...mentConfigTests-CreateSessionStateless.xml | 5 +-- ...tConfigTests-NoSessionManagementFilter.xml | 5 +-- .../SessionManagementConfigTests-Sec1208.xml | 5 +-- .../SessionManagementConfigTests-Sec2137.xml | 5 +-- ...Tests-SessionAuthenticationStrategyRef.xml | 5 +-- ...essionFixationProtectionMigrateSession.xml | 5 +-- ...figTests-SessionFixationProtectionNone.xml | 5 +-- ...ionProtectionNoneWithInvalidSessionUrl.xml | 5 +-- .../http/handlermappingintrospector.xml | 29 ++++++++++++++++ .../security/util/filtertest-valid.xml | 32 +++++++++--------- .../servlet/appendix/namespace/http.adoc | 4 +-- docs/modules/ROOT/pages/whats-new.adoc | 2 ++ .../spring/http-security-concurrency.xml | 18 ++++++++++ .../util/matcher/MvcRequestMatcher.java | 21 +++++++++++- 82 files changed, 391 insertions(+), 177 deletions(-) create mode 100644 config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-DefaultMatcherNoIntrospectorBean.xml create mode 100644 config/src/test/resources/org/springframework/security/config/http/handlermappingintrospector.xml 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 f02a0686c0..713e325393 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * 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. @@ -108,7 +108,7 @@ class AuthorizationFilterParser implements BeanDefinitionParser { if (expressionHandlerRef == null) { expressionHandlerRef = registerDefaultExpressionHandler(parserContext); } - MatcherType matcherType = MatcherType.fromElement(element); + MatcherType matcherType = MatcherType.fromElementOrMvc(element); ManagedMap matcherToExpression = new ManagedMap<>(); List interceptMessages = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL); for (Element interceptMessage : interceptMessages) { diff --git a/config/src/main/java/org/springframework/security/config/http/FilterChainBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/FilterChainBeanDefinitionParser.java index c362bcc0a1..bf64c410b8 100644 --- a/config/src/main/java/org/springframework/security/config/http/FilterChainBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/http/FilterChainBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * 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. @@ -39,7 +39,7 @@ public class FilterChainBeanDefinitionParser implements BeanDefinitionParser { @Override public BeanDefinition parse(Element elt, ParserContext pc) { - MatcherType matcherType = MatcherType.fromElement(elt); + MatcherType matcherType = MatcherType.fromElementOrMvc(elt); String path = elt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_PATH_PATTERN); String requestMatcher = elt.getAttribute(ATT_REQUEST_MATCHER_REF); String filters = elt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_FILTERS); diff --git a/config/src/main/java/org/springframework/security/config/http/FilterChainMapBeanDefinitionDecorator.java b/config/src/main/java/org/springframework/security/config/http/FilterChainMapBeanDefinitionDecorator.java index 842ac8799f..781f81e329 100644 --- a/config/src/main/java/org/springframework/security/config/http/FilterChainMapBeanDefinitionDecorator.java +++ b/config/src/main/java/org/springframework/security/config/http/FilterChainMapBeanDefinitionDecorator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * 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. @@ -47,7 +47,7 @@ public class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDeco BeanDefinition filterChainProxy = holder.getBeanDefinition(); ManagedList securityFilterChains = new ManagedList<>(); Element elt = (Element) node; - MatcherType matcherType = MatcherType.fromElement(elt); + MatcherType matcherType = MatcherType.fromElementOrMvc(elt); List filterChainElts = DomUtils.getChildElementsByTagName(elt, Elements.FILTER_CHAIN); for (Element chain : filterChainElts) { String path = chain.getAttribute(HttpSecurityBeanDefinitionParser.ATT_PATH_PATTERN); 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 d6a06696a9..5d3dcd4a07 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 @@ -93,7 +93,7 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit static RootBeanDefinition createSecurityMetadataSource(List interceptUrls, boolean addAllAuth, Element httpElt, ParserContext pc) { - MatcherType matcherType = MatcherType.fromElement(httpElt); + MatcherType matcherType = MatcherType.fromElementOrMvc(httpElt); boolean useExpressions = isUseExpressions(httpElt); ManagedMap requestToAttributesMap = parseInterceptUrlsForFilterInvocationRequestMap( matcherType, interceptUrls, useExpressions, addAllAuth, pc); 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 db27d23cc1..8dd094f9bd 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 @@ -217,7 +217,7 @@ class HttpConfigurationBuilder { this.pc = pc; this.portMapper = portMapper; this.portResolver = portResolver; - this.matcherType = MatcherType.fromElement(element); + this.matcherType = MatcherType.fromElementOrMvc(element); this.interceptUrls = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL); validateInterceptUrls(pc); String createSession = element.getAttribute(ATT_CREATE_SESSION); diff --git a/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java index 1bfe7811f2..1dd528fbff 100644 --- a/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * 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. @@ -196,7 +196,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { } else if (StringUtils.hasText(filterChainPattern)) { - filterChainMatcher = MatcherType.fromElement(element).createMatcher(pc, filterChainPattern, null); + filterChainMatcher = MatcherType.fromElementOrMvc(element).createMatcher(pc, filterChainPattern, null); } else { filterChainMatcher = new RootBeanDefinition(AnyRequestMatcher.class); 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 9d65f9ea63..ac417a239d 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * 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. @@ -22,11 +22,13 @@ 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.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; /** @@ -40,12 +42,18 @@ public enum MatcherType { ant(AntPathRequestMatcher.class), regex(RegexRequestMatcher.class), ciRegex(RegexRequestMatcher.class), mvc( MvcRequestMatcher.class); - 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 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; } @@ -64,7 +72,7 @@ public enum MatcherType { } matcherBldr.addConstructorArgValue(path); if (this == mvc) { - matcherBldr.addPropertyValue("method", method); + matcherBldr.addPropertyValue("method", (StringUtils.hasText(method) ? HttpMethod.valueOf(method) : null)); matcherBldr.addPropertyValue("servletPath", servletPath); } else { @@ -84,4 +92,12 @@ public enum MatcherType { return ant; } + 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/test/java/org/springframework/security/config/FilterChainProxyConfigTests.java b/config/src/test/java/org/springframework/security/config/FilterChainProxyConfigTests.java index 53d41edfc6..a980880419 100644 --- a/config/src/test/java/org/springframework/security/config/FilterChainProxyConfigTests.java +++ b/config/src/test/java/org/springframework/security/config/FilterChainProxyConfigTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited + * 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. @@ -36,8 +36,9 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic import org.springframework.security.web.context.SecurityContextPersistenceFilter; import org.springframework.security.web.firewall.DefaultHttpFirewall; import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AnyRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -113,12 +114,13 @@ public class FilterChainProxyConfigTests { List chains = fcp.getFilterChains(); assertThat(getPattern(chains.get(0))).isEqualTo("/login*"); assertThat(getPattern(chains.get(1))).isEqualTo("/logout"); - assertThat(((DefaultSecurityFilterChain) chains.get(2)).getRequestMatcher() instanceof AnyRequestMatcher) - .isTrue(); + assertThat(((DefaultSecurityFilterChain) chains.get(2)).getRequestMatcher()) + .isInstanceOf(AnyRequestMatcher.class); } private String getPattern(SecurityFilterChain chain) { - return ((AntPathRequestMatcher) ((DefaultSecurityFilterChain) chain).getRequestMatcher()).getPattern(); + RequestMatcher requestMatcher = ((DefaultSecurityFilterChain) chain).getRequestMatcher(); + return (String) ReflectionTestUtils.getField(requestMatcher, "pattern"); } private void checkPathAndFilterOrder(FilterChainProxy filterChainProxy) { 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 bdf66edd91..0762060fb5 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * 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. @@ -92,10 +92,12 @@ 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")); @@ -105,7 +107,8 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests { @Test public void parsingWithinFilterSecurityInterceptorIsSuccessful() { // @formatter:off - setContext("" + setContext("" + + "" + "" + " " + " " @@ -130,9 +133,8 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests { private FilterInvocation createFilterInvocation(String path, String method) { MockHttpServletRequest request = new MockHttpServletRequest("GET", ""); - request.setRequestURI(null); + request.setRequestURI(path); request.setMethod(method); - request.setServletPath(path); return new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain()); } 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 385358c210..34c85563e7 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * 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. @@ -24,6 +24,7 @@ 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; @@ -39,6 +40,7 @@ import org.springframework.web.context.ConfigurableWebApplicationContext; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatNoException; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -361,14 +363,20 @@ public class InterceptUrlConfigTests { } @Test - public void configureWhenUsingDefaultMatcherAndServletPathThenThrowsException() { - assertThatExceptionOfType(BeanDefinitionParsingException.class) + public void configureWhenUsingDefaultMatcherAndServletPathThenNoException() { + assertThatNoException() .isThrownBy(() -> this.spring.configLocations(this.xml("DefaultMatcherServletPath")).autowire()); } @Test - public void configureWhenUsingDefaultMatcherAndServletPathAndAuthorizationManagerThenThrowsException() { - assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy(() -> this.spring + public void configureWhenUsingDefaultMatcherAndNoIntrospectorBeanThenException() { + assertThatExceptionOfType(BeanCreationException.class) + .isThrownBy(() -> this.spring.configLocations(this.xml("DefaultMatcherNoIntrospectorBean")).autowire()); + } + + @Test + public void configureWhenUsingDefaultMatcherAndServletPathAndAuthorizationManagerThenNoException() { + assertThatNoException().isThrownBy(() -> this.spring .configLocations(this.xml("DefaultMatcherServletPathAuthorizationManager")).autowire()); } 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 e968b744a0..38a8cbfc8c 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 @@ -1,3 +1,19 @@ + + + + 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 0f36bbbbc1..47dab56e2e 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 @@ -1,12 +1,12 @@ + + + + + + + + + + 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 83f6be4f00..9044cf02e1 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 @@ -1,12 +1,12 @@ + + + + + + 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 5885916482..d12165a7b4 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 @@ -1,22 +1,20 @@ + ~ 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. + --> + + diff --git a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc index ee03f7dfb6..08a725eeef 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc @@ -117,7 +117,7 @@ Options are currently `mvc`, `ant`, `regex` and `ciRegex`, for Spring MVC, ant, 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. See the Javadoc for these classes for more details on exactly how the matching is performed. -Ant paths are the default strategy. +MVC is the default strategy if Spring MVC is present in the classpath, if not, Ant paths are used. [[nsa-http-request-matcher-ref]] @@ -1653,7 +1653,7 @@ If an identical pattern is specified with and without a method, the method-speci [[nsa-intercept-url-pattern]] * **pattern** The pattern which defines the URL path. -The content will depend on the `request-matcher` attribute from the containing http element, so will default to ant path syntax. +The content will depend on the `request-matcher` attribute from the containing http element, so will default to MVC matcher if Spring MVC is in the classpath. [[nsa-intercept-url-request-matcher-ref]] diff --git a/docs/modules/ROOT/pages/whats-new.adoc b/docs/modules/ROOT/pages/whats-new.adoc index 81eed226f5..aabd3bee9c 100644 --- a/docs/modules/ROOT/pages/whats-new.adoc +++ b/docs/modules/ROOT/pages/whats-new.adoc @@ -20,3 +20,5 @@ Reorganize imports * https://github.com/spring-projects/spring-security/issues/10347[gh-10347] - Remove `UsernamePasswordAuthenticationToken` check in `BasicAuthenticationFilter` * https://github.com/spring-projects/spring-security/pull/11923[gh-11923] - Remove `WebSecurityConfigurerAdapter`. Instead, create a https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter[SecurityFilterChain bean]. +* https://github.com/spring-projects/spring-security/issues/11899[gh-11899] - Use `MvcRequestMatcher` by default if Spring MVC is present. +You can configure a different `RequestMatcher` by using the https://docs.spring.io/spring-security/reference/servlet/appendix/namespace/http.html#nsa-http-attributes[request-matcher attribute from ]. 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 853b033ce3..310f1bedfe 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 @@ -1,5 +1,21 @@ + + + + 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 index 0bdf10d09b..b0f35a63d9 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * 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. @@ -17,6 +17,7 @@ package org.springframework.security.web.servlet.util.matcher; import java.util.Map; +import java.util.Objects; import jakarta.servlet.http.HttpServletRequest; @@ -129,6 +130,24 @@ public class MvcRequestMatcher implements RequestMatcher, RequestVariablesExtrac 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();