This commit is contained in:
Josh Cummings 2025-06-24 15:20:24 -06:00
parent 75f30d1701
commit ef50ff29ad
No known key found for this signature in database
GPG Key ID: 869B37A20E876129
174 changed files with 713 additions and 2967 deletions

View File

@ -52,7 +52,6 @@ import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@ -335,7 +334,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
}
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
this.proxyReceptorMatcher = new AntPathRequestMatcher("/**" + proxyReceptorUrl);
this.proxyReceptorMatcher = PathPatternRequestMatcher.withDefaults().matcher(proxyReceptorUrl);
}
public final void setProxyGrantingTicketStorage(final ProxyGrantingTicketStorage proxyGrantingTicketStorage) {

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,13 @@ 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
.getBeanProvider(PathPatternRequestMatcher.Builder.class)
.getIfUnique(PathPatternRequestMatcher::withDefaults);
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 +159,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 +178,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 +202,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

@ -19,7 +19,6 @@ package org.springframework.security.config.annotation.web;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpMethod;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
@ -34,11 +33,8 @@ public final class RequestMatcherFactory {
private static PathPatternRequestMatcher.Builder builder;
public static void setApplicationContext(ApplicationContext context) {
builder = context.getBeanProvider(PathPatternRequestMatcher.Builder.class).getIfUnique();
}
public static boolean usesPathPatterns() {
return builder != null;
builder = context.getBeanProvider(PathPatternRequestMatcher.Builder.class)
.getIfUnique(PathPatternRequestMatcher::withDefaults);
}
public static RequestMatcher matcher(String path) {
@ -46,10 +42,7 @@ public final class RequestMatcherFactory {
}
public static RequestMatcher matcher(HttpMethod method, String path) {
if (builder != null) {
return builder.matcher(method, path);
}
return new AntPathRequestMatcher(path, (method != null) ? method.name() : null);
return builder.matcher(method, path);
}
private RequestMatcherFactory() {

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
@ -320,9 +305,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
@ -2202,10 +2185,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
@ -2215,19 +2196,16 @@ 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()
.getBeanProvider(PathPatternRequestMatcher.Builder.class)
.getIfUnique(PathPatternRequestMatcher::withDefaults);
for (String pattern : patterns) {
if (RequestMatcherFactory.usesPathPatterns()) {
matchers.add(RequestMatcherFactory.matcher(pattern));
}
else {
RequestMatcher matcher = mvcPresent ? createMvcMatcher(pattern) : createAntMatcher(pattern);
matchers.add(matcher);
}
matchers.add(builder.matcher(pattern));
}
this.requestMatcher = new OrRequestMatcher(matchers);
return this;
@ -2258,26 +2236,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<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;
@ -430,7 +431,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

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

@ -69,7 +69,6 @@ import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.RequestRejectedHandler;
import org.springframework.web.filter.CompositeFilter;
import org.springframework.web.filter.ServletRequestPathFilter;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
/**
* Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web
@ -209,12 +208,11 @@ public class WebSecurityConfiguration implements ImportAware {
/**
* Used to ensure Spring MVC request matching is cached.
*
* Creates a {@link BeanDefinitionRegistryPostProcessor} that detects if a bean named
* HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME is defined. If so, it moves the
* Creates a {@link BeanDefinitionRegistryPostProcessor} that moves the
* AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME to another bean name
* and then adds a {@link CompositeFilter} that contains
* {@link HandlerMappingIntrospector#createCacheFilter()} and the original
* FilterChainProxy under the original Bean name.
* {@link ServletRequestPathFilter} and the original FilterChainProxy under the
* original Bean name.
* @return
*/
@Bean

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,10 +79,7 @@ public class CorsConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHt
CorsConfigurationSource.class);
return new CorsFilter(configurationSource);
}
if (mvcPresent) {
return MvcCorsFilter.getMvcCorsFilter(context);
}
return null;
return MvcCorsFilter.getMvcCorsFilter(context);
}
static class MvcCorsFilter {

View File

@ -31,7 +31,6 @@ import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.util.matcher.AndRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
@ -174,12 +173,7 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>>
}
private RequestMatcher getFaviconRequestMatcher() {
if (RequestMatcherFactory.usesPathPatterns()) {
return RequestMatcherFactory.matcher("/favicon.*");
}
else {
return new AntPathRequestMatcher("/**/favicon.*");
}
return RequestMatcherFactory.matcher("/favicon.*");
}
}

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

