Use PathPatternRequestMatcher in config

This commit changes the config module to use
PathPatternRequestMatcher in favor of
MvcRequestMatcher and AntPathRequestMatcher.

This allows removing several HandlerMappingIntrospector
support classes as well which were in place to
support MvcRequestMatcher.

Issue gh-16886
Issue gh-16887
This commit is contained in:
Josh Cummings 2025-07-02 17:49:50 -06:00
parent f709a9efef
commit 3e53cc2c4a
No known key found for this signature in database
GPG Key ID: 869B37A20E876129
137 changed files with 495 additions and 1570 deletions

View File

@ -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<C> {
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<C> {
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<MvcRequestMatcher> createMvcMatchers(HttpMethod method, String... mvcPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure mvcMatchers after anyRequest");
ResolvableType type = ResolvableType.forClassWithGenerics(ObjectPostProcessor.class, Object.class);
ObjectProvider<ObjectPostProcessor<Object>> postProcessors = this.context.getBeanProvider(type);
ObjectPostProcessor<Object> 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<MvcRequestMatcher> 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<C> {
/**
* <p>
* 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.
* </p>
* <p>
* If a specific {@link RequestMatcher} must be specified, use
@ -197,8 +128,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* </p>
* @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,11 @@ public abstract class AbstractRequestMatcherRegistry<C> {
+ "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.getBean(PathPatternRequestMatcher.Builder.class);
List<RequestMatcher> 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 +157,16 @@ public abstract class AbstractRequestMatcherRegistry<C> {
return false;
}
private RequestMatcher resolve(AntPathRequestMatcher ant, MvcRequestMatcher mvc, ServletContext servletContext) {
ServletRegistrationsSupport registrations = new ServletRegistrationsSupport(servletContext);
Collection<RegistrationMapping> mappings = registrations.mappings();
if (mappings.isEmpty()) {
return new DispatcherServletDelegatingRequestMatcher(ant, mvc, new MockMvcRequestMatcher());
}
Collection<RegistrationMapping> 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<? extends ServletRegistration> 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<String, Collection<String>> mappings = new LinkedHashMap<>();
for (ServletRegistration registration : registrations) {
mappings.put(registration.getClassName(), registration.getMappings());
}
return String.format(template, mappings);
}
/**
* <p>
* 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.
* </p>
* <p>
* If a specific {@link RequestMatcher} must be specified, use
* {@link #requestMatchers(RequestMatcher...)} instead
* </p>
* @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 +176,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
/**
* <p>
* 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}
* </p>
* <p>
* If a specific {@link RequestMatcher} must be specified, use
@ -339,182 +200,4 @@ public abstract class AbstractRequestMatcherRegistry<C> {
*/
protected abstract C chainRequestMatchers(List<RequestMatcher> 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<RequestMatcher> 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<RequestMatcher> 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<RequestMatcher> regexMatchers(HttpMethod httpMethod, String... regexPatterns) {
String method = (httpMethod != null) ? httpMethod.toString() : null;
List<RequestMatcher> 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<RequestMatcher> regexMatchers(String... regexPatterns) {
return regexMatchers(null, regexPatterns);
}
}
static class DeferredRequestMatcher implements RequestMatcher {
final Function<ServletContext, RequestMatcher> requestMatcherFactory;
final AtomicReference<String> description = new AtomicReference<>();
final Map<ServletContext, RequestMatcher> requestMatchers = new ConcurrentHashMap<>();
DeferredRequestMatcher(Function<ServletContext, RequestMatcher> 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 + "]";
}
}
}

View File

@ -1,59 +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.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;
/**
* This utility exists only to facilitate applications opting into using path patterns in
* the HttpSecurity DSL. It is for internal use only.
*
* @deprecated
*/
@Deprecated(forRemoval = true)
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;
}
public static RequestMatcher matcher(String path) {
return matcher(null, path);
}
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);
}
private RequestMatcherFactory() {
}
}

View File

