mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-07 03:02:23 +00:00
Use PathPatternRequestMatcher in config
This commit changes the config module to use PathPatternRequestMatcher in favor of MvcRequestMatcher and AntPathRequestMatcher. This allows removing several HandlerMappingIntrospector support classes as well which were in place to support MvcRequestMatcher. Issue gh-16886 Issue gh-16887
This commit is contained in:
parent
f709a9efef
commit
3e53cc2c4a
@ -18,41 +18,20 @@ package org.springframework.security.config.annotation.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.ServletRegistration;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.config.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.web.ServletRegistrationsSupport.RegistrationMapping;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* A base class for registering {@link RequestMatcher}'s. For example, it might allow for
|
||||
@ -65,23 +44,12 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
*/
|
||||
public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
|
||||
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
|
||||
|
||||
private static final boolean mvcPresent;
|
||||
|
||||
private static final RequestMatcher ANY_REQUEST = AnyRequestMatcher.INSTANCE;
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
private boolean anyRequestConfigured = false;
|
||||
|
||||
static {
|
||||
mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR,
|
||||
AbstractRequestMatcherRegistry.class.getClassLoader());
|
||||
}
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected final void setApplicationContext(ApplicationContext context) {
|
||||
@ -107,40 +75,6 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
return configurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link MvcRequestMatcher} instances for the method and patterns passed in
|
||||
* @param method the HTTP method to use or null if any should be used
|
||||
* @param mvcPatterns the Spring MVC patterns to match on
|
||||
* @return a List of {@link MvcRequestMatcher} instances
|
||||
* @deprecated Please use
|
||||
* {@link org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.Builder}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
protected final List<MvcRequestMatcher> createMvcMatchers(HttpMethod method, String... mvcPatterns) {
|
||||
Assert.state(!this.anyRequestConfigured, "Can't configure mvcMatchers after anyRequest");
|
||||
ResolvableType type = ResolvableType.forClassWithGenerics(ObjectPostProcessor.class, Object.class);
|
||||
ObjectProvider<ObjectPostProcessor<Object>> postProcessors = this.context.getBeanProvider(type);
|
||||
ObjectPostProcessor<Object> opp = postProcessors.getObject();
|
||||
if (!this.context.containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
|
||||
throw new NoSuchBeanDefinitionException("A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME
|
||||
+ " of type " + HandlerMappingIntrospector.class.getName()
|
||||
+ " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext.");
|
||||
}
|
||||
HandlerMappingIntrospector introspector = this.context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME,
|
||||
HandlerMappingIntrospector.class);
|
||||
List<MvcRequestMatcher> matchers = new ArrayList<>(mvcPatterns.length);
|
||||
for (String mvcPattern : mvcPatterns) {
|
||||
MvcRequestMatcher matcher = new MvcRequestMatcher(introspector, mvcPattern);
|
||||
opp.postProcess(matcher);
|
||||
if (method != null) {
|
||||
matcher.setMethod(method);
|
||||
}
|
||||
matchers.add(matcher);
|
||||
}
|
||||
return matchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of
|
||||
* {@link org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher}
|
||||
@ -184,12 +118,9 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an
|
||||
* {@link MvcRequestMatcher} that also specifies a specific {@link HttpMethod} to
|
||||
* match on. This matcher will use the same rules that Spring MVC uses for matching.
|
||||
* For example, often times a mapping of the path "/path" will match on "/path",
|
||||
* "/path/", "/path.html", etc. If the {@link HandlerMappingIntrospector} is not
|
||||
* available, maps to an {@link AntPathRequestMatcher}.
|
||||
* Match when the {@link HttpMethod} is {@code method} and when the request URI
|
||||
* matches one of {@code patterns}. See
|
||||
* {@link org.springframework.web.util.pattern.PathPattern} for matching rules.
|
||||
* </p>
|
||||
* <p>
|
||||
* If a specific {@link RequestMatcher} must be specified, use
|
||||
@ -197,8 +128,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
* </p>
|
||||
* @param method the {@link HttpMethod} to use or {@code null} for any
|
||||
* {@link HttpMethod}.
|
||||
* @param patterns the patterns to match on. The rules for matching are defined by
|
||||
* Spring MVC if {@link MvcRequestMatcher} is used
|
||||
* @param patterns the patterns to match on
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}.
|
||||
* @since 5.8
|
||||
*/
|
||||
@ -209,27 +139,11 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
+ "leading slash in all your request matcher patterns. In future versions of "
|
||||
+ "Spring Security, leaving out the leading slash will result in an exception.");
|
||||
}
|
||||
if (!mvcPresent) {
|
||||
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
|
||||
}
|
||||
if (!(this.context instanceof WebApplicationContext)) {
|
||||
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
|
||||
}
|
||||
WebApplicationContext context = (WebApplicationContext) this.context;
|
||||
ServletContext servletContext = context.getServletContext();
|
||||
if (servletContext == null) {
|
||||
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
|
||||
}
|
||||
Assert.state(!this.anyRequestConfigured, "Can't configure requestMatchers after anyRequest");
|
||||
PathPatternRequestMatcher.Builder builder = this.context.getBean(PathPatternRequestMatcher.Builder.class);
|
||||
List<RequestMatcher> matchers = new ArrayList<>();
|
||||
for (String pattern : patterns) {
|
||||
if (RequestMatcherFactory.usesPathPatterns()) {
|
||||
matchers.add(RequestMatcherFactory.matcher(method, pattern));
|
||||
}
|
||||
else {
|
||||
AntPathRequestMatcher ant = new AntPathRequestMatcher(pattern, (method != null) ? method.name() : null);
|
||||
MvcRequestMatcher mvc = createMvcMatchers(method, pattern).get(0);
|
||||
matchers.add(new DeferredRequestMatcher((c) -> resolve(ant, mvc, c), mvc, ant));
|
||||
}
|
||||
matchers.add(builder.matcher(method, pattern));
|
||||
}
|
||||
return requestMatchers(matchers.toArray(new RequestMatcher[0]));
|
||||
}
|
||||
@ -243,64 +157,16 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
return false;
|
||||
}
|
||||
|
||||
private RequestMatcher resolve(AntPathRequestMatcher ant, MvcRequestMatcher mvc, ServletContext servletContext) {
|
||||
ServletRegistrationsSupport registrations = new ServletRegistrationsSupport(servletContext);
|
||||
Collection<RegistrationMapping> mappings = registrations.mappings();
|
||||
if (mappings.isEmpty()) {
|
||||
return new DispatcherServletDelegatingRequestMatcher(ant, mvc, new MockMvcRequestMatcher());
|
||||
}
|
||||
Collection<RegistrationMapping> dispatcherServletMappings = registrations.dispatcherServletMappings();
|
||||
if (dispatcherServletMappings.isEmpty()) {
|
||||
return new DispatcherServletDelegatingRequestMatcher(ant, mvc, new MockMvcRequestMatcher());
|
||||
}
|
||||
if (dispatcherServletMappings.size() > 1) {
|
||||
String errorMessage = computeErrorMessage(servletContext.getServletRegistrations().values());
|
||||
throw new IllegalArgumentException(errorMessage);
|
||||
}
|
||||
RegistrationMapping dispatcherServlet = dispatcherServletMappings.iterator().next();
|
||||
if (mappings.size() > 1 && !dispatcherServlet.isDefault()) {
|
||||
String errorMessage = computeErrorMessage(servletContext.getServletRegistrations().values());
|
||||
throw new IllegalArgumentException(errorMessage);
|
||||
}
|
||||
if (dispatcherServlet.isDefault()) {
|
||||
if (mappings.size() == 1) {
|
||||
return mvc;
|
||||
}
|
||||
return new DispatcherServletDelegatingRequestMatcher(ant, mvc);
|
||||
}
|
||||
return mvc;
|
||||
}
|
||||
|
||||
private static String computeErrorMessage(Collection<? extends ServletRegistration> registrations) {
|
||||
String template = """
|
||||
This method cannot decide whether these patterns are Spring MVC patterns or not. \
|
||||
This is because there is more than one mappable servlet in your servlet context: %s.
|
||||
|
||||
To address this, please create one PathPatternRequestMatcher.Builder#servletPath for each servlet that has \
|
||||
authorized endpoints and use them to construct request matchers manually.
|
||||
""";
|
||||
Map<String, Collection<String>> mappings = new LinkedHashMap<>();
|
||||
for (ServletRegistration registration : registrations) {
|
||||
mappings.put(registration.getClassName(), registration.getMappings());
|
||||
}
|
||||
return String.format(template, mappings);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an
|
||||
* {@link MvcRequestMatcher} that does not care which {@link HttpMethod} is used. This
|
||||
* matcher will use the same rules that Spring MVC uses for matching. For example,
|
||||
* often times a mapping of the path "/path" will match on "/path", "/path/",
|
||||
* "/path.html", etc. If the {@link HandlerMappingIntrospector} is not available, maps
|
||||
* to an {@link AntPathRequestMatcher}.
|
||||
* Match when the request URI matches one of {@code patterns}. See
|
||||
* {@link org.springframework.web.util.pattern.PathPattern} for matching rules.
|
||||
* </p>
|
||||
* <p>
|
||||
* If a specific {@link RequestMatcher} must be specified, use
|
||||
* {@link #requestMatchers(RequestMatcher...)} instead
|
||||
* </p>
|
||||
* @param patterns the patterns to match on. The rules for matching are defined by
|
||||
* Spring MVC if {@link MvcRequestMatcher} is used
|
||||
* @param patterns the patterns to match on
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}.
|
||||
* @since 5.8
|
||||
*/
|
||||
@ -310,12 +176,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an
|
||||
* {@link MvcRequestMatcher} that matches on a specific {@link HttpMethod}. This
|
||||
* matcher will use the same rules that Spring MVC uses for matching. For example,
|
||||
* often times a mapping of the path "/path" will match on "/path", "/path/",
|
||||
* "/path.html", etc. If the {@link HandlerMappingIntrospector} is not available, maps
|
||||
* to an {@link AntPathRequestMatcher}.
|
||||
* Match when the {@link HttpMethod} is {@code method}
|
||||
* </p>
|
||||
* <p>
|
||||
* If a specific {@link RequestMatcher} must be specified, use
|
||||
@ -339,182 +200,4 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
*/
|
||||
protected abstract C chainRequestMatchers(List<RequestMatcher> requestMatchers);
|
||||
|
||||
/**
|
||||
* Utilities for creating {@link RequestMatcher} instances.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
private static final class RequestMatchers {
|
||||
|
||||
private RequestMatchers() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link List} of {@link AntPathRequestMatcher} instances.
|
||||
* @param httpMethod the {@link HttpMethod} to use or {@code null} for any
|
||||
* {@link HttpMethod}.
|
||||
* @param antPatterns the ant patterns to create {@link AntPathRequestMatcher}
|
||||
* from
|
||||
* @return a {@link List} of {@link AntPathRequestMatcher} instances
|
||||
*/
|
||||
static List<RequestMatcher> antMatchers(HttpMethod httpMethod, String... antPatterns) {
|
||||
return Arrays.asList(antMatchersAsArray(httpMethod, antPatterns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link List} of {@link AntPathRequestMatcher} instances that do not
|
||||
* specify an {@link HttpMethod}.
|
||||
* @param antPatterns the ant patterns to create {@link AntPathRequestMatcher}
|
||||
* from
|
||||
* @return a {@link List} of {@link AntPathRequestMatcher} instances
|
||||
*/
|
||||
static List<RequestMatcher> antMatchers(String... antPatterns) {
|
||||
return antMatchers(null, antPatterns);
|
||||
}
|
||||
|
||||
static RequestMatcher[] antMatchersAsArray(HttpMethod httpMethod, String... antPatterns) {
|
||||
String method = (httpMethod != null) ? httpMethod.toString() : null;
|
||||
RequestMatcher[] matchers = new RequestMatcher[antPatterns.length];
|
||||
for (int index = 0; index < antPatterns.length; index++) {
|
||||
matchers[index] = new AntPathRequestMatcher(antPatterns[index], method);
|
||||
}
|
||||
return matchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link List} of {@link RegexRequestMatcher} instances.
|
||||
* @param httpMethod the {@link HttpMethod} to use or {@code null} for any
|
||||
* {@link HttpMethod}.
|
||||
* @param regexPatterns the regular expressions to create
|
||||
* {@link RegexRequestMatcher} from
|
||||
* @return a {@link List} of {@link RegexRequestMatcher} instances
|
||||
*/
|
||||
static List<RequestMatcher> regexMatchers(HttpMethod httpMethod, String... regexPatterns) {
|
||||
String method = (httpMethod != null) ? httpMethod.toString() : null;
|
||||
List<RequestMatcher> matchers = new ArrayList<>();
|
||||
for (String pattern : regexPatterns) {
|
||||
matchers.add(new RegexRequestMatcher(pattern, method));
|
||||
}
|
||||
return matchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link List} of {@link RegexRequestMatcher} instances that do not
|
||||
* specify an {@link HttpMethod}.
|
||||
* @param regexPatterns the regular expressions to create
|
||||
* {@link RegexRequestMatcher} from
|
||||
* @return a {@link List} of {@link RegexRequestMatcher} instances
|
||||
*/
|
||||
static List<RequestMatcher> regexMatchers(String... regexPatterns) {
|
||||
return regexMatchers(null, regexPatterns);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class DeferredRequestMatcher implements RequestMatcher {
|
||||
|
||||
final Function<ServletContext, RequestMatcher> requestMatcherFactory;
|
||||
|
||||
final AtomicReference<String> description = new AtomicReference<>();
|
||||
|
||||
final Map<ServletContext, RequestMatcher> requestMatchers = new ConcurrentHashMap<>();
|
||||
|
||||
DeferredRequestMatcher(Function<ServletContext, RequestMatcher> resolver, RequestMatcher... candidates) {
|
||||
this.requestMatcherFactory = (sc) -> this.requestMatchers.computeIfAbsent(sc, resolver);
|
||||
this.description.set("Deferred " + Arrays.toString(candidates));
|
||||
}
|
||||
|
||||
RequestMatcher requestMatcher(ServletContext servletContext) {
|
||||
return this.requestMatcherFactory.apply(servletContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
return this.requestMatcherFactory.apply(request.getServletContext()).matches(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MatchResult matcher(HttpServletRequest request) {
|
||||
return this.requestMatcherFactory.apply(request.getServletContext()).matcher(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.description.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MockMvcRequestMatcher implements RequestMatcher {
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
return request.getAttribute("org.springframework.test.web.servlet.MockMvc.MVC_RESULT_ATTRIBUTE") != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class DispatcherServletRequestMatcher implements RequestMatcher {
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
String name = request.getHttpServletMapping().getServletName();
|
||||
ServletRegistration registration = request.getServletContext().getServletRegistration(name);
|
||||
Assert.notNull(registration,
|
||||
() -> computeErrorMessage(request.getServletContext().getServletRegistrations().values()));
|
||||
try {
|
||||
Class<?> clazz = Class.forName(registration.getClassName());
|
||||
return DispatcherServlet.class.isAssignableFrom(clazz);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class DispatcherServletDelegatingRequestMatcher implements RequestMatcher {
|
||||
|
||||
private final AntPathRequestMatcher ant;
|
||||
|
||||
private final MvcRequestMatcher mvc;
|
||||
|
||||
private final RequestMatcher dispatcherServlet;
|
||||
|
||||
DispatcherServletDelegatingRequestMatcher(AntPathRequestMatcher ant, MvcRequestMatcher mvc) {
|
||||
this(ant, mvc, new OrRequestMatcher(new MockMvcRequestMatcher(), new DispatcherServletRequestMatcher()));
|
||||
}
|
||||
|
||||
DispatcherServletDelegatingRequestMatcher(AntPathRequestMatcher ant, MvcRequestMatcher mvc,
|
||||
RequestMatcher dispatcherServlet) {
|
||||
this.ant = ant;
|
||||
this.mvc = mvc;
|
||||
this.dispatcherServlet = dispatcherServlet;
|
||||
}
|
||||
|
||||
RequestMatcher requestMatcher(HttpServletRequest request) {
|
||||
if (this.dispatcherServlet.matches(request)) {
|
||||
return this.mvc;
|
||||
}
|
||||
return this.ant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
return requestMatcher(request).matches(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MatchResult matcher(HttpServletRequest request) {
|
||||
return requestMatcher(request).matcher(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DispatcherServletDelegating [" + "ant = " + this.ant + ", mvc = " + this.mvc + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
/**
|
||||
* This utility exists only to facilitate applications opting into using path patterns in
|
||||
* the HttpSecurity DSL. It is for internal use only.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public final class RequestMatcherFactory {
|
||||
|
||||
private static PathPatternRequestMatcher.Builder builder;
|
||||
|
||||
public static void setApplicationContext(ApplicationContext context) {
|
||||
builder = context.getBeanProvider(PathPatternRequestMatcher.Builder.class).getIfUnique();
|
||||
}
|
||||
|
||||
public static boolean usesPathPatterns() {
|
||||
return builder != null;
|
||||
}
|
||||
|
||||
public static RequestMatcher matcher(String path) {
|
||||
return matcher(null, path);
|
||||
}
|
||||
|
||||
public static RequestMatcher matcher(HttpMethod method, String path) {
|
||||
if (builder != null) {
|
||||
return builder.matcher(method, path);
|
||||
}
|
||||
return new AntPathRequestMatcher(path, (method != null) ? method.name() : null);
|
||||
}
|
||||
|
||||
private RequestMatcherFactory() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -28,7 +28,6 @@ import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.OrderComparator;
|
||||
@ -45,7 +44,6 @@ import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
|
||||
import org.springframework.security.config.annotation.web.configurers.AnonymousConfigurer;
|
||||
@ -91,17 +89,14 @@ import org.springframework.security.web.PortMapperImpl;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.session.HttpSessionEventPublisher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* A {@link HttpSecurity} is similar to Spring Security's XML <http> element in the
|
||||
@ -153,12 +148,6 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
|
||||
implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
|
||||
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
|
||||
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
|
||||
|
||||
private static final boolean mvcPresent;
|
||||
|
||||
private final RequestMatcherConfigurer requestMatcherConfigurer;
|
||||
|
||||
private List<OrderedFilter> filters = new ArrayList<>();
|
||||
@ -169,10 +158,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
static {
|
||||
mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, HttpSecurity.class.getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} that should be used
|
||||
@ -303,9 +288,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
/**
|
||||
* Adds a {@link CorsFilter} to be used. If a bean by the name of corsFilter is
|
||||
* provided, that {@link CorsFilter} is used. Else if corsConfigurationSource is
|
||||
* defined, then that {@link CorsConfiguration} is used. Otherwise, if Spring MVC is
|
||||
* on the classpath a {@link HandlerMappingIntrospector} is used. You can enable CORS
|
||||
* using:
|
||||
* defined, then that {@link CorsConfiguration} is used. You can enable CORS using:
|
||||
*
|
||||
* <pre>
|
||||
* @Configuration
|
||||
@ -2174,7 +2157,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* {@link #securityMatchers()}
|
||||
* </p>
|
||||
* @param requestMatcher the {@link RequestMatcher} to use, for example,
|
||||
* {@code PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/admin/**")}
|
||||
* {@code PathPatternRequestMatcher.pathPattern(HttpMethod.GET, "/admin/**")}
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
* @see #securityMatcher(String...)
|
||||
*/
|
||||
@ -2185,10 +2168,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
|
||||
/**
|
||||
* Allows configuring the {@link HttpSecurity} to only be invoked when matching the
|
||||
* provided pattern. This method creates a {@link MvcRequestMatcher} if Spring MVC is
|
||||
* in the classpath or creates an {@link AntPathRequestMatcher} if not. If more
|
||||
* advanced configuration is necessary, consider using
|
||||
* {@link #securityMatchers(Customizer)} or {@link #securityMatcher(RequestMatcher)}.
|
||||
* provided set of {@code patterns}. See
|
||||
* {@link org.springframework.web.util.pattern.PathPattern} for matching rules
|
||||
*
|
||||
* <p>
|
||||
* Invoking {@link #securityMatcher(String...)} will override previous invocations of
|
||||
@ -2198,19 +2179,14 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* </p>
|
||||
* @param patterns the pattern to match on (i.e. "/admin/**")
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
* @see AntPathRequestMatcher
|
||||
* @see MvcRequestMatcher
|
||||
* @see org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher
|
||||
* @see org.springframework.web.util.pattern.PathPattern
|
||||
*/
|
||||
public HttpSecurity securityMatcher(String... patterns) {
|
||||
List<RequestMatcher> matchers = new ArrayList<>();
|
||||
PathPatternRequestMatcher.Builder builder = getContext().getBean(PathPatternRequestMatcher.Builder.class);
|
||||
for (String pattern : patterns) {
|
||||
if (RequestMatcherFactory.usesPathPatterns()) {
|
||||
matchers.add(RequestMatcherFactory.matcher(pattern));
|
||||
}
|
||||
else {
|
||||
RequestMatcher matcher = mvcPresent ? createMvcMatcher(pattern) : createAntMatcher(pattern);
|
||||
matchers.add(matcher);
|
||||
}
|
||||
matchers.add(builder.matcher(pattern));
|
||||
}
|
||||
this.requestMatcher = new OrRequestMatcher(matchers);
|
||||
return this;
|
||||
@ -2241,26 +2217,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
return HttpSecurity.this;
|
||||
}
|
||||
|
||||
private RequestMatcher createAntMatcher(String pattern) {
|
||||
return new AntPathRequestMatcher(pattern);
|
||||
}
|
||||
|
||||
private RequestMatcher createMvcMatcher(String mvcPattern) {
|
||||
ResolvableType type = ResolvableType.forClassWithGenerics(ObjectPostProcessor.class, Object.class);
|
||||
ObjectProvider<ObjectPostProcessor<Object>> postProcessors = getContext().getBeanProvider(type);
|
||||
ObjectPostProcessor<Object> opp = postProcessors.getObject();
|
||||
if (!getContext().containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
|
||||
throw new NoSuchBeanDefinitionException("A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME
|
||||
+ " of type " + HandlerMappingIntrospector.class.getName()
|
||||
+ " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext.");
|
||||
}
|
||||
HandlerMappingIntrospector introspector = getContext().getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME,
|
||||
HandlerMappingIntrospector.class);
|
||||
MvcRequestMatcher matcher = new MvcRequestMatcher(introspector, mvcPattern);
|
||||
opp.postProcess(matcher);
|
||||
return matcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the {@link SecurityConfigurer} has already been specified get the original,
|
||||
* otherwise apply the new {@link SecurityConfigurerAdapter}.
|
||||
|
@ -55,6 +55,7 @@ import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer;
|
||||
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.PathPatternRequestTransformer;
|
||||
import org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
||||
@ -422,7 +423,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
this.filterChainDecoratorPostProcessor = postProcessor.getIfUnique(ObjectPostProcessor::identity);
|
||||
Class<HttpServletRequestTransformer> requestTransformerClass = HttpServletRequestTransformer.class;
|
||||
this.privilegeEvaluatorRequestTransformer = applicationContext.getBeanProvider(requestTransformerClass)
|
||||
.getIfUnique();
|
||||
.getIfUnique(PathPatternRequestTransformer::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,7 +35,6 @@ import org.springframework.security.config.annotation.authentication.configurati
|
||||
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.provisioning.JdbcUserDetailsManagerConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer;
|
||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.DefaultLoginPageConfigurer;
|
||||
@ -105,7 +104,6 @@ class HttpSecurityConfiguration {
|
||||
@Bean(HTTPSECURITY_BEAN_NAME)
|
||||
@Scope("prototype")
|
||||
HttpSecurity httpSecurity() throws Exception {
|
||||
RequestMatcherFactory.setApplicationContext(this.context);
|
||||
LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context);
|
||||
AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(
|
||||
this.objectPostProcessor, passwordEncoder);
|
||||
|
@ -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
|
||||
|
@ -42,6 +42,7 @@ import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.Fallback;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
@ -57,6 +58,7 @@ import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.crypto.RsaKeyConversionServicePostProcessor;
|
||||
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
|
||||
import org.springframework.security.context.DelegatingApplicationListener;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
@ -69,7 +71,6 @@ import org.springframework.security.web.firewall.HttpFirewall;
|
||||
import org.springframework.security.web.firewall.RequestRejectedHandler;
|
||||
import org.springframework.web.filter.CompositeFilter;
|
||||
import org.springframework.web.filter.ServletRequestPathFilter;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web
|
||||
@ -143,6 +144,12 @@ public class WebSecurityConfiguration implements ImportAware {
|
||||
return this.webSecurity.getPrivilegeEvaluator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Fallback
|
||||
public PathPatternRequestMatcherBuilderFactoryBean pathPatternRequestMatcherBuilder() {
|
||||
return new PathPatternRequestMatcherBuilderFactoryBean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>}
|
||||
* instances used to create the web configuration.
|
||||
@ -209,12 +216,11 @@ public class WebSecurityConfiguration implements ImportAware {
|
||||
/**
|
||||
* Used to ensure Spring MVC request matching is cached.
|
||||
*
|
||||
* Creates a {@link BeanDefinitionRegistryPostProcessor} that detects if a bean named
|
||||
* HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME is defined. If so, it moves the
|
||||
* Creates a {@link BeanDefinitionRegistryPostProcessor} that moves the
|
||||
* AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME to another bean name
|
||||
* and then adds a {@link CompositeFilter} that contains
|
||||
* {@link HandlerMappingIntrospector#createCacheFilter()} and the original
|
||||
* FilterChainProxy under the original Bean name.
|
||||
* {@link ServletRequestPathFilter} and the original FilterChainProxy under the
|
||||
* original Bean name.
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
|
@ -25,6 +25,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
|
||||
/**
|
||||
* Adds a convenient base class for {@link SecurityConfigurer} instances that operate on
|
||||
@ -38,6 +39,8 @@ public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T,
|
||||
|
||||
private SecurityContextHolderStrategy securityContextHolderStrategy;
|
||||
|
||||
private PathPatternRequestMatcher.Builder requestMatcherBuilder;
|
||||
|
||||
/**
|
||||
* Disables the {@link AbstractHttpConfigurer} by removing it. After doing so a fresh
|
||||
* version of the configuration can be applied.
|
||||
@ -65,4 +68,13 @@ public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T,
|
||||
return this.securityContextHolderStrategy;
|
||||
}
|
||||
|
||||
protected PathPatternRequestMatcher.Builder getRequestMatcherBuilder() {
|
||||
if (this.requestMatcherBuilder != null) {
|
||||
return this.requestMatcherBuilder;
|
||||
}
|
||||
ApplicationContext context = getBuilder().getSharedObject(ApplicationContext.class);
|
||||
this.requestMatcherBuilder = context.getBean(PathPatternRequestMatcher.Builder.class);
|
||||
return this.requestMatcherBuilder;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -19,7 +19,6 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
@ -236,7 +235,7 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
|
||||
@Override
|
||||
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
|
||||
return RequestMatcherFactory.matcher(HttpMethod.POST, loginProcessingUrl);
|
||||
return getRequestMatcherBuilder().matcher(HttpMethod.POST, loginProcessingUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,7 +26,6 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
|
||||
@ -146,7 +145,7 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* (i.e. log out) to protect against
|
||||
* <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF
|
||||
* attacks</a>. If you really want to use an HTTP GET, you can use
|
||||
* <code>logoutRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GEt, logoutUrl));</code>
|
||||
* <code>logoutRequestMatcher(PathPatternRequestMatcher.pathPattern(HttpMethod.GEt, logoutUrl));</code>
|
||||
* </p>
|
||||
* @param logoutUrl the URL that will invoke logout.
|
||||
* @return the {@link LogoutConfigurer} for further customization
|
||||
@ -370,7 +369,7 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
}
|
||||
|
||||
private RequestMatcher createLogoutRequestMatcher(String httpMethod) {
|
||||
return RequestMatcherFactory.matcher(HttpMethod.valueOf(httpMethod), this.logoutUrl);
|
||||
return getRequestMatcherBuilder().matcher(HttpMethod.valueOf(httpMethod), this.logoutUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||
import org.springframework.security.web.RequestMatcherRedirectFilter;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.util.Assert;
|
||||
@ -55,7 +54,7 @@ public final class PasswordManagementConfigurer<B extends HttpSecurityBuilder<B>
|
||||
@Override
|
||||
public void configure(B http) throws Exception {
|
||||
RequestMatcherRedirectFilter changePasswordFilter = new RequestMatcherRedirectFilter(
|
||||
RequestMatcherFactory.matcher(WELL_KNOWN_CHANGE_PASSWORD_PATTERN), this.changePasswordPage);
|
||||
getRequestMatcherBuilder().matcher(WELL_KNOWN_CHANGE_PASSWORD_PATTERN), this.changePasswordPage);
|
||||
http.addFilterBefore(postProcess(changePasswordFilter), UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
|
||||
|
@ -24,14 +24,12 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.NullRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
|
||||
@ -151,7 +149,7 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
boolean isCsrfEnabled = http.getConfigurer(CsrfConfigurer.class) != null;
|
||||
List<RequestMatcher> matchers = new ArrayList<>();
|
||||
if (isCsrfEnabled) {
|
||||
RequestMatcher getRequests = RequestMatcherFactory.matcher(HttpMethod.GET, "/**");
|
||||
RequestMatcher getRequests = getRequestMatcherBuilder().matcher(HttpMethod.GET, "/**");
|
||||
matchers.add(0, getRequests);
|
||||
}
|
||||
matchers.add(notFavIcon);
|
||||
@ -174,12 +172,7 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
}
|
||||
|
||||
private RequestMatcher getFaviconRequestMatcher() {
|
||||
if (RequestMatcherFactory.usesPathPatterns()) {
|
||||
return RequestMatcherFactory.matcher("/favicon.*");
|
||||
}
|
||||
else {
|
||||
return new AntPathRequestMatcher("/**/favicon.*");
|
||||
}
|
||||
return getRequestMatcherBuilder().matcher("/favicon.*");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ import org.springframework.security.authentication.ott.OneTimeTokenAuthenticatio
|
||||
import org.springframework.security.authentication.ott.OneTimeTokenService;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
|
||||
@ -122,12 +121,15 @@ public final class OneTimeTokenLoginConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
private GenerateOneTimeTokenRequestResolver requestResolver;
|
||||
|
||||
public OneTimeTokenLoginConfigurer(ApplicationContext context) {
|
||||
super(new OneTimeTokenAuthenticationFilter(), OneTimeTokenAuthenticationFilter.DEFAULT_LOGIN_PROCESSING_URL);
|
||||
super(new OneTimeTokenAuthenticationFilter(), null);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(H http) throws Exception {
|
||||
if (getLoginProcessingUrl() == null) {
|
||||
loginProcessingUrl(OneTimeTokenAuthenticationFilter.DEFAULT_LOGIN_PROCESSING_URL);
|
||||
}
|
||||
super.init(http);
|
||||
AuthenticationProvider authenticationProvider = getAuthenticationProvider();
|
||||
http.authenticationProvider(postProcess(authenticationProvider));
|
||||
@ -162,7 +164,7 @@ public final class OneTimeTokenLoginConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
private void configureOttGenerateFilter(H http) {
|
||||
GenerateOneTimeTokenFilter generateFilter = new GenerateOneTimeTokenFilter(getOneTimeTokenService(),
|
||||
getOneTimeTokenGenerationSuccessHandler());
|
||||
generateFilter.setRequestMatcher(RequestMatcherFactory.matcher(HttpMethod.POST, this.tokenGeneratingUrl));
|
||||
generateFilter.setRequestMatcher(getRequestMatcherBuilder().matcher(HttpMethod.POST, this.tokenGeneratingUrl));
|
||||
generateFilter.setRequestResolver(getGenerateRequestResolver());
|
||||
http.addFilter(postProcess(generateFilter));
|
||||
http.addFilter(DefaultResourcesFilter.css());
|
||||
@ -189,7 +191,7 @@ public final class OneTimeTokenLoginConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
}
|
||||
DefaultOneTimeTokenSubmitPageGeneratingFilter submitPage = new DefaultOneTimeTokenSubmitPageGeneratingFilter();
|
||||
submitPage.setResolveHiddenInputs(this::hiddenInputs);
|
||||
submitPage.setRequestMatcher(RequestMatcherFactory.matcher(HttpMethod.GET, this.defaultSubmitPageUrl));
|
||||
submitPage.setRequestMatcher(getRequestMatcherBuilder().matcher(HttpMethod.GET, this.defaultSubmitPageUrl));
|
||||
submitPage.setLoginProcessingUrl(this.getLoginProcessingUrl());
|
||||
http.addFilter(postProcess(submitPage));
|
||||
}
|
||||
@ -206,7 +208,7 @@ public final class OneTimeTokenLoginConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
@Override
|
||||
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
|
||||
return RequestMatcherFactory.matcher(HttpMethod.POST, loginProcessingUrl);
|
||||
return getRequestMatcherBuilder().matcher(HttpMethod.POST, loginProcessingUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
@ -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();
|
||||
};
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -45,12 +45,12 @@ import org.springframework.security.access.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.access.vote.RoleVoter;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.config.http.GrantedAuthorityDefaultsParserUtils.AbstractGrantedAuthorityDefaultsBeanFactory;
|
||||
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.HandlerMappingIntrospectorRequestTransformer;
|
||||
import org.springframework.security.web.access.PathPatternRequestTransformer;
|
||||
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
|
||||
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
|
||||
@ -88,7 +88,6 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* Stateful class which helps HttpSecurityBDP to create the configuration for the
|
||||
@ -100,11 +99,6 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
*/
|
||||
class HttpConfigurationBuilder {
|
||||
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
|
||||
|
||||
private static final boolean mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR,
|
||||
HttpConfigurationBuilder.class.getClassLoader());
|
||||
|
||||
private static final String ATT_CREATE_SESSION = "create-session";
|
||||
|
||||
private static final String ATT_SESSION_FIXATION_PROTECTION = "session-fixation-protection";
|
||||
@ -165,6 +159,8 @@ class HttpConfigurationBuilder {
|
||||
|
||||
private static final String DEF_JAAS_API_PROVISION = "false";
|
||||
|
||||
private static final String REQUEST_MATCHER_BUILDER_BEAN_NAME = "HttpConfigurationBuilder-pathPatternRequestMatcherBuilder";
|
||||
|
||||
private final Element httpElt;
|
||||
|
||||
private final ParserContext pc;
|
||||
@ -244,6 +240,13 @@ class HttpConfigurationBuilder {
|
||||
String createSession = element.getAttribute(ATT_CREATE_SESSION);
|
||||
this.sessionPolicy = !StringUtils.hasText(createSession) ? SessionCreationPolicy.IF_REQUIRED
|
||||
: createPolicy(createSession);
|
||||
if (!this.pc.getRegistry().containsBeanDefinition(REQUEST_MATCHER_BUILDER_BEAN_NAME)) {
|
||||
BeanDefinitionBuilder pathPatternRequestMatcherBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(PathPatternRequestMatcherBuilderFactoryBean.class);
|
||||
pathPatternRequestMatcherBuilder.setFallback(true);
|
||||
BeanDefinition bean = pathPatternRequestMatcherBuilder.getBeanDefinition();
|
||||
this.pc.registerBeanComponent(new BeanComponentDefinition(bean, REQUEST_MATCHER_BUILDER_BEAN_NAME));
|
||||
}
|
||||
createSecurityContextHolderStrategy();
|
||||
createForceEagerSessionCreationFilter();
|
||||
createDisableEncodeUrlFilter();
|
||||
@ -793,10 +796,8 @@ class HttpConfigurationBuilder {
|
||||
BeanDefinitionBuilder wipeBldr = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(AuthorizationManagerWebInvocationPrivilegeEvaluator.class)
|
||||
.addConstructorArgReference(authorizationFilterParser.getAuthorizationManagerRef());
|
||||
if (mvcPresent) {
|
||||
wipeBldr.addPropertyValue("requestTransformer",
|
||||
new RootBeanDefinition(HandlerMappingIntrospectorRequestTransformerFactoryBean.class));
|
||||
}
|
||||
wipeBldr.addPropertyValue("requestTransformer",
|
||||
new RootBeanDefinition(PathPatternRequestTransformerFactoryBean.class));
|
||||
BeanDefinition wipe = wipeBldr.getBeanDefinition();
|
||||
this.pc.registerBeanComponent(
|
||||
new BeanComponentDefinition(wipe, this.pc.getReaderContext().generateBeanName(wipe)));
|
||||
@ -966,7 +967,7 @@ class HttpConfigurationBuilder {
|
||||
return BeanDefinitionBuilder.rootBeanDefinition(ObservationRegistryFactory.class).getBeanDefinition();
|
||||
}
|
||||
|
||||
static class HandlerMappingIntrospectorRequestTransformerFactoryBean
|
||||
static class PathPatternRequestTransformerFactoryBean
|
||||
implements FactoryBean<AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer>,
|
||||
ApplicationContextAware {
|
||||
|
||||
@ -982,10 +983,7 @@ class HttpConfigurationBuilder {
|
||||
if (requestTransformer != null) {
|
||||
return requestTransformer;
|
||||
}
|
||||
HandlerMappingIntrospector hmi = this.applicationContext.getBeanProvider(HandlerMappingIntrospector.class)
|
||||
.getIfAvailable();
|
||||
return (hmi != null) ? new HandlerMappingIntrospectorRequestTransformer(hmi)
|
||||
: new PathPatternRequestTransformer();
|
||||
return new PathPatternRequestTransformer();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -22,13 +22,12 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@ -39,21 +38,13 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public enum MatcherType {
|
||||
|
||||
ant(AntPathRequestMatcher.class), regex(RegexRequestMatcher.class), ciRegex(RegexRequestMatcher.class),
|
||||
mvc(MvcRequestMatcher.class);
|
||||
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
|
||||
|
||||
private static final boolean mvcPresent;
|
||||
ant(AntPathRequestMatcher.class), path(PathPatternRequestMatcher.class), regex(RegexRequestMatcher.class),
|
||||
ciRegex(RegexRequestMatcher.class), mvc(MvcRequestMatcher.class);
|
||||
|
||||
private static final String ATT_MATCHER_TYPE = "request-matcher";
|
||||
|
||||
final Class<? extends RequestMatcher> type;
|
||||
|
||||
static {
|
||||
mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, MatcherType.class.getClassLoader());
|
||||
}
|
||||
|
||||
MatcherType(Class<? extends RequestMatcher> type) {
|
||||
this.type = type;
|
||||
}
|
||||
@ -66,18 +57,17 @@ public enum MatcherType {
|
||||
if (("/**".equals(path) || "**".equals(path)) && method == null) {
|
||||
return new RootBeanDefinition(AnyRequestMatcher.class);
|
||||
}
|
||||
BeanDefinitionBuilder matcherBldr = BeanDefinitionBuilder.rootBeanDefinition(this.type);
|
||||
if (this == mvc) {
|
||||
matcherBldr.addConstructorArgValue(new RootBeanDefinition(HandlerMappingIntrospectorFactoryBean.class));
|
||||
}
|
||||
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 +79,10 @@ public enum MatcherType {
|
||||
return valueOf(elt.getAttribute(ATT_MATCHER_TYPE));
|
||||
}
|
||||
|
||||
return ant;
|
||||
return path;
|
||||
}
|
||||
|
||||
static MatcherType fromElementOrMvc(Element elt) {
|
||||
String matcherTypeName = elt.getAttribute(ATT_MATCHER_TYPE);
|
||||
if (!StringUtils.hasText(matcherTypeName) && mvcPresent) {
|
||||
return MatcherType.mvc;
|
||||
}
|
||||
return MatcherType.fromElement(elt);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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,7 @@ public final class RequestMatcherFactoryBean implements FactoryBean<RequestMatch
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||
this.builder = context.getBeanProvider(PathPatternRequestMatcher.Builder.class).getIfUnique();
|
||||
this.builder = context.getBean(PathPatternRequestMatcher.Builder.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -58,6 +58,6 @@ abstract class AbstractRequestMatcherDsl {
|
||||
protected abstract class AuthorizationManagerRule(open val rule: AuthorizationManager<RequestAuthorizationContext>)
|
||||
|
||||
protected enum class PatternType {
|
||||
ANT, MVC
|
||||
ANT, MVC, PATH;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,6 @@ operator fun HttpSecurity.invoke(httpConfiguration: HttpSecurityDsl.() -> Unit)
|
||||
*/
|
||||
@SecurityMarker
|
||||
class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecurityDsl.() -> Unit) {
|
||||
private val HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"
|
||||
|
||||
var authenticationManager: AuthenticationManager? = null
|
||||
val context: ApplicationContext = http.getSharedObject(ApplicationContext::class.java)
|
||||
@ -192,7 +191,7 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
|
||||
* @Bean
|
||||
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
* http {
|
||||
* securityMatcher(PathPatternRequestMatcher.withDefaults().matcher("/private/**"))
|
||||
* securityMatcher(pathPattern("/private/**"))
|
||||
* formLogin {
|
||||
* loginPage = "/log-in"
|
||||
* }
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1183,7 +1183,7 @@ hsts-options.attlist &=
|
||||
attribute preload {xsd:boolean}?
|
||||
|
||||
cors =
|
||||
## Element for configuration of CorsFilter. If no CorsFilter or CorsConfigurationSource is specified a HandlerMappingIntrospector is used as the CorsConfigurationSource
|
||||
## Element for configuration of CorsFilter. A CorsConfigurationSource must be specified. If Spring MVC is present, then it will attempt to look up its `CorsConfigurationSource`.
|
||||
element cors { cors-options.attlist }
|
||||
cors-options.attlist &=
|
||||
ref?
|
||||
|
@ -3317,8 +3317,8 @@
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="cors">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Element for configuration of CorsFilter. If no CorsFilter or CorsConfigurationSource is
|
||||
specified a HandlerMappingIntrospector is used as the CorsConfigurationSource
|
||||
<xs:documentation>Element for configuration of CorsFilter. A CorsConfigurationSource must be specified. If
|
||||
Spring MVC is present, then it will attempt to look up its `CorsConfigurationSource`.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
|
@ -39,6 +39,7 @@ import org.springframework.security.web.servletapi.SecurityContextHolderAwareReq
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@ -121,7 +122,7 @@ public class FilterChainProxyConfigTests {
|
||||
|
||||
private String getPattern(SecurityFilterChain chain) {
|
||||
RequestMatcher requestMatcher = ((DefaultSecurityFilterChain) chain).getRequestMatcher();
|
||||
return (String) ReflectionTestUtils.getField(requestMatcher, "pattern");
|
||||
return ((PathPattern) ReflectionTestUtils.getField(requestMatcher, "pattern")).getPatternString();
|
||||
}
|
||||
|
||||
private void checkPathAndFilterOrder(FilterChainProxy filterChainProxy) {
|
||||
|
@ -32,9 +32,10 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
@ -52,7 +53,7 @@ public class SecurityConfig {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeRequests((requests) -> requests
|
||||
.requestMatchers(new AntPathRequestMatcher("/*")).permitAll())
|
||||
.requestMatchers(pathPattern("/*")).permitAll())
|
||||
.authenticationProvider(authenticationProvider());
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
|
@ -25,13 +25,12 @@ import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
|
||||
/**
|
||||
* Tests for {@link AbstractRequestMatcherRegistry}.
|
||||
@ -88,7 +87,7 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests {
|
||||
http
|
||||
.authorizeRequests((requests) -> requests
|
||||
.anyRequest().authenticated()
|
||||
.requestMatchers(new AntPathRequestMatcher("/demo/**")).permitAll());
|
||||
.requestMatchers(pathPattern("/demo/**")).permitAll());
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
@ -100,12 +99,12 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests {
|
||||
static class MvcMatchersAfterAnyRequestConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeRequests((requests) -> requests
|
||||
.anyRequest().authenticated()
|
||||
.requestMatchers(new MvcRequestMatcher(introspector, "/demo/**")).permitAll());
|
||||
.requestMatchers(builder.matcher("/demo/**")).permitAll());
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
@ -156,7 +155,7 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests {
|
||||
http
|
||||
.authorizeRequests((requests) -> requests
|
||||
.anyRequest().authenticated()
|
||||
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll());
|
||||
.requestMatchers(pathPattern("/**")).permitAll());
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
@ -21,9 +21,10 @@ import java.util.List;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.test.support.ClassPathExclusions;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -41,22 +42,26 @@ public class AbstractRequestMatcherRegistryNoMvcTests {
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
this.matcherRegistry = new TestRequestMatcherRegistry();
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBean(PathPatternRequestMatcher.Builder.class, PathPatternRequestMatcher::withDefaults);
|
||||
context.refresh();
|
||||
this.matcherRegistry.setApplicationContext(context);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenPatternAndMvcNotPresentThenReturnAntPathRequestMatcherType() {
|
||||
public void requestMatchersWhenPatternAndMvcNotPresentThenReturnPathPatternRequestMatcherType() {
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/path");
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenHttpMethodAndPatternAndMvcNotPresentThenReturnAntPathRequestMatcherType() {
|
||||
public void requestMatchersWhenHttpMethodAndPatternAndMvcNotPresentThenReturnPathPatternRequestMatcherType() {
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET, "/path");
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -64,7 +69,7 @@ public class AbstractRequestMatcherRegistryNoMvcTests {
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET);
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class);
|
||||
}
|
||||
|
||||
private static class TestRequestMatcherRegistry extends AbstractRequestMatcherRegistry<List<RequestMatcher>> {
|
||||
|
@ -16,47 +16,29 @@
|
||||
|
||||
package org.springframework.security.config.annotation.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import jakarta.servlet.Servlet;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.security.config.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.DispatcherServletDelegatingRequestMatcher;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.web.servlet.MockServletContext;
|
||||
import org.springframework.security.web.servlet.TestMockHttpServletMappings;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.type;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
|
||||
/**
|
||||
* Tests for {@link AbstractRequestMatcherRegistry}.
|
||||
@ -86,9 +68,9 @@ public class AbstractRequestMatcherRegistryTests {
|
||||
ObjectProvider<ObjectPostProcessor<Object>> given = this.context.getBeanProvider(type);
|
||||
given(given).willReturn(postProcessors);
|
||||
given(postProcessors.getObject()).willReturn(NO_OP_OBJECT_POST_PROCESSOR);
|
||||
given(this.context.getServletContext()).willReturn(MockServletContext.mvc());
|
||||
given(this.context.getBean(PathPatternRequestMatcher.Builder.class))
|
||||
.willReturn(PathPatternRequestMatcher.withDefaults());
|
||||
this.matcherRegistry.setApplicationContext(this.context);
|
||||
mockMvcIntrospector(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -110,24 +92,24 @@ public class AbstractRequestMatcherRegistryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void antMatchersWhenHttpMethodAndPatternParamsThenReturnAntPathRequestMatcherType() {
|
||||
public void pathPatternWhenHttpMethodAndPatternParamsThenReturnPathPatternRequestMatcherType() {
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry
|
||||
.requestMatchers(new AntPathRequestMatcher("/a.*", HttpMethod.GET.name()));
|
||||
.requestMatchers(pathPattern(HttpMethod.GET, "/a.*"));
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void antMatchersWhenPatternParamThenReturnAntPathRequestMatcherType() {
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(new AntPathRequestMatcher("/a.*"));
|
||||
public void pathPatternWhenPatternParamThenReturnPathPatternRequestMatcherType() {
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(pathPattern("/a.*"));
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dispatcherTypeMatchersWhenHttpMethodAndPatternParamsThenReturnAntPathRequestMatcherType() {
|
||||
public void dispatcherTypeMatchersWhenHttpMethodAndPatternParamsThenReturnPathPatternRequestMatcherType() {
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.dispatcherTypeMatchers(HttpMethod.GET,
|
||||
DispatcherType.ASYNC);
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
@ -136,7 +118,7 @@ public class AbstractRequestMatcherRegistryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dispatcherMatchersWhenPatternParamThenReturnAntPathRequestMatcherType() {
|
||||
public void dispatcherMatchersWhenPatternParamThenReturnPathPatternRequestMatcherType() {
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.dispatcherTypeMatchers(DispatcherType.INCLUDE);
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
@ -144,252 +126,36 @@ public class AbstractRequestMatcherRegistryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenPatternAndMvcPresentThenReturnMvcRequestMatcherType() {
|
||||
public void requestMatchersWhenPatternAndMvcPresentThenReturnPathPatternRequestMatcherType() {
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/path");
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(MvcRequestMatcher.class);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenHttpMethodAndPatternAndMvcPresentThenReturnMvcRequestMatcherType() {
|
||||
public void requestMatchersWhenHttpMethodAndPatternAndMvcPresentThenReturnPathPatternRequestMatcherType() {
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET, "/path");
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(MvcRequestMatcher.class);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenHttpMethodAndMvcPresentThenReturnMvcRequestMatcherType() {
|
||||
public void requestMatchersWhenHttpMethodAndMvcPresentThenReturnPathPatternRequestMatcherType() {
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET);
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(MvcRequestMatcher.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenMvcPresentInClassPathAndMvcIntrospectorBeanNotAvailableThenException() {
|
||||
mockMvcIntrospector(false);
|
||||
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
|
||||
.isThrownBy(() -> this.matcherRegistry.requestMatchers("/path"))
|
||||
.withMessageContaining(
|
||||
"Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenNoDispatcherServletThenAntPathRequestMatcherType() {
|
||||
mockMvcIntrospector(true);
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
given(this.context.getServletContext()).willReturn(servletContext);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class))
|
||||
.extracting((matcher) -> matcher.requestMatcher(request))
|
||||
.isInstanceOf(AntPathRequestMatcher.class);
|
||||
servletContext.addServlet("servletOne", Servlet.class).addMapping("/one");
|
||||
servletContext.addServlet("servletTwo", Servlet.class).addMapping("/two");
|
||||
requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class))
|
||||
.extracting((matcher) -> matcher.requestMatcher(request))
|
||||
.isInstanceOf(AntPathRequestMatcher.class);
|
||||
servletContext.addServlet("servletOne", Servlet.class);
|
||||
servletContext.addServlet("servletTwo", Servlet.class);
|
||||
requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class))
|
||||
.extracting((matcher) -> matcher.requestMatcher(request))
|
||||
.isInstanceOf(AntPathRequestMatcher.class);
|
||||
}
|
||||
|
||||
// gh-14418
|
||||
@Test
|
||||
public void requestMatchersWhenNoDispatcherServletMockMvcThenMvcRequestMatcherType() throws Exception {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
try (SpringTestContext spring = new SpringTestContext(this)) {
|
||||
spring.register(MockMvcConfiguration.class)
|
||||
.postProcessor((context) -> context.setServletContext(servletContext))
|
||||
.autowire();
|
||||
this.matcherRegistry.setApplicationContext(spring.getContext());
|
||||
MockMvc mvc = MockMvcBuilders.webAppContextSetup(spring.getContext()).build();
|
||||
MockHttpServletRequest request = mvc.perform(get("/")).andReturn().getRequest();
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class))
|
||||
.extracting((matcher) -> matcher.requestMatcher(request))
|
||||
.isInstanceOf(MvcRequestMatcher.class);
|
||||
servletContext.addServlet("servletOne", Servlet.class).addMapping("/one");
|
||||
servletContext.addServlet("servletTwo", Servlet.class).addMapping("/two");
|
||||
requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class))
|
||||
.extracting((matcher) -> matcher.requestMatcher(request))
|
||||
.isInstanceOf(MvcRequestMatcher.class);
|
||||
servletContext.addServlet("servletOne", Servlet.class);
|
||||
servletContext.addServlet("servletTwo", Servlet.class);
|
||||
requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
||||
assertThat(requestMatchers).isNotEmpty();
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).asInstanceOf(type(DispatcherServletDelegatingRequestMatcher.class))
|
||||
.extracting((matcher) -> matcher.requestMatcher(request))
|
||||
.isInstanceOf(MvcRequestMatcher.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenAmbiguousServletsThenException() {
|
||||
mockMvcIntrospector(true);
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
given(this.context.getServletContext()).willReturn(servletContext);
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/");
|
||||
servletContext.addServlet("servletTwo", DispatcherServlet.class).addMapping("/servlet/*");
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> this.matcherRegistry.requestMatchers("/**"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenMultipleDispatcherServletMappingsThenException() {
|
||||
mockMvcIntrospector(true);
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
given(this.context.getServletContext()).willReturn(servletContext);
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/", "/mvc/*");
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> this.matcherRegistry.requestMatchers("/**"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenPathDispatcherServletAndOtherServletsThenException() {
|
||||
mockMvcIntrospector(true);
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
given(this.context.getServletContext()).willReturn(servletContext);
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
servletContext.addServlet("default", Servlet.class).addMapping("/");
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> this.matcherRegistry.requestMatchers("/**"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenUnmappableServletsThenSkips() {
|
||||
mockMvcIntrospector(true);
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
given(this.context.getServletContext()).willReturn(servletContext);
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/");
|
||||
servletContext.addServlet("servletTwo", Servlet.class);
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isInstanceOf(MvcRequestMatcher.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenOnlyDispatcherServletThenAllows() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
given(this.context.getServletContext()).willReturn(servletContext);
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isInstanceOf(MvcRequestMatcher.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenImplicitServletsThenAllows() {
|
||||
mockMvcIntrospector(true);
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
given(this.context.getServletContext()).willReturn(servletContext);
|
||||
servletContext.addServlet("defaultServlet", Servlet.class);
|
||||
servletContext.addServlet("jspServlet", Servlet.class).addMapping("*.jsp", "*.jspx");
|
||||
servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/");
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/**");
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isInstanceOf(DispatcherServletDelegatingRequestMatcher.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenPathBasedNonDispatcherServletThenAllows() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
given(this.context.getServletContext()).willReturn(servletContext);
|
||||
servletContext.addServlet("path", Servlet.class).addMapping("/services/*");
|
||||
servletContext.addServlet("default", DispatcherServlet.class).addMapping("/");
|
||||
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/services/*");
|
||||
assertThat(requestMatchers).hasSize(1);
|
||||
assertThat(requestMatchers.get(0)).isInstanceOf(DispatcherServletDelegatingRequestMatcher.class);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/services/endpoint");
|
||||
request.setHttpServletMapping(TestMockHttpServletMappings.defaultMapping());
|
||||
assertThat(requestMatchers.get(0).matcher(request).isMatch()).isTrue();
|
||||
request.setHttpServletMapping(TestMockHttpServletMappings.path(request, "/services"));
|
||||
request.setServletPath("/services");
|
||||
request.setPathInfo("/endpoint");
|
||||
assertThat(requestMatchers.get(0).matcher(request).isMatch()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchesWhenDispatcherServletThenMvc() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", DispatcherServlet.class).addMapping("/");
|
||||
servletContext.addServlet("path", Servlet.class).addMapping("/services/*");
|
||||
MvcRequestMatcher mvc = mock(MvcRequestMatcher.class);
|
||||
AntPathRequestMatcher ant = mock(AntPathRequestMatcher.class);
|
||||
RequestMatcher requestMatcher = new DispatcherServletDelegatingRequestMatcher(ant, mvc);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/services/endpoint");
|
||||
request.setHttpServletMapping(TestMockHttpServletMappings.defaultMapping());
|
||||
assertThat(requestMatcher.matches(request)).isFalse();
|
||||
verify(mvc).matches(request);
|
||||
verifyNoInteractions(ant);
|
||||
request.setHttpServletMapping(TestMockHttpServletMappings.path(request, "/services"));
|
||||
assertThat(requestMatcher.matches(request)).isFalse();
|
||||
verify(ant).matches(request);
|
||||
verifyNoMoreInteractions(mvc);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchesWhenNoMappingThenException() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
servletContext.addServlet("default", DispatcherServlet.class).addMapping("/");
|
||||
servletContext.addServlet("path", Servlet.class).addMapping("/services/*");
|
||||
MvcRequestMatcher mvc = mock(MvcRequestMatcher.class);
|
||||
AntPathRequestMatcher ant = mock(AntPathRequestMatcher.class);
|
||||
RequestMatcher requestMatcher = new DispatcherServletDelegatingRequestMatcher(ant, mvc);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/services/endpoint");
|
||||
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> requestMatcher.matcher(request));
|
||||
}
|
||||
|
||||
private void mockMvcIntrospector(boolean isPresent) {
|
||||
ApplicationContext context = this.matcherRegistry.getApplicationContext();
|
||||
given(context.containsBean("mvcHandlerMappingIntrospector")).willReturn(isPresent);
|
||||
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(PathPatternRequestMatcher.class);
|
||||
}
|
||||
|
||||
private static class TestRequestMatcherRegistry extends AbstractRequestMatcherRegistry<List<RequestMatcher>> {
|
||||
|
||||
@Override
|
||||
public List<RequestMatcher> requestMatchers(RequestMatcher... requestMatchers) {
|
||||
return unwrap(super.requestMatchers(requestMatchers));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<RequestMatcher> chainRequestMatchers(List<RequestMatcher> requestMatchers) {
|
||||
return requestMatchers;
|
||||
}
|
||||
|
||||
private List<RequestMatcher> unwrap(List<RequestMatcher> wrappedMatchers) {
|
||||
List<RequestMatcher> requestMatchers = new ArrayList<>();
|
||||
for (RequestMatcher requestMatcher : wrappedMatchers) {
|
||||
if (requestMatcher instanceof DeferredRequestMatcher) {
|
||||
DeferredRequestMatcher deferred = (DeferredRequestMatcher) requestMatcher;
|
||||
WebApplicationContext web = (WebApplicationContext) getApplicationContext();
|
||||
requestMatchers.add(deferred.requestMatcher(web.getServletContext()));
|
||||
}
|
||||
else {
|
||||
requestMatchers.add(requestMatcher);
|
||||
}
|
||||
}
|
||||
return requestMatchers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
@ -39,7 +39,6 @@ import org.springframework.security.core.userdetails.PasswordEncodedUser;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
@ -49,6 +48,7 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@ -150,8 +150,8 @@ public class HttpConfigurationTests {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((security) -> security
|
||||
.requestMatchers(new AntPathRequestMatcher("/api/**"))
|
||||
.requestMatchers(new AntPathRequestMatcher("/oauth/**")))
|
||||
.requestMatchers(pathPattern("/api/**"))
|
||||
.requestMatchers(pathPattern("/oauth/**")))
|
||||
.authorizeRequests((requests) -> requests
|
||||
.anyRequest().hasRole("USER"))
|
||||
.httpBasic(withDefaults());
|
||||
|
@ -54,8 +54,8 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.context.NullSecurityContextRepository;
|
||||
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.stereotype.Controller;
|
||||
@ -75,6 +75,7 @@ import static org.springframework.security.config.Customizer.withDefaults;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
@ -195,13 +196,13 @@ public class NamespaceHttpTests {
|
||||
}
|
||||
|
||||
@Test // http@request-matcher-ref ant
|
||||
public void configureWhenAntPatternMatchingThenAntPathRequestMatcherUsed() {
|
||||
public void configureWhenAntPatternMatchingThenPathPatternRequestMatcherUsed() {
|
||||
this.spring.register(RequestMatcherAntConfig.class).autowire();
|
||||
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
|
||||
assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
|
||||
DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
|
||||
.get(0);
|
||||
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
|
||||
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(PathPatternRequestMatcher.class);
|
||||
}
|
||||
|
||||
@Test // http@request-matcher-ref regex
|
||||
@ -226,21 +227,19 @@ public class NamespaceHttpTests {
|
||||
}
|
||||
|
||||
@Test // http@security=none
|
||||
public void configureWhenIgnoredAntPatternsThenAntPathRequestMatcherUsedWithNoFilters() {
|
||||
public void configureWhenIgnoredAntPatternsThenPathPatternRequestMatcherUsedWithNoFilters() {
|
||||
this.spring.register(SecurityNoneConfig.class).autowire();
|
||||
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
|
||||
assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
|
||||
DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
|
||||
.get(0);
|
||||
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
|
||||
assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern())
|
||||
.isEqualTo("/resources/**");
|
||||
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(PathPatternRequestMatcher.class);
|
||||
assertThat(securityFilterChain.getRequestMatcher()).isEqualTo(pathPattern("/resources/**"));
|
||||
assertThat(securityFilterChain.getFilters()).isEmpty();
|
||||
assertThat(filterChainProxy.getFilterChains().get(1)).isInstanceOf(DefaultSecurityFilterChain.class);
|
||||
securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains().get(1);
|
||||
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
|
||||
assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern())
|
||||
.isEqualTo("/public/**");
|
||||
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(PathPatternRequestMatcher.class);
|
||||
assertThat(securityFilterChain.getRequestMatcher()).isEqualTo(pathPattern("/public/**"));
|
||||
assertThat(securityFilterChain.getFilters()).isEmpty();
|
||||
}
|
||||
|
||||
@ -482,7 +481,7 @@ public class NamespaceHttpTests {
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatcher(new AntPathRequestMatcher("/api/**"));
|
||||
.securityMatcher(pathPattern("/api/**"));
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
@ -534,8 +533,9 @@ public class NamespaceHttpTests {
|
||||
|
||||
@Bean
|
||||
WebSecurityCustomizer webSecurityCustomizer() {
|
||||
PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withDefaults();
|
||||
return (web) -> web.ignoring()
|
||||
.requestMatchers(new AntPathRequestMatcher("/resources/**"), new AntPathRequestMatcher("/public/**"));
|
||||
.requestMatchers(builder.matcher("/resources/**"), builder.matcher("/public/**"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -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,
|
||||
|
@ -42,12 +42,11 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandler;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
@ -130,8 +129,8 @@ public class WebSecurityTests {
|
||||
static class MvcMatcherConfig {
|
||||
|
||||
@Bean
|
||||
WebSecurityCustomizer webSecurityCustomizer(HandlerMappingIntrospector introspector) {
|
||||
return (web) -> web.ignoring().requestMatchers(new MvcRequestMatcher(introspector, "/path"));
|
||||
WebSecurityCustomizer webSecurityCustomizer(PathPatternRequestMatcher.Builder builder) {
|
||||
return (web) -> web.ignoring().requestMatchers(builder.matcher("/path"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ -168,9 +167,10 @@ public class WebSecurityTests {
|
||||
static class MvcMatcherServletPathConfig {
|
||||
|
||||
@Bean
|
||||
WebSecurityCustomizer webSecurityCustomizer(HandlerMappingIntrospector introspector) {
|
||||
MvcRequestMatcher.Builder builder = new MvcRequestMatcher.Builder(introspector).servletPath("/spring");
|
||||
return (web) -> web.ignoring().requestMatchers(builder.pattern("/path")).requestMatchers("/notused");
|
||||
WebSecurityCustomizer webSecurityCustomizer(PathPatternRequestMatcher.Builder builder) {
|
||||
return (web) -> web.ignoring()
|
||||
.requestMatchers(builder.basePath("/spring").matcher("/path"))
|
||||
.requestMatchers("/notused");
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -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 {
|
||||
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -62,8 +62,6 @@ import org.springframework.security.web.access.PathPatternRequestTransformer;
|
||||
import org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -78,6 +76,7 @@ import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
@ -106,14 +105,13 @@ public class WebSecurityConfigurationTests {
|
||||
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
|
||||
List<SecurityFilterChain> filterChains = filterChainProxy.getFilterChains();
|
||||
assertThat(filterChains).hasSize(4);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||
request.setServletPath("/role1/**");
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/role1/**");
|
||||
assertThat(filterChains.get(0).matches(request)).isTrue();
|
||||
request.setServletPath("/role2/**");
|
||||
request = new MockHttpServletRequest("GET", "/role2/**");
|
||||
assertThat(filterChains.get(1).matches(request)).isTrue();
|
||||
request.setServletPath("/role3/**");
|
||||
request = new MockHttpServletRequest("GET", "/role3/**");
|
||||
assertThat(filterChains.get(2).matches(request)).isTrue();
|
||||
request.setServletPath("/**");
|
||||
request = new MockHttpServletRequest("GET", "/**");
|
||||
assertThat(filterChains.get(3).matches(request)).isTrue();
|
||||
}
|
||||
|
||||
@ -123,10 +121,9 @@ public class WebSecurityConfigurationTests {
|
||||
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
|
||||
List<SecurityFilterChain> filterChains = filterChainProxy.getFilterChains();
|
||||
assertThat(filterChains).hasSize(2);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||
request.setServletPath("/role1/**");
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/role1/**");
|
||||
assertThat(filterChains.get(0).matches(request)).isTrue();
|
||||
request.setServletPath("/role2/**");
|
||||
request = new MockHttpServletRequest("GET", "/role2/**");
|
||||
assertThat(filterChains.get(1).matches(request)).isTrue();
|
||||
}
|
||||
|
||||
@ -240,14 +237,13 @@ public class WebSecurityConfigurationTests {
|
||||
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
|
||||
List<SecurityFilterChain> filterChains = filterChainProxy.getFilterChains();
|
||||
assertThat(filterChains).hasSize(3);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||
request.setServletPath("/ignore1");
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/ignore1");
|
||||
assertThat(filterChains.get(0).matches(request)).isTrue();
|
||||
assertThat(filterChains.get(0).getFilters()).isEmpty();
|
||||
request.setServletPath("/ignore2");
|
||||
request = new MockHttpServletRequest("GET", "/ignore2");
|
||||
assertThat(filterChains.get(1).matches(request)).isTrue();
|
||||
assertThat(filterChains.get(1).getFilters()).isEmpty();
|
||||
request.setServletPath("/test/**");
|
||||
request = new MockHttpServletRequest("GET", "/test/**");
|
||||
assertThat(filterChains.get(2).matches(request)).isTrue();
|
||||
}
|
||||
|
||||
@ -257,16 +253,15 @@ public class WebSecurityConfigurationTests {
|
||||
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
|
||||
List<SecurityFilterChain> filterChains = filterChainProxy.getFilterChains();
|
||||
assertThat(filterChains).hasSize(3);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||
request.setServletPath("/ignore1");
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/ignore1");
|
||||
assertThat(filterChains.get(0).matches(request)).isTrue();
|
||||
assertThat(filterChains.get(0).getFilters()).isEmpty();
|
||||
request.setServletPath("/ignore2");
|
||||
request = new MockHttpServletRequest("GET", "/ignore2");
|
||||
assertThat(filterChains.get(1).matches(request)).isTrue();
|
||||
assertThat(filterChains.get(1).getFilters()).isEmpty();
|
||||
request.setServletPath("/role1/**");
|
||||
request = new MockHttpServletRequest("GET", "/role1/**");
|
||||
assertThat(filterChains.get(2).matches(request)).isTrue();
|
||||
request.setServletPath("/test/**");
|
||||
request = new MockHttpServletRequest("GET", "/test/**");
|
||||
assertThat(filterChains.get(2).matches(request)).isFalse();
|
||||
}
|
||||
|
||||
@ -276,11 +271,10 @@ public class WebSecurityConfigurationTests {
|
||||
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
|
||||
List<SecurityFilterChain> filterChains = filterChainProxy.getFilterChains();
|
||||
assertThat(filterChains).hasSize(3);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||
request.setServletPath("/ignore1");
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/ignore1");
|
||||
assertThat(filterChains.get(0).matches(request)).isTrue();
|
||||
assertThat(filterChains.get(0).getFilters()).isEmpty();
|
||||
request.setServletPath("/ignore2");
|
||||
request = new MockHttpServletRequest("GET", "/ignore2");
|
||||
assertThat(filterChains.get(1).matches(request)).isTrue();
|
||||
assertThat(filterChains.get(1).getFilters()).isEmpty();
|
||||
}
|
||||
@ -420,7 +414,7 @@ public class WebSecurityConfigurationTests {
|
||||
SecurityFilterChain filterChain1(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
return http
|
||||
.securityMatcher(new AntPathRequestMatcher("/role1/**"))
|
||||
.securityMatcher(pathPattern("/role1/**"))
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.anyRequest().hasRole("1")
|
||||
)
|
||||
@ -433,7 +427,7 @@ public class WebSecurityConfigurationTests {
|
||||
SecurityFilterChain filterChain2(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
return http
|
||||
.securityMatcher(new AntPathRequestMatcher("/role2/**"))
|
||||
.securityMatcher(pathPattern("/role2/**"))
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.anyRequest().hasRole("2")
|
||||
)
|
||||
@ -446,7 +440,7 @@ public class WebSecurityConfigurationTests {
|
||||
SecurityFilterChain filterChain3(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
return http
|
||||
.securityMatcher(new AntPathRequestMatcher("/role3/**"))
|
||||
.securityMatcher(pathPattern("/role3/**"))
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.anyRequest().hasRole("3")
|
||||
)
|
||||
@ -477,7 +471,7 @@ public class WebSecurityConfigurationTests {
|
||||
SecurityFilterChain securityFilterChain1(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
return http
|
||||
.securityMatcher(new AntPathRequestMatcher("/role1/**"))
|
||||
.securityMatcher(pathPattern("/role1/**"))
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.anyRequest().hasRole("1")
|
||||
)
|
||||
@ -734,7 +728,7 @@ public class WebSecurityConfigurationTests {
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
return http
|
||||
.securityMatcher(new AntPathRequestMatcher("/role1/**"))
|
||||
.securityMatcher(pathPattern("/role1/**"))
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.anyRequest().hasRole("1")
|
||||
)
|
||||
@ -773,7 +767,7 @@ public class WebSecurityConfigurationTests {
|
||||
public SecurityFilterChain path1(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/path1/**")))
|
||||
.securityMatchers((requests) -> requests.requestMatchers(pathPattern("/path1/**")))
|
||||
.authorizeRequests((requests) -> requests.anyRequest().authenticated());
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
@ -797,7 +791,7 @@ public class WebSecurityConfigurationTests {
|
||||
public SecurityFilterChain path1(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/path1/**")))
|
||||
.securityMatchers((requests) -> requests.requestMatchers(pathPattern("/path1/**")))
|
||||
.authorizeRequests((requests) -> requests.anyRequest().authenticated());
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
@ -822,7 +816,7 @@ public class WebSecurityConfigurationTests {
|
||||
public SecurityFilterChain notAuthorized(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/user")))
|
||||
.securityMatchers((requests) -> requests.requestMatchers(pathPattern("/user")))
|
||||
.authorizeRequests((requests) -> requests.anyRequest().hasRole("USER"));
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
@ -833,7 +827,7 @@ public class WebSecurityConfigurationTests {
|
||||
public SecurityFilterChain path1(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/admin")))
|
||||
.securityMatchers((requests) -> requests.requestMatchers(pathPattern("/admin")))
|
||||
.authorizeRequests((requests) -> requests.anyRequest().hasRole("ADMIN"));
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
@ -864,7 +858,7 @@ public class WebSecurityConfigurationTests {
|
||||
public SecurityFilterChain notAuthorized(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/user")))
|
||||
.securityMatchers((requests) -> requests.requestMatchers(pathPattern("/user")))
|
||||
.authorizeRequests((requests) -> requests.anyRequest().hasRole("USER"));
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
@ -875,7 +869,7 @@ public class WebSecurityConfigurationTests {
|
||||
public SecurityFilterChain admin(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((requests) -> requests.requestMatchers(new AntPathRequestMatcher("/admin")))
|
||||
.securityMatchers((requests) -> requests.requestMatchers(pathPattern("/admin")))
|
||||
.authorizeRequests((requests) -> requests.anyRequest().hasRole("ADMIN"));
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
@ -911,7 +905,7 @@ public class WebSecurityConfigurationTests {
|
||||
public SecurityFilterChain notAuthorized(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/user")))
|
||||
.securityMatchers((requests) -> requests.requestMatchers(pathPattern("/user")))
|
||||
.authorizeHttpRequests((authorize) -> authorize.anyRequest().hasRole("USER"));
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
@ -922,7 +916,7 @@ public class WebSecurityConfigurationTests {
|
||||
public SecurityFilterChain admin(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/admin")))
|
||||
.securityMatchers((requests) -> requests.requestMatchers(pathPattern("/admin")))
|
||||
.authorizeHttpRequests((authorize) -> authorize.anyRequest().hasRole("ADMIN"));
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
|
@ -22,11 +22,12 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
|
||||
public class AbstractConfigAttributeRequestMatcherRegistryTests {
|
||||
|
||||
@ -55,19 +56,18 @@ public class AbstractConfigAttributeRequestMatcherRegistryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRequestMatcherIsTypeAntPathRequestMatcher() {
|
||||
List<RequestMatcher> requestMatchers = this.registry
|
||||
.requestMatchers(new AntPathRequestMatcher("/a.*", HttpMethod.GET.name()));
|
||||
public void testGetRequestMatcherIsTypePathPatternRequestMatcher() {
|
||||
List<RequestMatcher> requestMatchers = this.registry.requestMatchers(pathPattern(HttpMethod.GET, "/a.*"));
|
||||
for (RequestMatcher requestMatcher : requestMatchers) {
|
||||
assertThat(requestMatcher).isInstanceOf(AntPathRequestMatcher.class);
|
||||
assertThat(requestMatcher).isInstanceOf(PathPatternRequestMatcher.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestMatcherIsTypeAntPathRequestMatcher() {
|
||||
List<RequestMatcher> requestMatchers = this.registry.requestMatchers(new AntPathRequestMatcher("/a.*"));
|
||||
public void testRequestMatcherIsTypePathPatternRequestMatcher() {
|
||||
List<RequestMatcher> requestMatchers = this.registry.requestMatchers(pathPattern("/a.*"));
|
||||
for (RequestMatcher requestMatcher : requestMatchers) {
|
||||
assertThat(requestMatcher).isInstanceOf(AntPathRequestMatcher.class);
|
||||
assertThat(requestMatcher).isInstanceOf(PathPatternRequestMatcher.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,6 @@ import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||
import org.springframework.security.config.observation.SecurityObservationSettings;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
@ -68,7 +67,6 @@ import org.springframework.security.web.access.expression.WebExpressionAuthoriza
|
||||
import org.springframework.security.web.access.intercept.AuthorizationFilter;
|
||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
||||
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
@ -81,7 +79,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@ -148,7 +145,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
public void configureWhenMvcMatcherAfterAnyRequestThenException() {
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> this.spring.register(AfterAnyRequestConfig.class).autowire())
|
||||
.withMessageContaining("Can't configure mvcMatchers after anyRequest");
|
||||
.withMessageContaining("Can't configure requestMatchers after anyRequest");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -689,7 +686,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void requestMatchersWhenMultipleDispatcherServletsAndPathBeanThenAllows() throws Exception {
|
||||
this.spring.register(MvcRequestMatcherBuilderConfig.class, BasicController.class)
|
||||
this.spring.register(PathPatternRequestMatcherBuilderConfig.class, BasicController.class)
|
||||
.postProcessor((context) -> context.getServletContext()
|
||||
.addServlet("otherDispatcherServlet", DispatcherServlet.class)
|
||||
.addMapping("/mvc"))
|
||||
@ -1063,13 +1060,11 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
static class ServletPathConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
|
||||
.servletPath("/spring");
|
||||
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
// @formatter:off
|
||||
return http
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/")).hasRole("ADMIN")
|
||||
.requestMatchers(builder.basePath("/spring").matcher("/")).hasRole("ADMIN")
|
||||
)
|
||||
.build();
|
||||
// @formatter:on
|
||||
@ -1358,7 +1353,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
static class MvcRequestMatcherBuilderConfig {
|
||||
static class PathPatternRequestMatcherBuilderConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain security(HttpSecurity http) throws Exception {
|
||||
@ -1394,11 +1389,6 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
PathPatternRequestMatcherBuilderFactoryBean pathPatternFactoryBean() {
|
||||
return new PathPatternRequestMatcherBuilderFactoryBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
@ -42,17 +42,17 @@ import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.web.servlet.MockServletContext;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
@ -126,11 +126,13 @@ public class AuthorizeRequestsTests {
|
||||
loadConfig(AntPatchersPathVariables.class);
|
||||
this.request.setRequestURI("/USER/user");
|
||||
this.request.setServletPath("/USER/user");
|
||||
this.request.setRequestURI("/USER/user");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
this.setup();
|
||||
this.request.setRequestURI("/USER/deny");
|
||||
this.request.setServletPath("/USER/deny");
|
||||
this.request.setRequestURI("/USER/deny");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
|
||||
}
|
||||
@ -204,7 +206,7 @@ public class AuthorizeRequestsTests {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeRequests((requests) -> requests
|
||||
.requestMatchers(new AntPathRequestMatcher("/**", HttpMethod.POST.name())).denyAll());
|
||||
.requestMatchers(pathPattern(HttpMethod.POST, "/**")).denyAll());
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
@ -225,7 +227,7 @@ public class AuthorizeRequestsTests {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.requestMatchers(new AntPathRequestMatcher("/**", HttpMethod.POST.name())).denyAll()
|
||||
.requestMatchers(pathPattern(HttpMethod.POST, "/**")).denyAll()
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
@ -244,10 +246,13 @@ public class AuthorizeRequestsTests {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
PathPatternParser parser = new PathPatternParser();
|
||||
parser.setCaseSensitive(false);
|
||||
PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withPathPatternParser(parser);
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeRequests((requests) -> requests
|
||||
.requestMatchers(new AntPathRequestMatcher("/user/{user}", null, false)).access("#user == 'user'")
|
||||
.requestMatchers(builder.matcher("/user/{user}")).access("#user == 'user'")
|
||||
.anyRequest().denyAll());
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
@ -266,10 +271,13 @@ public class AuthorizeRequestsTests {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
PathPatternParser parser = new PathPatternParser();
|
||||
parser.setCaseSensitive(false);
|
||||
PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withPathPatternParser(parser);
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeRequests((requests) -> requests
|
||||
.requestMatchers(new AntPathRequestMatcher("/user/{userName}", null, false)).access("#userName == 'user'")
|
||||
.requestMatchers(builder.matcher("/user/{userName}")).access("#userName == 'user'")
|
||||
.anyRequest().denyAll());
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
@ -383,14 +391,13 @@ public class AuthorizeRequestsTests {
|
||||
static class MvcMatcherServletPathConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
|
||||
.servletPath("/spring");
|
||||
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
PathPatternRequestMatcher.Builder spring = builder.basePath("/spring");
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeRequests((requests) -> requests
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/path")).denyAll());
|
||||
.requestMatchers(spring.matcher("/path")).denyAll());
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
@ -418,14 +425,13 @@ public class AuthorizeRequestsTests {
|
||||
static class MvcMatcherServletPathInLambdaConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
|
||||
.servletPath("/spring");
|
||||
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
PathPatternRequestMatcher.Builder spring = builder.basePath("/spring");
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/path")).denyAll()
|
||||
.requestMatchers(spring.matcher("/path")).denyAll()
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
|
@ -28,13 +28,13 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
@ -109,7 +109,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
|
||||
// @formatter:off
|
||||
http
|
||||
.csrf((csrf) -> csrf
|
||||
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/path"))
|
||||
.requireCsrfProtectionMatcher(pathPattern("/path"))
|
||||
.ignoringRequestMatchers(this.requestMatcher));
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
@ -129,7 +129,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
|
||||
// @formatter:off
|
||||
http
|
||||
.csrf((csrf) -> csrf
|
||||
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/path"))
|
||||
.requireCsrfProtectionMatcher(pathPattern("/path"))
|
||||
.ignoringRequestMatchers(this.requestMatcher)
|
||||
);
|
||||
return http.build();
|
||||
@ -149,7 +149,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
|
||||
// @formatter:off
|
||||
http
|
||||
.csrf((csrf) -> csrf
|
||||
.ignoringRequestMatchers(new AntPathRequestMatcher("/no-csrf"))
|
||||
.ignoringRequestMatchers(pathPattern("/no-csrf"))
|
||||
.ignoringRequestMatchers(this.requestMatcher));
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
@ -169,7 +169,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
|
||||
// @formatter:off
|
||||
http
|
||||
.csrf((csrf) -> csrf
|
||||
.ignoringRequestMatchers(new AntPathRequestMatcher("/no-csrf"))
|
||||
.ignoringRequestMatchers(pathPattern("/no-csrf"))
|
||||
.ignoringRequestMatchers(this.requestMatcher)
|
||||
);
|
||||
return http.build();
|
||||
|
@ -57,7 +57,6 @@ import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler
|
||||
import org.springframework.security.web.firewall.StrictHttpFirewall;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
@ -84,6 +83,7 @@ import static org.springframework.security.test.web.servlet.request.SecurityMock
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
||||
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
|
||||
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.head;
|
||||
@ -906,7 +906,7 @@ public class CsrfConfigurerTests {
|
||||
http
|
||||
.formLogin(withDefaults())
|
||||
.logout((logout) -> logout
|
||||
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")));
|
||||
.logoutRequestMatcher(pathPattern("/logout")));
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -32,11 +32,11 @@ import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@ -92,7 +92,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
|
||||
.exceptionHandling((handling) -> handling
|
||||
.defaultAccessDeniedHandlerFor(
|
||||
this.teapotDeniedHandler,
|
||||
new AntPathRequestMatcher("/hello/**"))
|
||||
pathPattern("/hello/**"))
|
||||
.defaultAccessDeniedHandlerFor(
|
||||
new AccessDeniedHandlerImpl(),
|
||||
AnyRequestMatcher.INSTANCE));
|
||||
@ -119,7 +119,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
|
||||
.exceptionHandling((exceptionHandling) -> exceptionHandling
|
||||
.defaultAccessDeniedHandlerFor(
|
||||
this.teapotDeniedHandler,
|
||||
new AntPathRequestMatcher("/hello/**")
|
||||
pathPattern("/hello/**")
|
||||
)
|
||||
.defaultAccessDeniedHandlerFor(
|
||||
new AccessDeniedHandlerImpl(),
|
||||
@ -148,7 +148,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
|
||||
.exceptionHandling((handling) -> handling
|
||||
.defaultAccessDeniedHandlerFor(
|
||||
this.teapotDeniedHandler,
|
||||
new AntPathRequestMatcher("/hello/**")));
|
||||
pathPattern("/hello/**")));
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
@ -36,12 +36,11 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
@ -160,14 +159,13 @@ public class HttpSecurityRequestMatchersTests {
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
SecurityFilterChain first(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
|
||||
SecurityFilterChain first(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((requests) -> requests
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/test-1"))
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/test-2"))
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/test-3"))
|
||||
.requestMatchers(builder.matcher("/test-1"))
|
||||
.requestMatchers(builder.matcher("/test-2"))
|
||||
.requestMatchers(builder.matcher("/test-3"))
|
||||
)
|
||||
.authorizeRequests((authorize) -> authorize.anyRequest().denyAll())
|
||||
.httpBasic(withDefaults());
|
||||
@ -176,12 +174,11 @@ public class HttpSecurityRequestMatchersTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain second(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
|
||||
SecurityFilterChain second(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((requests) -> requests
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/test-1"))
|
||||
.requestMatchers(builder.matcher("/test-1"))
|
||||
)
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.anyRequest().permitAll()
|
||||
@ -209,14 +206,13 @@ public class HttpSecurityRequestMatchersTests {
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
SecurityFilterChain first(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
|
||||
SecurityFilterChain first(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((security) -> security
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/test-1"))
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/test-2"))
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/test-3")))
|
||||
.requestMatchers(builder.matcher("/test-1"))
|
||||
.requestMatchers(builder.matcher("/test-2"))
|
||||
.requestMatchers(builder.matcher("/test-3")))
|
||||
.authorizeRequests((requests) -> requests
|
||||
.anyRequest().denyAll())
|
||||
.httpBasic(withDefaults());
|
||||
@ -225,12 +221,11 @@ public class HttpSecurityRequestMatchersTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain second(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
|
||||
SecurityFilterChain second(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((security) -> security
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/test-1")))
|
||||
.requestMatchers(builder.matcher("/test-1")))
|
||||
.authorizeRequests((requests) -> requests
|
||||
.anyRequest().permitAll());
|
||||
// @formatter:on
|
||||
@ -255,10 +250,10 @@ public class HttpSecurityRequestMatchersTests {
|
||||
static class MvcMatcherConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatcher(new MvcRequestMatcher(introspector, "/path"))
|
||||
.securityMatcher(builder.matcher("/path"))
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeRequests((requests) -> requests
|
||||
.anyRequest().denyAll());
|
||||
@ -289,11 +284,11 @@ public class HttpSecurityRequestMatchersTests {
|
||||
static class RequestMatchersMvcMatcherConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((security) -> security
|
||||
.requestMatchers(new MvcRequestMatcher(introspector, "/path")))
|
||||
.requestMatchers(builder.matcher("/path")))
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeRequests((requests) -> requests
|
||||
.anyRequest().denyAll());
|
||||
@ -324,11 +319,11 @@ public class HttpSecurityRequestMatchersTests {
|
||||
static class RequestMatchersMvcMatcherInLambdaConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((secure) -> secure
|
||||
.requestMatchers(new MvcRequestMatcher(introspector, "/path"))
|
||||
.requestMatchers(builder.matcher("/path"))
|
||||
)
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
@ -356,13 +351,11 @@ public class HttpSecurityRequestMatchersTests {
|
||||
static class RequestMatchersMvcMatcherServeltPathConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
|
||||
mvcMatcherBuilder.servletPath("/spring");
|
||||
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((security) -> security
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/path"))
|
||||
.requestMatchers(builder.basePath("/spring").matcher("/path"))
|
||||
.requestMatchers("/never-match"))
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeRequests((requests) -> requests
|
||||
@ -394,13 +387,11 @@ public class HttpSecurityRequestMatchersTests {
|
||||
static class RequestMatchersMvcMatcherServletPathInLambdaConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
|
||||
mvcMatcherBuilder.servletPath("/spring");
|
||||
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((secure) -> secure
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/path"))
|
||||
.requestMatchers(builder.basePath("/spring").matcher("/path"))
|
||||
.requestMatchers("/never-match")
|
||||
)
|
||||
.httpBasic(withDefaults())
|
||||
|
@ -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) {
|
||||
|
@ -39,12 +39,11 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.servlet.MockServletContext;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
@ -356,14 +355,13 @@ public class HttpSecuritySecurityMatchersTests {
|
||||
static class SecurityMatchersMvcMatcherServletPathConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain appSecurity(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
|
||||
.servletPath("/spring");
|
||||
SecurityFilterChain appSecurity(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
PathPatternRequestMatcher.Builder spring = builder.basePath("/spring");
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((security) -> security
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/path"))
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/never-match"))
|
||||
.requestMatchers(spring.matcher("/path"))
|
||||
.requestMatchers(spring.matcher("/never-match"))
|
||||
)
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
@ -391,14 +389,13 @@ public class HttpSecuritySecurityMatchersTests {
|
||||
static class SecurityMatchersMvcMatcherServletPathInLambdaConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain appSecurity(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
|
||||
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector)
|
||||
.servletPath("/spring");
|
||||
SecurityFilterChain appSecurity(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
PathPatternRequestMatcher.Builder spring = builder.basePath("/spring");
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((matchers) -> matchers
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/path"))
|
||||
.requestMatchers(mvcMatcherBuilder.pattern("/never-match"))
|
||||
.requestMatchers(spring.matcher("/path"))
|
||||
.requestMatchers(spring.matcher("/never-match"))
|
||||
)
|
||||
.httpBasic(withDefaults())
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
|
@ -126,11 +126,6 @@ public class HttpsRedirectConfigurerTests {
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
|
||||
return new PathPatternRequestMatcherBuilderFactoryBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
@ -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"))
|
||||
|
@ -34,7 +34,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.test.web.servlet.RequestCacheResultMatcher;
|
||||
@ -502,11 +501,6 @@ public class RequestCacheConfigurerTests {
|
||||
@EnableWebSecurity
|
||||
static class PathPatternFactoryBeanConfig {
|
||||
|
||||
@Bean
|
||||
PathPatternRequestMatcherBuilderFactoryBean factoryBean() {
|
||||
return new PathPatternRequestMatcherBuilderFactoryBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,9 +27,9 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@ -79,9 +79,9 @@ public class RequestMatcherConfigurerTests {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((security) -> security
|
||||
.requestMatchers(new AntPathRequestMatcher("/api/**")))
|
||||
.requestMatchers(pathPattern("/api/**")))
|
||||
.securityMatchers((security) -> security
|
||||
.requestMatchers(new AntPathRequestMatcher("/oauth/**")))
|
||||
.requestMatchers(pathPattern("/oauth/**")))
|
||||
.authorizeRequests((requests) -> requests
|
||||
.anyRequest().denyAll());
|
||||
return http.build();
|
||||
@ -99,10 +99,10 @@ public class RequestMatcherConfigurerTests {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatchers((secure) -> secure
|
||||
.requestMatchers(new AntPathRequestMatcher("/api/**"))
|
||||
.requestMatchers(pathPattern("/api/**"))
|
||||
)
|
||||
.securityMatchers((securityMatchers) -> securityMatchers
|
||||
.requestMatchers(new AntPathRequestMatcher("/oauth/**"))
|
||||
.requestMatchers(pathPattern("/oauth/**"))
|
||||
)
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.anyRequest().denyAll()
|
||||
|
@ -41,12 +41,11 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.servlet.MockServletContext;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
@ -133,12 +132,12 @@ public class UrlAuthorizationConfigurerTests {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http, ApplicationContext context,
|
||||
HandlerMappingIntrospector introspector) throws Exception {
|
||||
PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic(withDefaults())
|
||||
.apply(new UrlAuthorizationConfigurer(context)).getRegistry()
|
||||
.requestMatchers(new MvcRequestMatcher(introspector, "/path")).hasRole("ADMIN");
|
||||
.requestMatchers(builder.matcher("/path")).hasRole("ADMIN");
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
@ -167,14 +166,13 @@ public class UrlAuthorizationConfigurerTests {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http, ApplicationContext context,
|
||||
HandlerMappingIntrospector introspector) throws Exception {
|
||||
MvcRequestMatcher mvcRequestMatcher = new MvcRequestMatcher(introspector, "/path");
|
||||
mvcRequestMatcher.setServletPath("/spring");
|
||||
PathPatternRequestMatcher.Builder builder) throws Exception {
|
||||
PathPatternRequestMatcher.Builder spring = builder.basePath("/spring");
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic(withDefaults())
|
||||
.apply(new UrlAuthorizationConfigurer(context)).getRegistry()
|
||||
.requestMatchers(mvcRequestMatcher).hasRole("ADMIN");
|
||||
.requestMatchers(builder.matcher("/path")).hasRole("ADMIN");
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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'>"
|
||||
|
@ -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"));
|
||||
|
@ -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()
|
||||
|
@ -22,7 +22,8 @@ import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
||||
import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
@ -44,7 +45,7 @@ public class CustomConfigurer extends SecurityConfigurerAdapter<DefaultSecurityF
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeRequests((requests) -> requests
|
||||
.requestMatchers(new AntPathRequestMatcher(this.permitAllPattern)).permitAll()
|
||||
.requestMatchers(pathPattern(this.permitAllPattern)).permitAll()
|
||||
.anyRequest().authenticated());
|
||||
// @formatter:on
|
||||
if (http.getConfigurer(FormLoginConfigurer.class) == null) {
|
||||
|
@ -38,12 +38,8 @@ import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequ
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy
|
||||
import org.springframework.security.web.csrf.CsrfTokenRepository
|
||||
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler
|
||||
import org.springframework.security.web.csrf.CsrfTokenRequestHandler
|
||||
import org.springframework.security.web.csrf.DefaultCsrfToken
|
||||
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
|
||||
import org.springframework.security.web.csrf.*
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.post
|
||||
@ -176,7 +172,7 @@ class CsrfDslTests {
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
csrf {
|
||||
requireCsrfProtectionMatcher = AntPathRequestMatcher("/test1")
|
||||
requireCsrfProtectionMatcher = PathPatternRequestMatcher.pathPattern("/test1")
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
@ -247,8 +243,8 @@ class CsrfDslTests {
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
csrf {
|
||||
requireCsrfProtectionMatcher = AntPathRequestMatcher("/**")
|
||||
ignoringRequestMatchers(AntPathRequestMatcher("/test2"))
|
||||
requireCsrfProtectionMatcher = PathPatternRequestMatcher.pathPattern("/**")
|
||||
ignoringRequestMatchers(PathPatternRequestMatcher.pathPattern("/test2"))
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
@ -279,7 +275,7 @@ class CsrfDslTests {
|
||||
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
csrf {
|
||||
requireCsrfProtectionMatcher = AntPathRequestMatcher("/**")
|
||||
requireCsrfProtectionMatcher = PathPatternRequestMatcher.pathPattern("/**")
|
||||
ignoringRequestMatchers("/test2")
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -40,7 +40,7 @@ import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler
|
||||
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.post
|
||||
|
||||
@ -102,7 +102,7 @@ class LogoutDslTests {
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
logout {
|
||||
logoutRequestMatcher = AntPathRequestMatcher("/custom/logout")
|
||||
logoutRequestMatcher = PathPatternRequestMatcher.pathPattern("/custom/logout")
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
@ -307,8 +307,9 @@ class LogoutDslTests {
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
logout {
|
||||
logoutRequestMatcher = AntPathRequestMatcher("/logout/**")
|
||||
defaultLogoutSuccessHandlerFor(SimpleUrlLogoutSuccessHandler(), AntPathRequestMatcher("/logout/custom"))
|
||||
logoutRequestMatcher = PathPatternRequestMatcher.pathPattern("/logout/**")
|
||||
defaultLogoutSuccessHandlerFor(SimpleUrlLogoutSuccessHandler(),
|
||||
PathPatternRequestMatcher.pathPattern("/logout/custom"))
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.security.web.server.header.StrictTransportSecurityServerHttpHeadersWriter
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
@ -148,7 +148,7 @@ class HttpStrictTransportSecurityDslTests {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
httpStrictTransportSecurity {
|
||||
requestMatcher = AntPathRequestMatcher("/secure/**")
|
||||
requestMatcher = PathPatternRequestMatcher.pathPattern("/secure/**")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,16 +15,12 @@
|
||||
-->
|
||||
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
|
||||
http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd
|
||||
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util-3.1.xsd
|
||||
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
|
||||
">
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
|
||||
|
||||
|
||||
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd">
|
||||
|
||||
<security:http pattern="/foo/**">
|
||||
<security:intercept-url pattern="/**" access="hasRole('FOO')" />
|
||||
@ -43,7 +39,5 @@ http://www.springframework.org/schema/security https://www.springframework.org/s
|
||||
</security:user-service>
|
||||
</security:authentication-provider>
|
||||
</security:authentication-manager>
|
||||
|
||||
<import resource="handlermappingintrospector.xml"/>
|
||||
|
||||
</beans>
|
||||
|
@ -30,7 +30,6 @@
|
||||
</http>
|
||||
|
||||
<b:import resource="CsrfConfigTests-shared-userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
|
||||
<b:bean id="firewall" class="org.springframework.security.web.firewall.StrictHttpFirewall"
|
||||
p:unsafeAllowAnyHttpMethod="true"/>
|
||||
|
@ -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>
|
@ -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>
|
||||
|
@ -16,8 +16,10 @@
|
||||
<user name="user" password="password" authorities="ROLE_USER"/>
|
||||
</user-service>
|
||||
|
||||
<b:bean id="matcherRef" class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"
|
||||
c:pattern="/foo"
|
||||
c:httpMethod="GET"
|
||||
c:caseSensitive="false"/>
|
||||
<b:bean id="mvcPatternParser" class="org.springframework.web.util.pattern.PathPatternParser">
|
||||
<b:property name="caseSensitive" value="false"/>
|
||||
</b:bean>
|
||||
|
||||
<b:bean id="matcherRef" class="org.springframework.security.config.http.PathPatternRequestMatcherFactoryBean"
|
||||
c:pattern="/foo" c:method="GET"/>
|
||||
</b:beans>
|
||||
|
@ -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>
|
||||
|
@ -33,5 +33,4 @@
|
||||
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -33,5 +33,4 @@
|
||||
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -30,5 +30,4 @@
|
||||
</http>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -30,5 +30,4 @@
|
||||
</http>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -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>
|
||||
|
@ -33,5 +33,4 @@
|
||||
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -33,5 +33,4 @@
|
||||
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -33,5 +33,4 @@
|
||||
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -33,5 +33,4 @@
|
||||
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -34,5 +34,4 @@
|
||||
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -34,5 +34,4 @@
|
||||
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -34,5 +34,4 @@
|
||||
<b:bean name="id" class="org.springframework.security.config.http.InterceptUrlConfigTests.Id"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -34,5 +34,4 @@
|
||||
<b:bean name="id" class="org.springframework.security.config.http.InterceptUrlConfigTests.Id"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -32,5 +32,4 @@
|
||||
</http>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -31,5 +31,4 @@
|
||||
</http>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -34,5 +34,4 @@
|
||||
</b:bean>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -29,5 +29,4 @@
|
||||
<http pattern="/unprotected" security="none"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -31,5 +31,4 @@
|
||||
</http>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -31,5 +31,4 @@
|
||||
</http>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -30,5 +30,4 @@
|
||||
</http>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -30,5 +30,4 @@
|
||||
</http>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -35,5 +35,4 @@
|
||||
<b:bean name="basicController" class="org.springframework.security.config.http.MultiHttpBlockConfigTests.BasicController"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -33,5 +33,4 @@
|
||||
</http>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
@ -50,5 +50,4 @@
|
||||
</authentication-provider>
|
||||
</authentication-manager>
|
||||
|
||||
<b:import resource="handlermappingintrospector.xml"/>
|
||||
</b:beans>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user