@ -50,7 +50,6 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.HandlerMappingIntrospectorRequestTransformer;
import org.springframework.security.web.access.PathPatternRequestTransformer;
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
@ -88,7 +87,6 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
/**
* Stateful class which helps HttpSecurityBDP to create the configuration for the
@ -100,11 +98,6 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
*/
class HttpConfigurationBuilder {
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
private static final boolean mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR,
HttpConfigurationBuilder.class.getClassLoader());
private static final String ATT_CREATE_SESSION = "create-session";
private static final String ATT_SESSION_FIXATION_PROTECTION = "session-fixation-protection";
@ -793,10 +786,8 @@ class HttpConfigurationBuilder {
BeanDefinitionBuilder wipeBldr = BeanDefinitionBuilder
.rootBeanDefinition(AuthorizationManagerWebInvocationPrivilegeEvaluator.class)
.addConstructorArgReference(authorizationFilterParser.getAuthorizationManagerRef());
if (mvcPresent) {
wipeBldr.addPropertyValue("requestTransformer",
new RootBeanDefinition(HandlerMappingIntrospectorRequestTransformerFactoryBean.class));
}
wipeBldr.addPropertyValue("requestTransformer",
new RootBeanDefinition(PathPatternRequestTransformerFactoryBean.class));
BeanDefinition wipe = wipeBldr.getBeanDefinition();
this.pc.registerBeanComponent(
new BeanComponentDefinition(wipe, this.pc.getReaderContext().generateBeanName(wipe)));
@ -966,7 +957,7 @@ class HttpConfigurationBuilder {
return BeanDefinitionBuilder.rootBeanDefinition(ObservationRegistryFactory.class).getBeanDefinition();
}
static class HandlerMappingIntrospectorRequestTransformerFactoryBean
static class PathPatternRequestTransformerFactoryBean
implements FactoryBean<AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer>,
ApplicationContextAware {
@ -982,10 +973,7 @@ class HttpConfigurationBuilder {
if (requestTransformer != null) {
return requestTransformer;
}
HandlerMappingIntrospector hmi = this.applicationContext.getBeanProvider(HandlerMappingIntrospector.class)
.getIfAvailable();
return (hmi != null) ? new HandlerMappingIntrospectorRequestTransformer(hmi)
: new PathPatternRequestTransformer();
return new PathPatternRequestTransformer();
}
@Override

View File

@ -22,13 +22,10 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.http.HttpMethod;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
@ -39,21 +36,12 @@ import org.springframework.util.StringUtils;
*/
public enum MatcherType {
ant(AntPathRequestMatcher.class), regex(RegexRequestMatcher.class), ciRegex(RegexRequestMatcher.class),
mvc(MvcRequestMatcher.class);
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
private static final boolean mvcPresent;
path(PathPatternRequestMatcher.class), regex(RegexRequestMatcher.class), ciRegex(RegexRequestMatcher.class);
private static final String ATT_MATCHER_TYPE = "request-matcher";
final Class<? extends RequestMatcher> type;
static {
mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, MatcherType.class.getClassLoader());
}
MatcherType(Class<? extends RequestMatcher> type) {
this.type = type;
}
@ -66,18 +54,17 @@ public enum MatcherType {
if (("/**".equals(path) || "**".equals(path)) && method == null) {
return new RootBeanDefinition(AnyRequestMatcher.class);
}
BeanDefinitionBuilder matcherBldr = BeanDefinitionBuilder.rootBeanDefinition(this.type);
if (this == mvc) {
matcherBldr.addConstructorArgValue(new RootBeanDefinition(HandlerMappingIntrospectorFactoryBean.class));
}
matcherBldr.addConstructorArgValue(path);
if (this == mvc) {
matcherBldr.addPropertyValue("method", (StringUtils.hasText(method) ? HttpMethod.valueOf(method) : null));
matcherBldr.addPropertyValue("servletPath", servletPath);
BeanDefinitionBuilder matcherBldr;
if (this == MatcherType.path) {
matcherBldr = BeanDefinitionBuilder.rootBeanDefinition(PathPatternRequestMatcherFactoryBean.class);
matcherBldr.addConstructorArgValue(path);
matcherBldr.addPropertyValue("basePath", servletPath);
}
else {
matcherBldr.addConstructorArgValue(method);
matcherBldr = BeanDefinitionBuilder.rootBeanDefinition(this.type);
matcherBldr.addConstructorArgValue(path);
}
matcherBldr.addConstructorArgValue(method);
if (this == ciRegex) {
matcherBldr.addConstructorArgValue(true);
}
@ -89,14 +76,10 @@ public enum MatcherType {
return valueOf(elt.getAttribute(ATT_MATCHER_TYPE));
}
return ant;
return path;
}
static MatcherType fromElementOrMvc(Element elt) {
String matcherTypeName = elt.getAttribute(ATT_MATCHER_TYPE);
if (!StringUtils.hasText(matcherTypeName) && mvcPresent) {
return MatcherType.mvc;
}
return MatcherType.fromElement(elt);
}

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,10 +44,7 @@ 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);
return this.builder.matcher(this.method, this.path);
}
@Override
@ -58,7 +54,8 @@ 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.getBeanProvider(PathPatternRequestMatcher.Builder.class)
.getIfUnique(PathPatternRequestMatcher::withDefaults);
}
}

View File