@ -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 &lt;http&gt; element in the
@ -153,12 +148,6 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
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<OrderedFilter> filters = new ArrayList<>();
@ -169,10 +158,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
private AuthenticationManager authenticationManager;
static {
mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, HttpSecurity.class.getClassLoader());
}
/**
* Creates a new instance
* @param objectPostProcessor the {@link ObjectPostProcessor} that should be used
@ -303,9 +288,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
/**
* Adds a {@link CorsFilter} to be used. 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. You can enable CORS
* using:
* defined, then that {@link CorsConfiguration} is used. You can enable CORS using:
*
* <pre>
* &#064;Configuration
@ -2174,7 +2157,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* {@link #securityMatchers()}
* </p>
* @param requestMatcher the {@link RequestMatcher} to use, for example,
* {@code PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/admin/**")}
* {@code PathPatternRequestMatcher.pathPattern(HttpMethod.GET, "/admin/**")}
* @return the {@link HttpSecurity} for further customizations
* @see #securityMatcher(String...)
*/
@ -2185,10 +2168,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
/**
* Allows configuring the {@link HttpSecurity} to only be invoked when matching the
* provided pattern. This method creates a {@link MvcRequestMatcher} if Spring MVC is
* in the classpath or creates an {@link AntPathRequestMatcher} if not. If more
* advanced configuration is necessary, consider using
* {@link #securityMatchers(Customizer)} or {@link #securityMatcher(RequestMatcher)}.
* provided set of {@code patterns}. See
* {@link org.springframework.web.util.pattern.PathPattern} for matching rules
*
* <p>
* Invoking {@link #securityMatcher(String...)} will override previous invocations of
@ -2198,19 +2179,14 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* </p>
* @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<RequestMatcher> matchers = new ArrayList<>();
PathPatternRequestMatcher.Builder builder = getContext().getBean(PathPatternRequestMatcher.Builder.class);
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;
@ -2241,26 +2217,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
return HttpSecurity.this;
}
private RequestMatcher createAntMatcher(String pattern) {
return new AntPathRequestMatcher(pattern);
}
private RequestMatcher createMvcMatcher(String mvcPattern) {
ResolvableType type = ResolvableType.forClassWithGenerics(ObjectPostProcessor.class, Object.class);
ObjectProvider<ObjectPostProcessor<Object>> postProcessors = getContext().getBeanProvider(type);
ObjectPostProcessor<Object> 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}.

View File

@ -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;
@ -422,7 +423,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
this.filterChainDecoratorPostProcessor = postProcessor.getIfUnique(ObjectPostProcessor::identity);
Class<HttpServletRequestTransformer> requestTransformerClass = HttpServletRequestTransformer.class;
this.privilegeEvaluatorRequestTransformer = applicationContext.getBeanProvider(requestTransformerClass)
.getIfUnique();
.getIfUnique(PathPatternRequestTransformer::new);
}
@Override

View File

@ -35,7 +35,6 @@ import org.springframework.security.config.annotation.authentication.configurati
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.JdbcUserDetailsManagerConfigurer;
import org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer;
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.DefaultLoginPageConfigurer;
@ -105,7 +104,6 @@ class HttpSecurityConfiguration {
@Bean(HTTPSECURITY_BEAN_NAME)
@Scope("prototype")
HttpSecurity httpSecurity() throws Exception {
RequestMatcherFactory.setApplicationContext(this.context);
LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context);
AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(
this.objectPostProcessor, passwordEncoder);

View File

@ -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<BeanMetadataElement> 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<Filter> {
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

View File

@ -42,6 +42,7 @@ import org.springframework.beans.factory.support.ManagedList;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Fallback;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.OrderComparator;
import org.springframework.core.Ordered;
@ -57,6 +58,7 @@ import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.crypto.RsaKeyConversionServicePostProcessor;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.context.DelegatingApplicationListener;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.web.FilterChainProxy;
@ -69,7 +71,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
@ -143,6 +144,12 @@ public class WebSecurityConfiguration implements ImportAware {
return this.webSecurity.getPrivilegeEvaluator();
}
@Bean
@Fallback
public PathPatternRequestMatcherBuilderFactoryBean pathPatternRequestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
/**
* Sets the {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>}
* instances used to create the web configuration.
@ -209,12 +216,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

View File

@ -25,6 +25,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
/**
* Adds a convenient base class for {@link SecurityConfigurer} instances that operate on
@ -38,6 +39,8 @@ public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T,
private SecurityContextHolderStrategy securityContextHolderStrategy;
private PathPatternRequestMatcher.Builder requestMatcherBuilder;
/**
* Disables the {@link AbstractHttpConfigurer} by removing it. After doing so a fresh
* version of the configuration can be applied.
@ -65,4 +68,13 @@ public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T,
return this.securityContextHolderStrategy;
}
protected PathPatternRequestMatcher.Builder getRequestMatcherBuilder() {
if (this.requestMatcherBuilder != null) {
return this.requestMatcherBuilder;
}
ApplicationContext context = getBuilder().getSharedObject(ApplicationContext.class);
this.requestMatcherBuilder = context.getBean(PathPatternRequestMatcher.Builder.class);
return this.requestMatcherBuilder;
}
}

View File

@ -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 <H> the builder to return.
* @author Rob Winch
@ -45,16 +41,8 @@ public class CorsConfigurer<H extends HttpSecurityBuilder<H>> 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,11 +79,8 @@ public class CorsConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHt
CorsConfigurationSource.class);
return new CorsFilter(configurationSource);
}
if (mvcPresent) {
return MvcCorsFilter.getMvcCorsFilter(context);
}
return null;
}
static class MvcCorsFilter {

View File

@ -19,7 +19,6 @@ package org.springframework.security.config.annotation.web.configurers;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.AuthenticationEntryPoint;
@ -236,7 +235,7 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
@Override
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
return RequestMatcherFactory.matcher(HttpMethod.POST, loginProcessingUrl);
return getRequestMatcherBuilder().matcher(HttpMethod.POST, loginProcessingUrl);
}
/**

View File

@ -26,7 +26,6 @@ import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
@ -146,7 +145,7 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
* (i.e. log out) to protect against
* <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF
* attacks</a>. If you really want to use an HTTP GET, you can use
* <code>logoutRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GEt, logoutUrl));</code>
* <code>logoutRequestMatcher(PathPatternRequestMatcher.pathPattern(HttpMethod.GEt, logoutUrl));</code>
* </p>
* @param logoutUrl the URL that will invoke logout.
* @return the {@link LogoutConfigurer} for further customization
@ -370,7 +369,7 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
}
private RequestMatcher createLogoutRequestMatcher(String httpMethod) {
return RequestMatcherFactory.matcher(HttpMethod.valueOf(httpMethod), this.logoutUrl);
return getRequestMatcherBuilder().matcher(HttpMethod.valueOf(httpMethod), this.logoutUrl);
}
}

View File

@ -17,7 +17,6 @@
package org.springframework.security.config.annotation.web.configurers;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
import org.springframework.security.web.RequestMatcherRedirectFilter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.Assert;
@ -55,7 +54,7 @@ public final class PasswordManagementConfigurer<B extends HttpSecurityBuilder<B>
@Override
public void configure(B http) throws Exception {
RequestMatcherRedirectFilter changePasswordFilter = new RequestMatcherRedirectFilter(
RequestMatcherFactory.matcher(WELL_KNOWN_CHANGE_PASSWORD_PATTERN), this.changePasswordPage);
getRequestMatcherBuilder().matcher(WELL_KNOWN_CHANGE_PASSWORD_PATTERN), this.changePasswordPage);
http.addFilterBefore(postProcess(changePasswordFilter), UsernamePasswordAuthenticationFilter.class);
}

View File

@ -24,14 +24,12 @@ import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
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;
@ -151,7 +149,7 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>>
boolean isCsrfEnabled = http.getConfigurer(CsrfConfigurer.class) != null;
List<RequestMatcher> matchers = new ArrayList<>();
if (isCsrfEnabled) {
RequestMatcher getRequests = RequestMatcherFactory.matcher(HttpMethod.GET, "/**");
RequestMatcher getRequests = getRequestMatcherBuilder().matcher(HttpMethod.GET, "/**");
matchers.add(0, getRequests);
}
matchers.add(notFavIcon);
@ -174,12 +172,7 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>>
}
private RequestMatcher getFaviconRequestMatcher() {
if (RequestMatcherFactory.usesPathPatterns()) {
return RequestMatcherFactory.matcher("/favicon.*");
}
else {
return new AntPathRequestMatcher("/**/favicon.*");
}
return getRequestMatcherBuilder().matcher("/favicon.*");
}
}

View File

@ -31,7 +31,6 @@ import org.springframework.security.authentication.ott.OneTimeTokenAuthenticatio
import org.springframework.security.authentication.ott.OneTimeTokenService;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
@ -122,12 +121,15 @@ public final class OneTimeTokenLoginConfigurer<H extends HttpSecurityBuilder<H>>
private GenerateOneTimeTokenRequestResolver requestResolver;
public OneTimeTokenLoginConfigurer(ApplicationContext context) {
super(new OneTimeTokenAuthenticationFilter(), OneTimeTokenAuthenticationFilter.DEFAULT_LOGIN_PROCESSING_URL);
super(new OneTimeTokenAuthenticationFilter(), null);
this.context = context;
}
@Override
public void init(H http) throws Exception {
if (getLoginProcessingUrl() == null) {
loginProcessingUrl(OneTimeTokenAuthenticationFilter.DEFAULT_LOGIN_PROCESSING_URL);
}
super.init(http);
AuthenticationProvider authenticationProvider = getAuthenticationProvider();
http.authenticationProvider(postProcess(authenticationProvider));
@ -162,7 +164,7 @@ public final class OneTimeTokenLoginConfigurer<H extends HttpSecurityBuilder<H>>
private void configureOttGenerateFilter(H http) {
GenerateOneTimeTokenFilter generateFilter = new GenerateOneTimeTokenFilter(getOneTimeTokenService(),
getOneTimeTokenGenerationSuccessHandler());
generateFilter.setRequestMatcher(RequestMatcherFactory.matcher(HttpMethod.POST, this.tokenGeneratingUrl));
generateFilter.setRequestMatcher(getRequestMatcherBuilder().matcher(HttpMethod.POST, this.tokenGeneratingUrl));
generateFilter.setRequestResolver(getGenerateRequestResolver());
http.addFilter(postProcess(generateFilter));
http.addFilter(DefaultResourcesFilter.css());
@ -189,7 +191,7 @@ public final class OneTimeTokenLoginConfigurer<H extends HttpSecurityBuilder<H>>
}
DefaultOneTimeTokenSubmitPageGeneratingFilter submitPage = new DefaultOneTimeTokenSubmitPageGeneratingFilter();
submitPage.setResolveHiddenInputs(this::hiddenInputs);
submitPage.setRequestMatcher(RequestMatcherFactory.matcher(HttpMethod.GET, this.defaultSubmitPageUrl));
submitPage.setRequestMatcher(getRequestMatcherBuilder().matcher(HttpMethod.GET, this.defaultSubmitPageUrl));
submitPage.setLoginProcessingUrl(this.getLoginProcessingUrl());
http.addFilter(postProcess(submitPage));
}
@ -206,7 +208,7 @@ public final class OneTimeTokenLoginConfigurer<H extends HttpSecurityBuilder<H>>
@Override
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
return RequestMatcherFactory.matcher(HttpMethod.POST, loginProcessingUrl);
return getRequestMatcherBuilder().matcher(HttpMethod.POST, loginProcessingUrl);
}
/**

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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<HandlerMappingIntrospector>, ApplicationContextAware {
class CorsConfigurationSourceFactoryBean implements FactoryBean<CorsConfigurationSource>, 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 <cors>. 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

View File

@ -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<Filter> filters = null;
try {
filters = fcp.getFilters(loginPage);
@ -237,7 +242,7 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
}
}
private boolean checkLoginPageIsPublic(List<Filter> filters, FilterInvocation loginRequest) {
private boolean checkLoginPageIsPublic(List<Filter> 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<HttpServletRequest> 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<Boolean> deriveAnonymousCheck(List<Filter> filters, FilterInvocation loginRequest,
private Supplier<Boolean> deriveAnonymousCheck(List<Filter> 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<HttpServletRequest> authorizationManager = authorizationFilter
.getAuthorizationManager();
AuthorizationResult result = authorizationManager.authorize(() -> token, loginRequest.getHttpRequest());
AuthorizationResult result = authorizationManager.authorize(() -> token, loginRequest);
return result != null && result.isGranted();
};
}

View File

@ -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);

View File

@ -45,12 +45,12 @@ import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.config.Elements;
import org.springframework.security.config.http.GrantedAuthorityDefaultsParserUtils.AbstractGrantedAuthorityDefaultsBeanFactory;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.context.SecurityContextHolder;
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 +88,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 +99,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";
@ -165,6 +159,8 @@ class HttpConfigurationBuilder {
private static final String DEF_JAAS_API_PROVISION = "false";
private static final String REQUEST_MATCHER_BUILDER_BEAN_NAME = "HttpConfigurationBuilder-pathPatternRequestMatcherBuilder";
private final Element httpElt;
private final ParserContext pc;
@ -244,6 +240,13 @@ class HttpConfigurationBuilder {
String createSession = element.getAttribute(ATT_CREATE_SESSION);
this.sessionPolicy = !StringUtils.hasText(createSession) ? SessionCreationPolicy.IF_REQUIRED
: createPolicy(createSession);
if (!this.pc.getRegistry().containsBeanDefinition(REQUEST_MATCHER_BUILDER_BEAN_NAME)) {
BeanDefinitionBuilder pathPatternRequestMatcherBuilder = BeanDefinitionBuilder
.rootBeanDefinition(PathPatternRequestMatcherBuilderFactoryBean.class);
pathPatternRequestMatcherBuilder.setFallback(true);
BeanDefinition bean = pathPatternRequestMatcherBuilder.getBeanDefinition();
this.pc.registerBeanComponent(new BeanComponentDefinition(bean, REQUEST_MATCHER_BUILDER_BEAN_NAME));
}
createSecurityContextHolderStrategy();
createForceEagerSessionCreationFilter();
createDisableEncodeUrlFilter();
@ -793,10 +796,8 @@ class HttpConfigurationBuilder {
BeanDefinitionBuilder wipeBldr = BeanDefinitionBuilder
.rootBeanDefinition(AuthorizationManagerWebInvocationPrivilegeEvaluator.class)
.addConstructorArgReference(authorizationFilterParser.getAuthorizationManagerRef());
if (mvcPresent) {
wipeBldr.addPropertyValue("requestTransformer",
new RootBeanDefinition(HandlerMappingIntrospectorRequestTransformerFactoryBean.class));
}
new RootBeanDefinition(PathPatternRequestTransformerFactoryBean.class));
BeanDefinition wipe = wipeBldr.getBeanDefinition();
this.pc.registerBeanComponent(
new BeanComponentDefinition(wipe, this.pc.getReaderContext().generateBeanName(wipe)));
@ -966,7 +967,7 @@ class HttpConfigurationBuilder {
return BeanDefinitionBuilder.rootBeanDefinition(ObservationRegistryFactory.class).getBeanDefinition();
}
static class HandlerMappingIntrospectorRequestTransformerFactoryBean
static class PathPatternRequestTransformerFactoryBean
implements FactoryBean<AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer>,
ApplicationContextAware {
@ -982,10 +983,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

View File

@ -22,13 +22,12 @@ 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.servlet.util.matcher.PathPatternRequestMatcher;
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;
/**
@ -39,21 +38,13 @@ 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;
ant(AntPathRequestMatcher.class), path(PathPatternRequestMatcher.class), regex(RegexRequestMatcher.class),
ciRegex(RegexRequestMatcher.class), mvc(MvcRequestMatcher.class);
private static final String ATT_MATCHER_TYPE = "request-matcher";
final Class<? extends RequestMatcher> type;
static {
mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, MatcherType.class.getClassLoader());
}
MatcherType(Class<? extends RequestMatcher> type) {
this.type = type;
}
@ -66,18 +57,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));
}
BeanDefinitionBuilder matcherBldr;
if (this == MatcherType.path) {
matcherBldr = BeanDefinitionBuilder.rootBeanDefinition(PathPatternRequestMatcherFactoryBean.class);
matcherBldr.addConstructorArgValue(path);
if (this == mvc) {
matcherBldr.addPropertyValue("method", (StringUtils.hasText(method) ? HttpMethod.valueOf(method) : null));
matcherBldr.addPropertyValue("servletPath", servletPath);
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 +79,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);
}

View File

@ -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<PathPatternRequestMatcher>, 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);
}
}
}

View File

@ -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,11 +44,8 @@ public final class RequestMatcherFactoryBean implements FactoryBean<RequestMatch
@Override
public RequestMatcher getObject() throws Exception {
if (this.builder != null) {
return this.builder.matcher(this.method, this.path);
}
return new AntPathRequestMatcher(this.path, (this.method != null) ? this.method.name() : null);
}
@Override
public Class<?> getObjectType() {
@ -58,7 +54,7 @@ public final class RequestMatcherFactoryBean implements FactoryBean<RequestMatch
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.builder = context.getBeanProvider(PathPatternRequestMatcher.Builder.class).getIfUnique();
this.builder = context.getBean(PathPatternRequestMatcher.Builder.class);
}
}

View File

@ -58,6 +58,6 @@ abstract class AbstractRequestMatcherDsl {
protected abstract class AuthorizationManagerRule(open val rule: AuthorizationManager<RequestAuthorizationContext>)
protected enum class PatternType {
ANT, MVC
ANT, MVC, PATH;
}
}

View File

@ -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)
}
}
}

View File

@ -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<AuthorizationRule>()
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)
}
}
}

View File

@ -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)
@ -192,7 +191,7 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
* @Bean
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
* http {
* securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/private/&ast;&ast;"))
* securityMatcher(pathPattern("/private/&ast;&ast;"))
* formLogin {
* loginPage = "/log-in"
* }

View File

@ -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<AuthorizationRule>()
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<ChannelProcessor>? = 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)
}
}
}

View File

@ -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. If Spring MVC is present, then it will attempt to look up its `CorsConfigurationSource`.
element cors { cors-options.attlist }
cors-options.attlist &=
ref?

View File

@ -3317,8 +3317,8 @@
</xs:attributeGroup>
<xs:element name="cors">
<xs:annotation>
<xs:documentation>Element for configuration of CorsFilter. If no CorsFilter or CorsConfigurationSource is
specified a HandlerMappingIntrospector is used as the CorsConfigurationSource
<xs:documentation>Element for configuration of CorsFilter. A CorsConfigurationSource must be specified. If
Spring MVC is present, then it will attempt to look up its `CorsConfigurationSource`.
</xs:documentation>
</xs:annotation>
<xs:complexType>

View File

@ -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;
@ -121,7 +122,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) {

View File

@ -32,9 +32,10 @@ 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.util.Assert;
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
/**
* @author Rob Winch
*
@ -52,7 +53,7 @@ public class SecurityConfig {
// @formatter:off
http
.authorizeRequests((requests) -> requests
.requestMatchers(new AntPathRequestMatcher("/*")).permitAll())
.requestMatchers(pathPattern("/*")).permitAll())
.authenticationProvider(authenticationProvider());
// @formatter:on
return http.build();

View File

@ -25,13 +25,12 @@ 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.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;
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
/**
* Tests for {@link AbstractRequestMatcherRegistry}.
@ -88,7 +87,7 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests {
http
.authorizeRequests((requests) -> requests
.anyRequest().authenticated()
.requestMatchers(new AntPathRequestMatcher("/demo/**")).permitAll());
.requestMatchers(pathPattern("/demo/**")).permitAll());
return http.build();
// @formatter:on
}
@ -100,12 +99,12 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests {
static class MvcMatchersAfterAnyRequestConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
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 +155,7 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests {
http
.authorizeRequests((requests) -> requests
.anyRequest().authenticated()
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll());
.requestMatchers(pathPattern("/**")).permitAll());
return http.build();
// @formatter:on
}

View File

@ -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,26 @@ public class AbstractRequestMatcherRegistryNoMvcTests {
@BeforeEach
public void setUp() {
this.matcherRegistry = new TestRequestMatcherRegistry();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(PathPatternRequestMatcher.Builder.class, PathPatternRequestMatcher::withDefaults);
context.refresh();
this.matcherRegistry.setApplicationContext(context);
}
@Test
public void requestMatchersWhenPatternAndMvcNotPresentThenReturnAntPathRequestMatcherType() {
public void requestMatchersWhenPatternAndMvcNotPresentThenReturnPathPatternRequestMatcherType() {
List<RequestMatcher> 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<RequestMatcher> 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 +69,7 @@ public class AbstractRequestMatcherRegistryNoMvcTests {
List<RequestMatcher> 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<List<RequestMatcher>> {

View File

@ -16,47 +16,29 @@
package org.springframework.security.config.annotation.web;
import java.util.ArrayList;
import java.util.List;
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.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;
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
/**
* Tests for {@link AbstractRequestMatcherRegistry}.
@ -86,9 +68,9 @@ public class AbstractRequestMatcherRegistryTests {
ObjectProvider<ObjectPostProcessor<Object>> 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.getBean(PathPatternRequestMatcher.Builder.class))
.willReturn(PathPatternRequestMatcher.withDefaults());
this.matcherRegistry.setApplicationContext(this.context);
mockMvcIntrospector(true);
}
@Test
@ -110,24 +92,24 @@ public class AbstractRequestMatcherRegistryTests {
}
@Test
public void antMatchersWhenHttpMethodAndPatternParamsThenReturnAntPathRequestMatcherType() {
public void pathPatternWhenHttpMethodAndPatternParamsThenReturnPathPatternRequestMatcherType() {
List<RequestMatcher> requestMatchers = this.matcherRegistry
.requestMatchers(new AntPathRequestMatcher("/a.*", HttpMethod.GET.name()));
.requestMatchers(pathPattern(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<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(new AntPathRequestMatcher("/a.*"));
public void pathPatternWhenPatternParamThenReturnPathPatternRequestMatcherType() {
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(pathPattern("/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<RequestMatcher> requestMatchers = this.matcherRegistry.dispatcherTypeMatchers(HttpMethod.GET,
DispatcherType.ASYNC);
assertThat(requestMatchers).isNotEmpty();
@ -136,7 +118,7 @@ public class AbstractRequestMatcherRegistryTests {
}
@Test
public void dispatcherMatchersWhenPatternParamThenReturnAntPathRequestMatcherType() {
public void dispatcherMatchersWhenPatternParamThenReturnPathPatternRequestMatcherType() {
List<RequestMatcher> requestMatchers = this.matcherRegistry.dispatcherTypeMatchers(DispatcherType.INCLUDE);
assertThat(requestMatchers).isNotEmpty();
assertThat(requestMatchers).hasSize(1);
@ -144,252 +126,36 @@ public class AbstractRequestMatcherRegistryTests {
}
@Test
public void requestMatchersWhenPatternAndMvcPresentThenReturnMvcRequestMatcherType() {
public void requestMatchersWhenPatternAndMvcPresentThenReturnPathPatternRequestMatcherType() {
List<RequestMatcher> 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<RequestMatcher> 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<RequestMatcher> 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<RequestMatcher> 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<RequestMatcher> 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<RequestMatcher> 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<RequestMatcher> 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<RequestMatcher> 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<RequestMatcher> 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<List<RequestMatcher>> {
@Override
public List<RequestMatcher> requestMatchers(RequestMatcher... requestMatchers) {
return unwrap(super.requestMatchers(requestMatchers));
}
@Override
protected List<RequestMatcher> chainRequestMatchers(List<RequestMatcher> requestMatchers) {
return requestMatchers;
}
private List<RequestMatcher> unwrap(List<RequestMatcher> wrappedMatchers) {
List<RequestMatcher> 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

View File

@ -39,7 +39,6 @@ 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.test.web.servlet.MockMvc;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@ -49,6 +48,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -150,8 +150,8 @@ public class HttpConfigurationTests {
// @formatter:off
http
.securityMatchers((security) -> security
.requestMatchers(new AntPathRequestMatcher("/api/**"))
.requestMatchers(new AntPathRequestMatcher("/oauth/**")))
.requestMatchers(pathPattern("/api/**"))
.requestMatchers(pathPattern("/oauth/**")))
.authorizeRequests((requests) -> requests
.anyRequest().hasRole("USER"))
.httpBasic(withDefaults());

View File

@ -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;
@ -75,6 +75,7 @@ import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
@ -195,13 +196,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 +227,19 @@ 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(pathPattern("/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(pathPattern("/public/**"));
assertThat(securityFilterChain.getFilters()).isEmpty();
}
@ -482,7 +481,7 @@ public class NamespaceHttpTests {
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http
.securityMatcher(new AntPathRequestMatcher("/api/**"));
.securityMatcher(pathPattern("/api/**"));
return http.build();
// @formatter:on
}
@ -534,8 +533,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

View File

@ -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<SecurityFilterChain> 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,

View File

@ -42,12 +42,11 @@ 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 +129,8 @@ public class WebSecurityTests {
static class MvcMatcherConfig {
@Bean
WebSecurityCustomizer webSecurityCustomizer(HandlerMappingIntrospector introspector) {
return (web) -> web.ignoring().requestMatchers(new MvcRequestMatcher(introspector, "/path"));
WebSecurityCustomizer webSecurityCustomizer(PathPatternRequestMatcher.Builder builder) {
return (web) -> web.ignoring().requestMatchers(builder.matcher("/path"));
}
@Bean
@ -168,9 +167,10 @@ 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");
WebSecurityCustomizer webSecurityCustomizer(PathPatternRequestMatcher.Builder builder) {
return (web) -> web.ignoring()
.requestMatchers(builder.basePath("/spring").matcher("/path"))
.requestMatchers("/notused");
}
@Bean

View File

@ -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 {
}

View File

@ -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 {
}
}

View File

@ -62,8 +62,6 @@ 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;
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;
@ -78,6 +76,7 @@ import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -106,14 +105,13 @@ public class WebSecurityConfigurationTests {
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
List<SecurityFilterChain> 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<SecurityFilterChain> 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<SecurityFilterChain> 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<SecurityFilterChain> 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<SecurityFilterChain> 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(pathPattern("/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(pathPattern("/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(pathPattern("/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(pathPattern("/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(pathPattern("/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(pathPattern("/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(pathPattern("/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(pathPattern("/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(pathPattern("/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(pathPattern("/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(pathPattern("/admin")))
.authorizeRequests((requests) -> requests.anyRequest().hasRole("ADMIN"));
// @formatter:on
return http.build();
@ -911,7 +905,7 @@ public class WebSecurityConfigurationTests {
public SecurityFilterChain notAuthorized(HttpSecurity http) throws Exception {
// @formatter:off
http
.securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/user")))
.securityMatchers((requests) -> requests.requestMatchers(pathPattern("/user")))
.authorizeHttpRequests((authorize) -> authorize.anyRequest().hasRole("USER"));
// @formatter:on
return http.build();
@ -922,7 +916,7 @@ public class WebSecurityConfigurationTests {
public SecurityFilterChain admin(HttpSecurity http) throws Exception {
// @formatter:off
http
.securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/admin")))
.securityMatchers((requests) -> requests.requestMatchers(pathPattern("/admin")))
.authorizeHttpRequests((authorize) -> authorize.anyRequest().hasRole("ADMIN"));
// @formatter:on
return http.build();

View File

@ -22,11 +22,12 @@ 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;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
public class AbstractConfigAttributeRequestMatcherRegistryTests {
@ -55,19 +56,18 @@ public class AbstractConfigAttributeRequestMatcherRegistryTests {
}
@Test
public void testGetRequestMatcherIsTypeAntPathRequestMatcher() {
List<RequestMatcher> requestMatchers = this.registry
.requestMatchers(new AntPathRequestMatcher("/a.*", HttpMethod.GET.name()));
public void testGetRequestMatcherIsTypePathPatternRequestMatcher() {
List<RequestMatcher> requestMatchers = this.registry.requestMatchers(pathPattern(HttpMethod.GET, "/a.*"));
for (RequestMatcher requestMatcher : requestMatchers) {
assertThat(requestMatcher).isInstanceOf(AntPathRequestMatcher.class);
assertThat(requestMatcher).isInstanceOf(PathPatternRequestMatcher.class);
}
}
@Test
public void testRequestMatcherIsTypeAntPathRequestMatcher() {
List<RequestMatcher> requestMatchers = this.registry.requestMatchers(new AntPathRequestMatcher("/a.*"));
public void testRequestMatcherIsTypePathPatternRequestMatcher() {
List<RequestMatcher> requestMatchers = this.registry.requestMatchers(pathPattern("/a.*"));
for (RequestMatcher requestMatcher : requestMatchers) {
assertThat(requestMatcher).isInstanceOf(AntPathRequestMatcher.class);
assertThat(requestMatcher).isInstanceOf(PathPatternRequestMatcher.class);
}
}

View File

@ -55,7 +55,6 @@ import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.observation.SecurityObservationSettings;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
@ -68,7 +67,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 +79,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 +145,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 +686,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 +1060,11 @@ public class AuthorizeHttpRequestsConfigurerTests {
static class ServletPathConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
.servletPath("/spring");
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 +1353,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
@Configuration
@EnableWebSecurity
@EnableWebMvc
static class MvcRequestMatcherBuilderConfig {
static class PathPatternRequestMatcherBuilderConfig {
@Bean
SecurityFilterChain security(HttpSecurity http) throws Exception {
@ -1394,11 +1389,6 @@ public class AuthorizeHttpRequestsConfigurerTests {
return http.build();
}
@Bean
PathPatternRequestMatcherBuilderFactoryBean pathPatternFactoryBean() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
}
@Configuration

View File

@ -42,17 +42,17 @@ 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;
import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
/**
* @author Rob Winch
@ -126,11 +126,13 @@ public class AuthorizeRequestsTests {
loadConfig(AntPatchersPathVariables.class);
this.request.setRequestURI("/USER/user");
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.setRequestURI("/USER/deny");
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);
}
@ -204,7 +206,7 @@ public class AuthorizeRequestsTests {
// @formatter:off
http
.authorizeRequests((requests) -> requests
.requestMatchers(new AntPathRequestMatcher("/**", HttpMethod.POST.name())).denyAll());
.requestMatchers(pathPattern(HttpMethod.POST, "/**")).denyAll());
// @formatter:on
return http.build();
}
@ -225,7 +227,7 @@ public class AuthorizeRequestsTests {
// @formatter:off
http
.authorizeRequests((authorize) -> authorize
.requestMatchers(new AntPathRequestMatcher("/**", HttpMethod.POST.name())).denyAll()
.requestMatchers(pathPattern(HttpMethod.POST, "/**")).denyAll()
);
// @formatter:on
return http.build();
@ -244,10 +246,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();
@ -266,10 +271,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();
@ -383,14 +391,13 @@ public class AuthorizeRequestsTests {
static class MvcMatcherServletPathConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
.servletPath("/spring");
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();
}
@ -418,14 +425,13 @@ public class AuthorizeRequestsTests {
static class MvcMatcherServletPathInLambdaConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
.servletPath("/spring");
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();

View File

@ -28,13 +28,13 @@ 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.util.matcher.RequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
@ -109,7 +109,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
// @formatter:off
http
.csrf((csrf) -> csrf
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/path"))
.requireCsrfProtectionMatcher(pathPattern("/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(pathPattern("/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(pathPattern("/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(pathPattern("/no-csrf"))
.ignoringRequestMatchers(this.requestMatcher)
);
return http.build();

View File

@ -57,7 +57,6 @@ 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.util.matcher.RequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
@ -84,6 +83,7 @@ import static org.springframework.security.test.web.servlet.request.SecurityMock
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.head;
@ -906,7 +906,7 @@ public class CsrfConfigurerTests {
http
.formLogin(withDefaults())
.logout((logout) -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")));
.logoutRequestMatcher(pathPattern("/logout")));
return http.build();
// @formatter:on
}

View File

@ -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);

View File

@ -32,11 +32,11 @@ 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.util.matcher.AnyRequestMatcher;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -92,7 +92,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
.exceptionHandling((handling) -> handling
.defaultAccessDeniedHandlerFor(
this.teapotDeniedHandler,
new AntPathRequestMatcher("/hello/**"))
pathPattern("/hello/**"))
.defaultAccessDeniedHandlerFor(
new AccessDeniedHandlerImpl(),
AnyRequestMatcher.INSTANCE));
@ -119,7 +119,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
.exceptionHandling((exceptionHandling) -> exceptionHandling
.defaultAccessDeniedHandlerFor(
this.teapotDeniedHandler,
new AntPathRequestMatcher("/hello/**")
pathPattern("/hello/**")
)
.defaultAccessDeniedHandlerFor(
new AccessDeniedHandlerImpl(),
@ -148,7 +148,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
.exceptionHandling((handling) -> handling
.defaultAccessDeniedHandlerFor(
this.teapotDeniedHandler,
new AntPathRequestMatcher("/hello/**")));
pathPattern("/hello/**")));
return http.build();
// @formatter:on
}

View File

@ -36,12 +36,11 @@ 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;
@ -160,14 +159,13 @@ public class HttpSecurityRequestMatchersTests {
@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());
@ -176,12 +174,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()
@ -209,14 +206,13 @@ public class HttpSecurityRequestMatchersTests {
@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());
@ -225,12 +221,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
@ -255,10 +250,10 @@ public class HttpSecurityRequestMatchersTests {
static class MvcMatcherConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
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());
@ -289,11 +284,11 @@ public class HttpSecurityRequestMatchersTests {
static class RequestMatchersMvcMatcherConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
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());
@ -324,11 +319,11 @@ public class HttpSecurityRequestMatchersTests {
static class RequestMatchersMvcMatcherInLambdaConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
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
@ -356,13 +351,11 @@ 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");
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
@ -394,13 +387,11 @@ 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");
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())

View File

@ -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) {

View File

@ -39,12 +39,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 +355,13 @@ public class HttpSecuritySecurityMatchersTests {
static class SecurityMatchersMvcMatcherServletPathConfig {
@Bean
SecurityFilterChain appSecurity(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
.servletPath("/spring");
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 +389,13 @@ public class HttpSecuritySecurityMatchersTests {
static class SecurityMatchersMvcMatcherServletPathInLambdaConfig {
@Bean
SecurityFilterChain appSecurity(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
.servletPath("/spring");
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

View File

@ -126,11 +126,6 @@ public class HttpsRedirectConfigurerTests {
return http.build();
}
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
}
@Configuration

View File

@ -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"))

View File

@ -34,7 +34,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.test.web.servlet.RequestCacheResultMatcher;
@ -502,11 +501,6 @@ public class RequestCacheConfigurerTests {
@EnableWebSecurity
static class PathPatternFactoryBeanConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean factoryBean() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
}
}

View File

@ -27,9 +27,9 @@ 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.test.web.servlet.MockMvc;
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -79,9 +79,9 @@ public class RequestMatcherConfigurerTests {
// @formatter:off
http
.securityMatchers((security) -> security
.requestMatchers(new AntPathRequestMatcher("/api/**")))
.requestMatchers(pathPattern("/api/**")))
.securityMatchers((security) -> security
.requestMatchers(new AntPathRequestMatcher("/oauth/**")))
.requestMatchers(pathPattern("/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(pathPattern("/api/**"))
)
.securityMatchers((securityMatchers) -> securityMatchers
.requestMatchers(new AntPathRequestMatcher("/oauth/**"))
.requestMatchers(pathPattern("/oauth/**"))
)
.authorizeRequests((authorize) -> authorize
.anyRequest().denyAll()

View File

@ -41,12 +41,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;
@ -133,12 +132,12 @@ public class UrlAuthorizationConfigurerTests {
@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();
}
@ -167,14 +166,13 @@ public class UrlAuthorizationConfigurerTests {
@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();
}

View File

@ -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);
}
}

View File

@ -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<SecurityFilterChain> chains = new ArrayList<>();
chains.add(chain2);
chains.add(chain1);

View File

@ -92,9 +92,7 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
public void interceptUrlsSupportPropertyPlaceholders() {
System.setProperty("secure.url", "/secure");
System.setProperty("secure.role", "ROLE_A");
setContext(
"<b:bean class=\"org.springframework.web.servlet.handler.HandlerMappingIntrospector\" name=\"mvcHandlerMappingIntrospector\"/>"
+ "<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>"
setContext("<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>"
+ "<filter-security-metadata-source id='fids' use-expressions='false'>"
+ " <intercept-url pattern='${secure.url}' access='${secure.role}'/>"
+ "</filter-security-metadata-source>");
@ -107,8 +105,7 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
@Test
public void parsingWithinFilterSecurityInterceptorIsSuccessful() {
// @formatter:off
setContext("<b:bean class=\"org.springframework.web.servlet.handler.HandlerMappingIntrospector\" name=\"mvcHandlerMappingIntrospector\"/>" +
"<http auto-config='true' use-expressions='false' use-authorization-manager='false'/>"
setContext("<http auto-config='true' use-expressions='false' use-authorization-manager='false'/>"
+ "<b:bean id='fsi' class='org.springframework.security.web.access.intercept.FilterSecurityInterceptor' autowire='byType'>"
+ " <b:property name='securityMetadataSource'>"
+ " <filter-security-metadata-source use-expressions='false'>"

View File

@ -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"));

View File

@ -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()

View File

@ -22,7 +22,8 @@ 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 static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
/**
* @author Rob Winch
@ -44,7 +45,7 @@ public class CustomConfigurer extends SecurityConfigurerAdapter<DefaultSecurityF
// @formatter:off
http
.authorizeRequests((requests) -> requests
.requestMatchers(new AntPathRequestMatcher(this.permitAllPattern)).permitAll()
.requestMatchers(pathPattern(this.permitAllPattern)).permitAll()
.anyRequest().authenticated());
// @formatter:on
if (http.getConfigurer(FormLoginConfigurer.class) == null) {

View File

@ -38,12 +38,8 @@ import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequ
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy
import org.springframework.security.web.csrf.CsrfTokenRepository
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.csrf.*
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 +172,7 @@ class CsrfDslTests {
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
csrf {
requireCsrfProtectionMatcher = AntPathRequestMatcher("/test1")
requireCsrfProtectionMatcher = PathPatternRequestMatcher.pathPattern("/test1")
}
}
return http.build()
@ -247,8 +243,8 @@ class CsrfDslTests {
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
csrf {
requireCsrfProtectionMatcher = AntPathRequestMatcher("/**")
ignoringRequestMatchers(AntPathRequestMatcher("/test2"))
requireCsrfProtectionMatcher = PathPatternRequestMatcher.pathPattern("/**")
ignoringRequestMatchers(PathPatternRequestMatcher.pathPattern("/test2"))
}
}
return http.build()
@ -279,7 +275,7 @@ class CsrfDslTests {
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
csrf {
requireCsrfProtectionMatcher = AntPathRequestMatcher("/**")
requireCsrfProtectionMatcher = PathPatternRequestMatcher.pathPattern("/**")
ignoringRequestMatchers("/test2")
}
}

View File

@ -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()

View File

@ -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.pathPattern("/custom/logout")
}
}
return http.build()
@ -307,8 +307,9 @@ class LogoutDslTests {
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
logout {
logoutRequestMatcher = AntPathRequestMatcher("/logout/**")
defaultLogoutSuccessHandlerFor(SimpleUrlLogoutSuccessHandler(), AntPathRequestMatcher("/logout/custom"))
logoutRequestMatcher = PathPatternRequestMatcher.pathPattern("/logout/**")
defaultLogoutSuccessHandlerFor(SimpleUrlLogoutSuccessHandler(),
PathPatternRequestMatcher.pathPattern("/logout/custom"))
}
}
return http.build()

View File

@ -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"
}

View File

@ -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.pathPattern("/secure/**")
}
}
}

View File

@ -15,16 +15,12 @@
-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util-3.1.xsd
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
">
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd">
<security:http pattern="/foo/**">
<security:intercept-url pattern="/**" access="hasRole('FOO')" />
@ -44,6 +40,4 @@ http://www.springframework.org/schema/security https://www.springframework.org/s
</security:authentication-provider>
</security:authentication-manager>
<import resource="handlermappingintrospector.xml"/>
</beans>

View File

@ -30,7 +30,6 @@
</http>
<b:import resource="CsrfConfigTests-shared-userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
<b:bean id="firewall" class="org.springframework.security.web.firewall.StrictHttpFirewall"
p:unsafeAllowAnyHttpMethod="true"/>

View File

@ -24,7 +24,7 @@
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<http auto-config="true" use-expressions="false" request-matcher="ant" use-authorization-manager="false">
<http auto-config="true" use-expressions="false" use-authorization-manager="false">
<intercept-url pattern="/**" access="ROLE_USER"/>
<form-login/>
</http>

View File

@ -24,7 +24,7 @@
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<http auto-config="true" use-expressions="false" request-matcher="ant" use-authorization-manager="false">
<http auto-config="true" use-expressions="false" use-authorization-manager="false">
<intercept-url pattern="/**" access="ROLE_USER"/>
<form-login authentication-success-handler-ref="fsh" authentication-failure-handler-ref="fsh"/>
</http>

View File

@ -16,8 +16,10 @@
<user name="user" password="password" authorities="ROLE_USER"/>
</user-service>
<b:bean id="matcherRef" class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"
c:pattern="/foo"
c:httpMethod="GET"
c:caseSensitive="false"/>
<b:bean id="mvcPatternParser" class="org.springframework.web.util.pattern.PathPatternParser">
<b:property name="caseSensitive" value="false"/>
</b:bean>
<b:bean id="matcherRef" class="org.springframework.security.config.http.PathPatternRequestMatcherFactoryBean"
c:pattern="/foo" c:method="GET"/>
</b:beans>

View File

@ -38,7 +38,7 @@
<b:constructor-arg value="ERROR"/>
</b:bean>
<b:bean name="errorPathRequestMatcher" class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
<b:bean name="errorPathRequestMatcher" class="org.springframework.security.config.http.PathPatternRequestMatcherFactoryBean">
<b:constructor-arg value="/error"/>
</b:bean>

View File

@ -33,5 +33,4 @@
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -33,5 +33,4 @@
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -30,5 +30,4 @@
</http>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -30,5 +30,4 @@
</http>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -38,7 +38,7 @@
<b:constructor-arg value="ERROR"/>
</b:bean>
<b:bean name="errorPathRequestMatcher" class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
<b:bean name="errorPathRequestMatcher" class="org.springframework.security.config.http.PathPatternRequestMatcherFactoryBean">
<b:constructor-arg value="/error"/>
</b:bean>

View File

@ -33,5 +33,4 @@
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -33,5 +33,4 @@
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -33,5 +33,4 @@
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -33,5 +33,4 @@
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -34,5 +34,4 @@
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -34,5 +34,4 @@
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -34,5 +34,4 @@
<b:bean name="id" class="org.springframework.security.config.http.InterceptUrlConfigTests.Id"/>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -34,5 +34,4 @@
<b:bean name="id" class="org.springframework.security.config.http.InterceptUrlConfigTests.Id"/>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -32,5 +32,4 @@
</http>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -31,5 +31,4 @@
</http>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -34,5 +34,4 @@
</b:bean>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -32,7 +32,7 @@
<http-basic/>
</http>
<b:bean name="matcher" class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
<b:bean name="matcher" class="org.springframework.security.config.http.PathPatternRequestMatcherFactoryBean">
<b:constructor-arg value="/unprotected"/>
</b:bean>

View File

@ -29,5 +29,4 @@
<http pattern="/unprotected" security="none"/>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -31,5 +31,4 @@
</http>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -31,5 +31,4 @@
</http>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -30,5 +30,4 @@
</http>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -30,5 +30,4 @@
</http>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -35,5 +35,4 @@
<b:bean name="basicController" class="org.springframework.security.config.http.MultiHttpBlockConfigTests.BasicController"/>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -33,5 +33,4 @@
</http>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

View File

@ -50,5 +50,4 @@
</authentication-provider>
</authentication-manager>
<b:import resource="handlermappingintrospector.xml"/>
</b:beans>

Some files were not shown because too many files have changed in this diff Show More