@ -58,6 +58,6 @@ abstract class AbstractRequestMatcherDsl {
protected abstract class AuthorizationManagerRule(open val rule: AuthorizationManager<RequestAuthorizationContext>)
protected enum class PatternType {
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)

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
element cors { cors-options.attlist }
cors-options.attlist &=
ref?

View File

@ -3317,8 +3317,7 @@
</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
</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;
@ -120,7 +121,7 @@ public class FilterChainProxyConfigTests {
private String getPattern(SecurityFilterChain chain) {
RequestMatcher requestMatcher = ((DefaultSecurityFilterChain) chain).getRequestMatcher();
return (String) ReflectionTestUtils.getField(requestMatcher, "pattern");
return ((PathPattern) ReflectionTestUtils.getField(requestMatcher, "pattern")).getPatternString();
}
private void checkPathAndFilterOrder(FilterChainProxy filterChainProxy) {

View File

@ -32,7 +32,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.util.Assert;
/**
@ -52,7 +52,7 @@ public class SecurityConfig {
// @formatter:off
http
.authorizeRequests((requests) -> requests
.requestMatchers(new AntPathRequestMatcher("/*")).permitAll())
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/*")).permitAll())
.authenticationProvider(authenticationProvider());
// @formatter:on
return http.build();

View File

@ -24,12 +24,11 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -88,7 +87,7 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests {
http
.authorizeRequests((requests) -> requests
.anyRequest().authenticated()
.requestMatchers(new AntPathRequestMatcher("/demo/**")).permitAll());
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/demo/**")).permitAll());
return http.build();
// @formatter:on
}
@ -100,12 +99,17 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests {
static class MvcMatchersAfterAnyRequestConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off
http
.authorizeRequests((requests) -> requests
.anyRequest().authenticated()
.requestMatchers(new MvcRequestMatcher(introspector, "/demo/**")).permitAll());
.requestMatchers(builder.matcher("/demo/**")).permitAll());
return http.build();
// @formatter:on
}
@ -156,7 +160,7 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests {
http
.authorizeRequests((requests) -> requests
.anyRequest().authenticated()
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll());
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/**")).permitAll());
return http.build();
// @formatter:on
}

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,25 @@ public class AbstractRequestMatcherRegistryNoMvcTests {
@BeforeEach
public void setUp() {
this.matcherRegistry = new TestRequestMatcherRegistry();
GenericApplicationContext context = new GenericApplicationContext();
context.refresh();
this.matcherRegistry.setApplicationContext(context);
}
@Test
public void requestMatchersWhenPatternAndMvcNotPresentThenReturnAntPathRequestMatcherType() {
public void requestMatchersWhenPatternAndMvcNotPresentThenReturnPathPatternRequestMatcherType() {
List<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 +68,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,30 @@
package org.springframework.security.config.annotation.web;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.Servlet;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.config.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.DispatcherServletDelegatingRequestMatcher;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.web.servlet.MockServletContext;
import org.springframework.security.web.servlet.TestMockHttpServletMappings;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.InstanceOfAssertFactories.type;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
/**
* Tests for {@link AbstractRequestMatcherRegistry}.
@ -86,9 +69,13 @@ public class AbstractRequestMatcherRegistryTests {
ObjectProvider<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.getBeanProvider(any(Class.class))).willReturn(new ObjectProvider<>() {
@Override
public Stream<Object> stream() {
return Stream.of();
}
});
this.matcherRegistry.setApplicationContext(this.context);
mockMvcIntrospector(true);
}
@Test
@ -110,24 +97,25 @@ public class AbstractRequestMatcherRegistryTests {
}
@Test
public void antMatchersWhenHttpMethodAndPatternParamsThenReturnAntPathRequestMatcherType() {
public void pathPatternWhenHttpMethodAndPatternParamsThenReturnPathPatternRequestMatcherType() {
List<RequestMatcher> requestMatchers = this.matcherRegistry
.requestMatchers(new AntPathRequestMatcher("/a.*", HttpMethod.GET.name()));
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/a.*"));
assertThat(requestMatchers).isNotEmpty();
assertThat(requestMatchers).hasSize(1);
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class);
}
@Test
public void antMatchersWhenPatternParamThenReturnAntPathRequestMatcherType() {
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(new AntPathRequestMatcher("/a.*"));
public void pathPatternWhenPatternParamThenReturnPathPatternRequestMatcherType() {
List<RequestMatcher> requestMatchers = this.matcherRegistry
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/a.*"));
assertThat(requestMatchers).isNotEmpty();
assertThat(requestMatchers).hasSize(1);
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class);
}
@Test
public void dispatcherTypeMatchersWhenHttpMethodAndPatternParamsThenReturnAntPathRequestMatcherType() {
public void dispatcherTypeMatchersWhenHttpMethodAndPatternParamsThenReturnPathPatternRequestMatcherType() {
List<RequestMatcher> requestMatchers = this.matcherRegistry.dispatcherTypeMatchers(HttpMethod.GET,
DispatcherType.ASYNC);
assertThat(requestMatchers).isNotEmpty();
@ -136,7 +124,7 @@ public class AbstractRequestMatcherRegistryTests {
}
@Test
public void dispatcherMatchersWhenPatternParamThenReturnAntPathRequestMatcherType() {
public void dispatcherMatchersWhenPatternParamThenReturnPathPatternRequestMatcherType() {
List<RequestMatcher> requestMatchers = this.matcherRegistry.dispatcherTypeMatchers(DispatcherType.INCLUDE);
assertThat(requestMatchers).isNotEmpty();
assertThat(requestMatchers).hasSize(1);
@ -144,252 +132,36 @@ public class AbstractRequestMatcherRegistryTests {
}
@Test
public void requestMatchersWhenPatternAndMvcPresentThenReturnMvcRequestMatcherType() {
public void requestMatchersWhenPatternAndMvcPresentThenReturnPathPatternRequestMatcherType() {
List<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,7 @@ import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@ -150,8 +150,8 @@ public class HttpConfigurationTests {
// @formatter:off
http
.securityMatchers((security) -> security
.requestMatchers(new AntPathRequestMatcher("/api/**"))
.requestMatchers(new AntPathRequestMatcher("/oauth/**")))
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/api/**"))
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/oauth/**")))
.authorizeRequests((requests) -> requests
.anyRequest().hasRole("USER"))
.httpBasic(withDefaults());

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;
@ -195,13 +195,13 @@ public class NamespaceHttpTests {
}
@Test // http@request-matcher-ref ant
public void configureWhenAntPatternMatchingThenAntPathRequestMatcherUsed() {
public void configureWhenAntPatternMatchingThenPathPatternRequestMatcherUsed() {
this.spring.register(RequestMatcherAntConfig.class).autowire();
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
.get(0);
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(PathPatternRequestMatcher.class);
}
@Test // http@request-matcher-ref regex
@ -226,21 +226,21 @@ public class NamespaceHttpTests {
}
@Test // http@security=none
public void configureWhenIgnoredAntPatternsThenAntPathRequestMatcherUsedWithNoFilters() {
public void configureWhenIgnoredAntPatternsThenPathPatternRequestMatcherUsedWithNoFilters() {
this.spring.register(SecurityNoneConfig.class).autowire();
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
.get(0);
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern())
.isEqualTo("/resources/**");
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(PathPatternRequestMatcher.class);
assertThat(securityFilterChain.getRequestMatcher())
.isEqualTo(PathPatternRequestMatcher.withDefaults().matcher("/resources/**"));
assertThat(securityFilterChain.getFilters()).isEmpty();
assertThat(filterChainProxy.getFilterChains().get(1)).isInstanceOf(DefaultSecurityFilterChain.class);
securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains().get(1);
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern())
.isEqualTo("/public/**");
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(PathPatternRequestMatcher.class);
assertThat(securityFilterChain.getRequestMatcher())
.isEqualTo(PathPatternRequestMatcher.withDefaults().matcher("/public/**"));
assertThat(securityFilterChain.getFilters()).isEmpty();
}
@ -482,7 +482,7 @@ public class NamespaceHttpTests {
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http
.securityMatcher(new AntPathRequestMatcher("/api/**"));
.securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/api/**"));
return http.build();
// @formatter:on
}
@ -534,8 +534,9 @@ public class NamespaceHttpTests {
@Bean
WebSecurityCustomizer webSecurityCustomizer() {
PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withDefaults();
return (web) -> web.ignoring()
.requestMatchers(new AntPathRequestMatcher("/resources/**"), new AntPathRequestMatcher("/public/**"));
.requestMatchers(builder.matcher("/resources/**"), builder.matcher("/public/**"));
}
@Bean

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

@ -37,17 +37,17 @@ import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandler;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.config.Customizer.withDefaults;
@ -130,8 +130,13 @@ public class WebSecurityTests {
static class MvcMatcherConfig {
@Bean
WebSecurityCustomizer webSecurityCustomizer(HandlerMappingIntrospector introspector) {
return (web) -> web.ignoring().requestMatchers(new MvcRequestMatcher(introspector, "/path"));
PathPatternRequestMatcherBuilderFactoryBean pathPatternRequestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
WebSecurityCustomizer webSecurityCustomizer(PathPatternRequestMatcher.Builder builder) {
return (web) -> web.ignoring().requestMatchers(builder.matcher("/path"));
}
@Bean
@ -168,9 +173,15 @@ public class WebSecurityTests {
static class MvcMatcherServletPathConfig {
@Bean
WebSecurityCustomizer webSecurityCustomizer(HandlerMappingIntrospector introspector) {
MvcRequestMatcher.Builder builder = new MvcRequestMatcher.Builder(introspector).servletPath("/spring");
return (web) -> web.ignoring().requestMatchers(builder.pattern("/path")).requestMatchers("/notused");
PathPatternRequestMatcherBuilderFactoryBean pathPatternRequestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
WebSecurityCustomizer webSecurityCustomizer(PathPatternRequestMatcher.Builder builder) {
return (web) -> web.ignoring()
.requestMatchers(builder.basePath("/spring").matcher("/path"))
.requestMatchers("/notused");
}
@Bean

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

@ -63,7 +63,6 @@ import org.springframework.security.web.access.RequestMatcherDelegatingWebInvoca
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.GetMapping;
@ -106,14 +105,13 @@ public class WebSecurityConfigurationTests {
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
List<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(PathPatternRequestMatcher.withDefaults().matcher("/role1/**"))
.authorizeRequests((authorize) -> authorize
.anyRequest().hasRole("1")
)
@ -433,7 +427,7 @@ public class WebSecurityConfigurationTests {
SecurityFilterChain filterChain2(HttpSecurity http) throws Exception {
// @formatter:off
return http
.securityMatcher(new AntPathRequestMatcher("/role2/**"))
.securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/role2/**"))
.authorizeRequests((authorize) -> authorize
.anyRequest().hasRole("2")
)
@ -446,7 +440,7 @@ public class WebSecurityConfigurationTests {
SecurityFilterChain filterChain3(HttpSecurity http) throws Exception {
// @formatter:off
return http
.securityMatcher(new AntPathRequestMatcher("/role3/**"))
.securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/role3/**"))
.authorizeRequests((authorize) -> authorize
.anyRequest().hasRole("3")
)
@ -477,7 +471,7 @@ public class WebSecurityConfigurationTests {
SecurityFilterChain securityFilterChain1(HttpSecurity http) throws Exception {
// @formatter:off
return http
.securityMatcher(new AntPathRequestMatcher("/role1/**"))
.securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/role1/**"))
.authorizeRequests((authorize) -> authorize
.anyRequest().hasRole("1")
)
@ -734,7 +728,7 @@ public class WebSecurityConfigurationTests {
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
return http
.securityMatcher(new AntPathRequestMatcher("/role1/**"))
.securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/role1/**"))
.authorizeRequests((authorize) -> authorize
.anyRequest().hasRole("1")
)
@ -773,7 +767,7 @@ public class WebSecurityConfigurationTests {
public SecurityFilterChain path1(HttpSecurity http) throws Exception {
// @formatter:off
http
.securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/path1/**")))
.securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/path1/**")))
.authorizeRequests((requests) -> requests.anyRequest().authenticated());
// @formatter:on
return http.build();
@ -797,7 +791,7 @@ public class WebSecurityConfigurationTests {
public SecurityFilterChain path1(HttpSecurity http) throws Exception {
// @formatter:off
http
.securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/path1/**")))
.securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/path1/**")))
.authorizeRequests((requests) -> requests.anyRequest().authenticated());
// @formatter:on
return http.build();
@ -822,7 +816,7 @@ public class WebSecurityConfigurationTests {
public SecurityFilterChain notAuthorized(HttpSecurity http) throws Exception {
// @formatter:off
http
.securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/user")))
.securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/user")))
.authorizeRequests((requests) -> requests.anyRequest().hasRole("USER"));
// @formatter:on
return http.build();
@ -833,7 +827,7 @@ public class WebSecurityConfigurationTests {
public SecurityFilterChain path1(HttpSecurity http) throws Exception {
// @formatter:off
http
.securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/admin")))
.securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/admin")))
.authorizeRequests((requests) -> requests.anyRequest().hasRole("ADMIN"));
// @formatter:on
return http.build();
@ -864,7 +858,7 @@ public class WebSecurityConfigurationTests {
public SecurityFilterChain notAuthorized(HttpSecurity http) throws Exception {
// @formatter:off
http
.securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/user")))
.securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/user")))
.authorizeRequests((requests) -> requests.anyRequest().hasRole("USER"));
// @formatter:on
return http.build();
@ -875,7 +869,7 @@ public class WebSecurityConfigurationTests {
public SecurityFilterChain admin(HttpSecurity http) throws Exception {
// @formatter:off
http
.securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/admin")))
.securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/admin")))
.authorizeRequests((requests) -> requests.anyRequest().hasRole("ADMIN"));
// @formatter:on
return http.build();

View File

@ -22,7 +22,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpMethod;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
@ -55,19 +55,20 @@ public class AbstractConfigAttributeRequestMatcherRegistryTests {
}
@Test
public void testGetRequestMatcherIsTypeAntPathRequestMatcher() {
public void testGetRequestMatcherIsTypePathPatternRequestMatcher() {
List<RequestMatcher> requestMatchers = this.registry
.requestMatchers(new AntPathRequestMatcher("/a.*", HttpMethod.GET.name()));
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/a.*"));
for (RequestMatcher requestMatcher : requestMatchers) {
assertThat(requestMatcher).isInstanceOf(AntPathRequestMatcher.class);
assertThat(requestMatcher).isInstanceOf(PathPatternRequestMatcher.class);
}
}
@Test
public void testRequestMatcherIsTypeAntPathRequestMatcher() {
List<RequestMatcher> requestMatchers = this.registry.requestMatchers(new AntPathRequestMatcher("/a.*"));
public void testRequestMatcherIsTypePathPatternRequestMatcher() {
List<RequestMatcher> requestMatchers = this.registry
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/a.*"));
for (RequestMatcher requestMatcher : requestMatchers) {
assertThat(requestMatcher).isInstanceOf(AntPathRequestMatcher.class);
assertThat(requestMatcher).isInstanceOf(PathPatternRequestMatcher.class);
}
}

View File

@ -68,7 +68,6 @@ import org.springframework.security.web.access.expression.WebExpressionAuthoriza
import org.springframework.security.web.access.intercept.AuthorizationFilter;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.test.web.servlet.MockMvc;
@ -81,7 +80,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -148,7 +146,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
public void configureWhenMvcMatcherAfterAnyRequestThenException() {
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> this.spring.register(AfterAnyRequestConfig.class).autowire())
.withMessageContaining("Can't configure mvcMatchers after anyRequest");
.withMessageContaining("Can't configure requestMatchers after anyRequest");
}
@Test
@ -689,7 +687,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
@Test
public void requestMatchersWhenMultipleDispatcherServletsAndPathBeanThenAllows() throws Exception {
this.spring.register(MvcRequestMatcherBuilderConfig.class, BasicController.class)
this.spring.register(PathPatternRequestMatcherBuilderConfig.class, BasicController.class)
.postProcessor((context) -> context.getServletContext()
.addServlet("otherDispatcherServlet", DispatcherServlet.class)
.addMapping("/mvc"))
@ -1063,13 +1061,16 @@ public class AuthorizeHttpRequestsConfigurerTests {
static class ServletPathConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
.servletPath("/spring");
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off
return http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(mvcMatcherBuilder.pattern("/")).hasRole("ADMIN")
.requestMatchers(builder.basePath("/spring").matcher("/")).hasRole("ADMIN")
)
.build();
// @formatter:on
@ -1358,7 +1359,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
@Configuration
@EnableWebSecurity
@EnableWebMvc
static class MvcRequestMatcherBuilderConfig {
static class PathPatternRequestMatcherBuilderConfig {
@Bean
SecurityFilterChain security(HttpSecurity http) throws Exception {

View File

@ -33,6 +33,7 @@ import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextImpl;
@ -42,13 +43,12 @@ import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.servlet.MockServletContext;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import org.springframework.web.util.pattern.PathPatternParser;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.spy;
@ -111,10 +111,12 @@ public class AuthorizeRequestsTests {
public void antMatchersPathVariables() throws Exception {
loadConfig(AntPatchersPathVariables.class);
this.request.setServletPath("/user/user");
this.request.setRequestURI("/user/user");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
this.setup();
this.request.setServletPath("/user/deny");
this.request.setRequestURI("/user/deny");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
@ -124,10 +126,12 @@ public class AuthorizeRequestsTests {
public void antMatchersPathVariablesCaseInsensitive() throws Exception {
loadConfig(AntPatchersPathVariables.class);
this.request.setServletPath("/USER/user");
this.request.setRequestURI("/USER/user");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
this.setup();
this.request.setServletPath("/USER/deny");
this.request.setRequestURI("/USER/deny");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
@ -137,10 +141,12 @@ public class AuthorizeRequestsTests {
public void antMatchersPathVariablesCaseInsensitiveCamelCaseVariables() throws Exception {
loadConfig(AntMatchersPathVariablesCamelCaseVariables.class);
this.request.setServletPath("/USER/user");
this.request.setRequestURI("/USER/user");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
this.setup();
this.request.setServletPath("/USER/deny");
this.request.setRequestURI("/USER/deny");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
@ -199,7 +205,7 @@ public class AuthorizeRequestsTests {
// @formatter:off
http
.authorizeRequests((requests) -> requests
.requestMatchers(new AntPathRequestMatcher("/**", HttpMethod.POST.name())).denyAll());
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/**")).denyAll());
// @formatter:on
return http.build();
}
@ -220,7 +226,7 @@ public class AuthorizeRequestsTests {
// @formatter:off
http
.authorizeRequests((authorize) -> authorize
.requestMatchers(new AntPathRequestMatcher("/**", HttpMethod.POST.name())).denyAll()
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/**")).denyAll()
);
// @formatter:on
return http.build();
@ -239,10 +245,13 @@ public class AuthorizeRequestsTests {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
PathPatternParser parser = new PathPatternParser();
parser.setCaseSensitive(false);
PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withPathPatternParser(parser);
// @formatter:off
http
.authorizeRequests((requests) -> requests
.requestMatchers(new AntPathRequestMatcher("/user/{user}", null, false)).access("#user == 'user'")
.requestMatchers(builder.matcher("/user/{user}")).access("#user == 'user'")
.anyRequest().denyAll());
// @formatter:on
return http.build();
@ -261,10 +270,13 @@ public class AuthorizeRequestsTests {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
PathPatternParser parser = new PathPatternParser();
parser.setCaseSensitive(false);
PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withPathPatternParser(parser);
// @formatter:off
http
.authorizeRequests((requests) -> requests
.requestMatchers(new AntPathRequestMatcher("/user/{userName}", null, false)).access("#userName == 'user'")
.requestMatchers(builder.matcher("/user/{userName}")).access("#userName == 'user'")
.anyRequest().denyAll());
// @formatter:on
return http.build();
@ -378,14 +390,18 @@ public class AuthorizeRequestsTests {
static class MvcMatcherServletPathConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
.servletPath("/spring");
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
PathPatternRequestMatcher.Builder spring = builder.basePath("/spring");
// @formatter:off
http
.httpBasic(withDefaults())
.authorizeRequests((requests) -> requests
.requestMatchers(mvcMatcherBuilder.pattern("/path")).denyAll());
.requestMatchers(spring.matcher("/path")).denyAll());
// @formatter:on
return http.build();
}
@ -413,14 +429,18 @@ public class AuthorizeRequestsTests {
static class MvcMatcherServletPathInLambdaConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
.servletPath("/spring");
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
PathPatternRequestMatcher.Builder spring = builder.basePath("/spring");
// @formatter:off
http
.httpBasic(withDefaults())
.authorizeRequests((authorize) -> authorize
.requestMatchers(mvcMatcherBuilder.pattern("/path")).denyAll()
.requestMatchers(spring.matcher("/path")).denyAll()
);
// @formatter:on
return http.build();

View File

@ -28,7 +28,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.RequestMapping;
@ -109,7 +109,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
// @formatter:off
http
.csrf((csrf) -> csrf
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/path"))
.requireCsrfProtectionMatcher(PathPatternRequestMatcher.withDefaults().matcher("/path"))
.ignoringRequestMatchers(this.requestMatcher));
return http.build();
// @formatter:on
@ -129,7 +129,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
// @formatter:off
http
.csrf((csrf) -> csrf
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/path"))
.requireCsrfProtectionMatcher(PathPatternRequestMatcher.withDefaults().matcher("/path"))
.ignoringRequestMatchers(this.requestMatcher)
);
return http.build();
@ -149,7 +149,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
// @formatter:off
http
.csrf((csrf) -> csrf
.ignoringRequestMatchers(new AntPathRequestMatcher("/no-csrf"))
.ignoringRequestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/no-csrf"))
.ignoringRequestMatchers(this.requestMatcher));
return http.build();
// @formatter:on
@ -169,7 +169,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
// @formatter:off
http
.csrf((csrf) -> csrf
.ignoringRequestMatchers(new AntPathRequestMatcher("/no-csrf"))
.ignoringRequestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/no-csrf"))
.ignoringRequestMatchers(this.requestMatcher)
);
return http.build();

View File

@ -57,7 +57,7 @@ import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler
import org.springframework.security.web.firewall.StrictHttpFirewall;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
@ -906,7 +906,7 @@ public class CsrfConfigurerTests {
http
.formLogin(withDefaults())
.logout((logout) -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")));
.logoutRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher("/logout")));
return http.build();
// @formatter:on
}

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,7 +32,7 @@ import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
@ -92,7 +92,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
.exceptionHandling((handling) -> handling
.defaultAccessDeniedHandlerFor(
this.teapotDeniedHandler,
new AntPathRequestMatcher("/hello/**"))
PathPatternRequestMatcher.withDefaults().matcher("/hello/**"))
.defaultAccessDeniedHandlerFor(
new AccessDeniedHandlerImpl(),
AnyRequestMatcher.INSTANCE));
@ -119,7 +119,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
.exceptionHandling((exceptionHandling) -> exceptionHandling
.defaultAccessDeniedHandlerFor(
this.teapotDeniedHandler,
new AntPathRequestMatcher("/hello/**")
PathPatternRequestMatcher.withDefaults().matcher("/hello/**")
)
.defaultAccessDeniedHandlerFor(
new AccessDeniedHandlerImpl(),
@ -148,7 +148,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
.exceptionHandling((handling) -> handling
.defaultAccessDeniedHandlerFor(
this.teapotDeniedHandler,
new AntPathRequestMatcher("/hello/**")));
PathPatternRequestMatcher.withDefaults().matcher("/hello/**")));
return http.build();
// @formatter:on
}

View File

@ -32,16 +32,16 @@ import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.config.Customizer.withDefaults;
@ -167,16 +167,20 @@ public class HttpSecurityRequestMatchersTests {
@EnableWebMvc
static class MultiMvcMatcherInLambdaConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
SecurityFilterChain first(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
SecurityFilterChain first(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off
http
.securityMatchers((requests) -> requests
.requestMatchers(mvcMatcherBuilder.pattern("/test-1"))
.requestMatchers(mvcMatcherBuilder.pattern("/test-2"))
.requestMatchers(mvcMatcherBuilder.pattern("/test-3"))
.requestMatchers(builder.matcher("/test-1"))
.requestMatchers(builder.matcher("/test-2"))
.requestMatchers(builder.matcher("/test-3"))
)
.authorizeRequests((authorize) -> authorize.anyRequest().denyAll())
.httpBasic(withDefaults());
@ -185,12 +189,11 @@ public class HttpSecurityRequestMatchersTests {
}
@Bean
SecurityFilterChain second(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
SecurityFilterChain second(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off
http
.securityMatchers((requests) -> requests
.requestMatchers(mvcMatcherBuilder.pattern("/test-1"))
.requestMatchers(builder.matcher("/test-1"))
)
.authorizeRequests((authorize) -> authorize
.anyRequest().permitAll()
@ -216,16 +219,20 @@ public class HttpSecurityRequestMatchersTests {
@EnableWebMvc
static class MultiMvcMatcherConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
SecurityFilterChain first(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
SecurityFilterChain first(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off
http
.securityMatchers((security) -> security
.requestMatchers(mvcMatcherBuilder.pattern("/test-1"))
.requestMatchers(mvcMatcherBuilder.pattern("/test-2"))
.requestMatchers(mvcMatcherBuilder.pattern("/test-3")))
.requestMatchers(builder.matcher("/test-1"))
.requestMatchers(builder.matcher("/test-2"))
.requestMatchers(builder.matcher("/test-3")))
.authorizeRequests((requests) -> requests
.anyRequest().denyAll())
.httpBasic(withDefaults());
@ -234,12 +241,11 @@ public class HttpSecurityRequestMatchersTests {
}
@Bean
SecurityFilterChain second(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
SecurityFilterChain second(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off
http
.securityMatchers((security) -> security
.requestMatchers(mvcMatcherBuilder.pattern("/test-1")))
.requestMatchers(builder.matcher("/test-1")))
.authorizeRequests((requests) -> requests
.anyRequest().permitAll());
// @formatter:on
@ -264,10 +270,15 @@ public class HttpSecurityRequestMatchersTests {
static class MvcMatcherConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off
http
.securityMatcher(new MvcRequestMatcher(introspector, "/path"))
.securityMatcher(builder.matcher("/path"))
.httpBasic(withDefaults())
.authorizeRequests((requests) -> requests
.anyRequest().denyAll());
@ -298,11 +309,16 @@ public class HttpSecurityRequestMatchersTests {
static class RequestMatchersMvcMatcherConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off
http
.securityMatchers((security) -> security
.requestMatchers(new MvcRequestMatcher(introspector, "/path")))
.requestMatchers(builder.matcher("/path")))
.httpBasic(withDefaults())
.authorizeRequests((requests) -> requests
.anyRequest().denyAll());
@ -333,11 +349,16 @@ public class HttpSecurityRequestMatchersTests {
static class RequestMatchersMvcMatcherInLambdaConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off
http
.securityMatchers((secure) -> secure
.requestMatchers(new MvcRequestMatcher(introspector, "/path"))
.requestMatchers(builder.matcher("/path"))
)
.httpBasic(withDefaults())
.authorizeRequests((authorize) -> authorize
@ -365,13 +386,16 @@ public class HttpSecurityRequestMatchersTests {
static class RequestMatchersMvcMatcherServeltPathConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
mvcMatcherBuilder.servletPath("/spring");
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off
http
.securityMatchers((security) -> security
.requestMatchers(mvcMatcherBuilder.pattern("/path"))
.requestMatchers(builder.basePath("/spring").matcher("/path"))
.requestMatchers("/never-match"))
.httpBasic(withDefaults())
.authorizeRequests((requests) -> requests
@ -403,13 +427,16 @@ public class HttpSecurityRequestMatchersTests {
static class RequestMatchersMvcMatcherServletPathInLambdaConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
mvcMatcherBuilder.servletPath("/spring");
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off
http
.securityMatchers((secure) -> secure
.requestMatchers(mvcMatcherBuilder.pattern("/path"))
.requestMatchers(builder.basePath("/spring").matcher("/path"))
.requestMatchers("/never-match")
)
.httpBasic(withDefaults())

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

@ -32,6 +32,7 @@ import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
@ -39,12 +40,11 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.servlet.MockServletContext;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.config.Customizer.withDefaults;
@ -356,14 +356,18 @@ public class HttpSecuritySecurityMatchersTests {
static class SecurityMatchersMvcMatcherServletPathConfig {
@Bean
SecurityFilterChain appSecurity(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
.servletPath("/spring");
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
SecurityFilterChain appSecurity(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
PathPatternRequestMatcher.Builder spring = builder.basePath("/spring");
// @formatter:off
http
.securityMatchers((security) -> security
.requestMatchers(mvcMatcherBuilder.pattern("/path"))
.requestMatchers(mvcMatcherBuilder.pattern("/never-match"))
.requestMatchers(spring.matcher("/path"))
.requestMatchers(spring.matcher("/never-match"))
)
.httpBasic(withDefaults())
.authorizeHttpRequests((authorize) -> authorize
@ -391,14 +395,18 @@ public class HttpSecuritySecurityMatchersTests {
static class SecurityMatchersMvcMatcherServletPathInLambdaConfig {
@Bean
SecurityFilterChain appSecurity(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
.servletPath("/spring");
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
SecurityFilterChain appSecurity(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
PathPatternRequestMatcher.Builder spring = builder.basePath("/spring");
// @formatter:off
http
.securityMatchers((matchers) -> matchers
.requestMatchers(mvcMatcherBuilder.pattern("/path"))
.requestMatchers(mvcMatcherBuilder.pattern("/never-match"))
.requestMatchers(spring.matcher("/path"))
.requestMatchers(spring.matcher("/never-match"))
)
.httpBasic(withDefaults())
.authorizeHttpRequests((authorize) -> authorize

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

@ -27,7 +27,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@ -79,9 +79,9 @@ public class RequestMatcherConfigurerTests {
// @formatter:off
http
.securityMatchers((security) -> security
.requestMatchers(new AntPathRequestMatcher("/api/**")))
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/api/**")))
.securityMatchers((security) -> security
.requestMatchers(new AntPathRequestMatcher("/oauth/**")))
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/oauth/**")))
.authorizeRequests((requests) -> requests
.anyRequest().denyAll());
return http.build();
@ -99,10 +99,10 @@ public class RequestMatcherConfigurerTests {
// @formatter:off
http
.securityMatchers((secure) -> secure
.requestMatchers(new AntPathRequestMatcher("/api/**"))
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/api/**"))
)
.securityMatchers((securityMatchers) -> securityMatchers
.requestMatchers(new AntPathRequestMatcher("/oauth/**"))
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/oauth/**"))
)
.authorizeRequests((authorize) -> authorize
.anyRequest().denyAll()

View File

@ -78,7 +78,7 @@ public class SessionManagementConfigurerServlet31Tests {
@Test
public void changeSessionIdThenPreserveParameters() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/login");
String id = request.getSession().getId();
request.getSession();
request.setServletPath("/login");

View File

@ -33,6 +33,7 @@ import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
@ -41,12 +42,11 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.servlet.MockServletContext;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.config.Customizer.withDefaults;
@ -131,14 +131,19 @@ public class UrlAuthorizationConfigurerTests {
@EnableWebMvc
static class MvcMatcherConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http, ApplicationContext context,
HandlerMappingIntrospector introspector) throws Exception {
PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off
http
.httpBasic(withDefaults())
.apply(new UrlAuthorizationConfigurer(context)).getRegistry()
.requestMatchers(new MvcRequestMatcher(introspector, "/path")).hasRole("ADMIN");
.requestMatchers(builder.matcher("/path")).hasRole("ADMIN");
// @formatter:on
return http.build();
}
@ -165,16 +170,20 @@ public class UrlAuthorizationConfigurerTests {
@EnableWebMvc
static class MvcMatcherServletPathConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean pathPattern() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http, ApplicationContext context,
HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher mvcRequestMatcher = new MvcRequestMatcher(introspector, "/path");
mvcRequestMatcher.setServletPath("/spring");
PathPatternRequestMatcher.Builder builder) throws Exception {
PathPatternRequestMatcher.Builder spring = builder.basePath("/spring");
// @formatter:off
http
.httpBasic(withDefaults())
.apply(new UrlAuthorizationConfigurer(context)).getRegistry()
.requestMatchers(mvcRequestMatcher).hasRole("ADMIN");
.requestMatchers(builder.matcher("/path")).hasRole("ADMIN");
// @formatter:on
return http.build();
}

View File

@ -185,7 +185,7 @@ public class OAuth2LoginConfigurerTests {
@BeforeEach
public void setup() {
this.request = new MockHttpServletRequest("GET", "");
this.request = new MockHttpServletRequest("GET", "/login/oauth2/code/google");
this.request.setServletPath("/login/oauth2/code/google");
this.response = new MockHttpServletResponse();
this.filterChain = new MockFilterChain();

View File

@ -38,6 +38,7 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockHttpSession;
@ -76,7 +77,7 @@ import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
@ -620,7 +621,7 @@ public class Saml2LogoutConfigurerTests {
.saml2Logout((saml2) -> saml2.addObjectPostProcessor(new ObjectPostProcessor<LogoutFilter>() {
@Override
public <O extends LogoutFilter> O postProcess(O filter) {
filter.setLogoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"));
filter.setLogoutRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/logout"));
return filter;
}
}));

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,12 +92,10 @@ 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'/>"
+ "<filter-security-metadata-source id='fids' use-expressions='false'>"
+ " <intercept-url pattern='${secure.url}' access='${secure.role}'/>"
+ "</filter-security-metadata-source>");
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>");
DefaultFilterInvocationSecurityMetadataSource fids = (DefaultFilterInvocationSecurityMetadataSource) this.appContext
.getBean("fids");
Collection<ConfigAttribute> cad = fids.getAttributes(createFilterInvocation("/secure", "GET"));
@ -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,7 @@ import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
/**
* @author Rob Winch
@ -44,7 +44,7 @@ public class CustomConfigurer extends SecurityConfigurerAdapter<DefaultSecurityF
// @formatter:off
http
.authorizeRequests((requests) -> requests
.requestMatchers(new AntPathRequestMatcher(this.permitAllPattern)).permitAll()
.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(this.permitAllPattern)).permitAll()
.anyRequest().authenticated());
// @formatter:on
if (http.getConfigurer(FormLoginConfigurer.class) == null) {

View File

@ -43,7 +43,7 @@ import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler
import org.springframework.security.web.csrf.CsrfTokenRequestHandler
import org.springframework.security.web.csrf.DefaultCsrfToken
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
import org.springframework.test.web.servlet.post
@ -176,7 +176,7 @@ class CsrfDslTests {
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
csrf {
requireCsrfProtectionMatcher = AntPathRequestMatcher("/test1")
requireCsrfProtectionMatcher = PathPatternRequestMatcher.withDefaults().matcher("/test1")
}
}
return http.build()
@ -247,8 +247,8 @@ class CsrfDslTests {
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
csrf {
requireCsrfProtectionMatcher = AntPathRequestMatcher("/**")
ignoringRequestMatchers(AntPathRequestMatcher("/test2"))
requireCsrfProtectionMatcher = PathPatternRequestMatcher.withDefaults().matcher("/**")
ignoringRequestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/test2"))
}
}
return http.build()
@ -279,7 +279,7 @@ class CsrfDslTests {
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
csrf {
requireCsrfProtectionMatcher = AntPathRequestMatcher("/**")
requireCsrfProtectionMatcher = PathPatternRequestMatcher.withDefaults().matcher("/**")
ignoringRequestMatchers("/test2")
}
}

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

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

View File

@ -43,7 +43,7 @@ http://www.springframework.org/schema/security https://www.springframework.org/s
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<import resource="handlermappingintrospector.xml"/>
<import resource="pathpatternrequestmatcherbuilder.xml"/>
</beans>

View File

@ -30,7 +30,7 @@
</http>
<b:import resource="CsrfConfigTests-shared-userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
<b:import resource="pathpatternrequestmatcherbuilder.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,12 @@
<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="builderRef" class="org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean"/>
<b:bean id="matcherRef" class="org.springframework.security.config.http.PathPatternRequestMatcherFactoryBean"
c:pattern="/foo" c:method="GET"/>
</b:beans>

View File

@ -33,15 +33,15 @@
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:bean name="error" class="org.springframework.security.config.http.InterceptUrlConfigTests.ErrorController"/>
<b:bean name="errorRequestMatcher" class="org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher">
<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>
<b:bean name="pathErrorRequestMatcher" class="org.springframework.security.web.util.matcher.AndRequestMatcher">
<b:constructor-arg>
<b:list>

View File

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

View File

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

View File

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

View File

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

View File

@ -33,15 +33,15 @@
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:bean name="error" class="org.springframework.security.config.http.InterceptUrlConfigTests.ErrorController"/>
<b:bean name="errorRequestMatcher" class="org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher">
<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>
<b:bean name="pathErrorRequestMatcher" class="org.springframework.security.web.util.matcher.AndRequestMatcher">
<b:constructor-arg>
<b:list>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -34,5 +34,5 @@
</b:bean>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
<b:import resource="pathpatternrequestmatcherbuilder.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,5 @@
<http pattern="/unprotected" security="none"/>
<b:import resource="userservice.xml"/>
<b:import resource="handlermappingintrospector.xml"/>
<b:import resource="pathpatternrequestmatcherbuilder.xml"/>
</b:beans>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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