Skip to content

Commit 3e53cc2

Browse files
committed
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
1 parent f709a9e commit 3e53cc2

File tree

137 files changed

+495
-1570
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

137 files changed

+495
-1570
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java

Lines changed: 12 additions & 329 deletions
Large diffs are not rendered by default.

config/src/main/java/org/springframework/security/config/annotation/web/RequestMatcherFactory.java

Lines changed: 0 additions & 59 deletions
This file was deleted.

config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java

Lines changed: 9 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import jakarta.servlet.ServletResponse;
2929
import jakarta.servlet.http.HttpServletRequest;
3030

31-
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
3231
import org.springframework.beans.factory.ObjectProvider;
3332
import org.springframework.context.ApplicationContext;
3433
import org.springframework.core.OrderComparator;
@@ -45,7 +44,6 @@
4544
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
4645
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
4746
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
48-
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
4947
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
5048
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
5149
import org.springframework.security.config.annotation.web.configurers.AnonymousConfigurer;
@@ -91,17 +89,14 @@
9189
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
9290
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
9391
import org.springframework.security.web.context.SecurityContextRepository;
94-
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
92+
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
9593
import org.springframework.security.web.session.HttpSessionEventPublisher;
96-
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
9794
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
9895
import org.springframework.security.web.util.matcher.OrRequestMatcher;
9996
import org.springframework.security.web.util.matcher.RequestMatcher;
10097
import org.springframework.util.Assert;
101-
import org.springframework.util.ClassUtils;
10298
import org.springframework.web.cors.CorsConfiguration;
10399
import org.springframework.web.filter.CorsFilter;
104-
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
105100

106101
/**
107102
* A {@link HttpSecurity} is similar to Spring Security's XML <http> element in the
@@ -153,12 +148,6 @@
153148
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
154149
implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
155150

156-
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
157-
158-
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
159-
160-
private static final boolean mvcPresent;
161-
162151
private final RequestMatcherConfigurer requestMatcherConfigurer;
163152

164153
private List<OrderedFilter> filters = new ArrayList<>();
@@ -169,10 +158,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
169158

170159
private AuthenticationManager authenticationManager;
171160

172-
static {
173-
mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, HttpSecurity.class.getClassLoader());
174-
}
175-
176161
/**
177162
* Creates a new instance
178163
* @param objectPostProcessor the {@link ObjectPostProcessor} that should be used
@@ -303,9 +288,7 @@ public HttpSecurity headers(Customizer<HeadersConfigurer<HttpSecurity>> headersC
303288
/**
304289
* Adds a {@link CorsFilter} to be used. If a bean by the name of corsFilter is
305290
* provided, that {@link CorsFilter} is used. Else if corsConfigurationSource is
306-
* defined, then that {@link CorsConfiguration} is used. Otherwise, if Spring MVC is
307-
* on the classpath a {@link HandlerMappingIntrospector} is used. You can enable CORS
308-
* using:
291+
* defined, then that {@link CorsConfiguration} is used. You can enable CORS using:
309292
*
310293
* <pre>
311294
* &#064;Configuration
@@ -2174,7 +2157,7 @@ public HttpSecurity securityMatchers(Customizer<RequestMatcherConfigurer> reques
21742157
* {@link #securityMatchers()}
21752158
* </p>
21762159
* @param requestMatcher the {@link RequestMatcher} to use, for example,
2177-
* {@code PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/admin/**")}
2160+
* {@code PathPatternRequestMatcher.pathPattern(HttpMethod.GET, "/admin/**")}
21782161
* @return the {@link HttpSecurity} for further customizations
21792162
* @see #securityMatcher(String...)
21802163
*/
@@ -2185,10 +2168,8 @@ public HttpSecurity securityMatcher(RequestMatcher requestMatcher) {
21852168

21862169
/**
21872170
* Allows configuring the {@link HttpSecurity} to only be invoked when matching the
2188-
* provided pattern. This method creates a {@link MvcRequestMatcher} if Spring MVC is
2189-
* in the classpath or creates an {@link AntPathRequestMatcher} if not. If more
2190-
* advanced configuration is necessary, consider using
2191-
* {@link #securityMatchers(Customizer)} or {@link #securityMatcher(RequestMatcher)}.
2171+
* provided set of {@code patterns}. See
2172+
* {@link org.springframework.web.util.pattern.PathPattern} for matching rules
21922173
*
21932174
* <p>
21942175
* Invoking {@link #securityMatcher(String...)} will override previous invocations of
@@ -2198,19 +2179,14 @@ public HttpSecurity securityMatcher(RequestMatcher requestMatcher) {
21982179
* </p>
21992180
* @param patterns the pattern to match on (i.e. "/admin/**")
22002181
* @return the {@link HttpSecurity} for further customizations
2201-
* @see AntPathRequestMatcher
2202-
* @see MvcRequestMatcher
2182+
* @see org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher
2183+
* @see org.springframework.web.util.pattern.PathPattern
22032184
*/
22042185
public HttpSecurity securityMatcher(String... patterns) {
22052186
List<RequestMatcher> matchers = new ArrayList<>();
2187+
PathPatternRequestMatcher.Builder builder = getContext().getBean(PathPatternRequestMatcher.Builder.class);
22062188
for (String pattern : patterns) {
2207-
if (RequestMatcherFactory.usesPathPatterns()) {
2208-
matchers.add(RequestMatcherFactory.matcher(pattern));
2209-
}
2210-
else {
2211-
RequestMatcher matcher = mvcPresent ? createMvcMatcher(pattern) : createAntMatcher(pattern);
2212-
matchers.add(matcher);
2213-
}
2189+
matchers.add(builder.matcher(pattern));
22142190
}
22152191
this.requestMatcher = new OrRequestMatcher(matchers);
22162192
return this;
@@ -2241,26 +2217,6 @@ public HttpSecurity webAuthn(Customizer<WebAuthnConfigurer<HttpSecurity>> webAut
22412217
return HttpSecurity.this;
22422218
}
22432219

2244-
private RequestMatcher createAntMatcher(String pattern) {
2245-
return new AntPathRequestMatcher(pattern);
2246-
}
2247-
2248-
private RequestMatcher createMvcMatcher(String mvcPattern) {
2249-
ResolvableType type = ResolvableType.forClassWithGenerics(ObjectPostProcessor.class, Object.class);
2250-
ObjectProvider<ObjectPostProcessor<Object>> postProcessors = getContext().getBeanProvider(type);
2251-
ObjectPostProcessor<Object> opp = postProcessors.getObject();
2252-
if (!getContext().containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
2253-
throw new NoSuchBeanDefinitionException("A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME
2254-
+ " of type " + HandlerMappingIntrospector.class.getName()
2255-
+ " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext.");
2256-
}
2257-
HandlerMappingIntrospector introspector = getContext().getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME,
2258-
HandlerMappingIntrospector.class);
2259-
MvcRequestMatcher matcher = new MvcRequestMatcher(introspector, mvcPattern);
2260-
opp.postProcess(matcher);
2261-
return matcher;
2262-
}
2263-
22642220
/**
22652221
* If the {@link SecurityConfigurer} has already been specified get the original,
22662222
* otherwise apply the new {@link SecurityConfigurerAdapter}.

config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
5656
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer;
5757
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
58+
import org.springframework.security.web.access.PathPatternRequestTransformer;
5859
import org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator;
5960
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
6061
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
@@ -422,7 +423,7 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
422423
this.filterChainDecoratorPostProcessor = postProcessor.getIfUnique(ObjectPostProcessor::identity);
423424
Class<HttpServletRequestTransformer> requestTransformerClass = HttpServletRequestTransformer.class;
424425
this.privilegeEvaluatorRequestTransformer = applicationContext.getBeanProvider(requestTransformerClass)
425-
.getIfUnique();
426+
.getIfUnique(PathPatternRequestTransformer::new);
426427
}
427428

428429
@Override

config/src/main/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
3636
import org.springframework.security.config.annotation.authentication.configurers.provisioning.JdbcUserDetailsManagerConfigurer;
3737
import org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer;
38-
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
3938
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
4039
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
4140
import org.springframework.security.config.annotation.web.configurers.DefaultLoginPageConfigurer;
@@ -105,7 +104,6 @@ void setContentNegotiationStrategy(ContentNegotiationStrategy contentNegotiation
105104
@Bean(HTTPSECURITY_BEAN_NAME)
106105
@Scope("prototype")
107106
HttpSecurity httpSecurity() throws Exception {
108-
RequestMatcherFactory.setApplicationContext(this.context);
109107
LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context);
110108
AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(
111109
this.objectPostProcessor, passwordEncoder);

config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java

Lines changed: 0 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,7 @@
2626
import jakarta.servlet.ServletResponse;
2727
import jakarta.servlet.http.HttpServletRequest;
2828

29-
import org.springframework.beans.BeanMetadataElement;
3029
import org.springframework.beans.BeansException;
31-
import org.springframework.beans.factory.FactoryBean;
32-
import org.springframework.beans.factory.config.BeanDefinition;
33-
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
34-
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
35-
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
36-
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
37-
import org.springframework.beans.factory.support.ManagedList;
3830
import org.springframework.context.ApplicationContext;
3931
import org.springframework.context.ApplicationContextAware;
4032
import org.springframework.context.annotation.Bean;
@@ -45,8 +37,6 @@
4537
import org.springframework.security.core.context.SecurityContextHolderStrategy;
4638
import org.springframework.security.web.FilterChainProxy;
4739
import org.springframework.security.web.SecurityFilterChain;
48-
import org.springframework.security.web.access.HandlerMappingIntrospectorRequestTransformer;
49-
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
5040
import org.springframework.security.web.debug.DebugFilter;
5141
import org.springframework.security.web.firewall.HttpFirewall;
5242
import org.springframework.security.web.firewall.RequestRejectedHandler;
@@ -58,7 +48,6 @@
5848
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
5949
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
6050
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
61-
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
6251
import org.springframework.web.servlet.support.RequestDataValueProcessor;
6352

6453
/**
@@ -76,10 +65,6 @@
7665
*/
7766
class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContextAware {
7867

79-
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
80-
81-
private static final String PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME = "pathPatternRequestTransformer";
82-
8368
private BeanResolver beanResolver;
8469

8570
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
@@ -121,86 +106,6 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
121106
}
122107
}
123108

124-
@Bean
125-
static BeanDefinitionRegistryPostProcessor springSecurityHandlerMappingIntrospectorBeanDefinitionRegistryPostProcessor() {
126-
return new BeanDefinitionRegistryPostProcessor() {
127-
@Override
128-
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
129-
}
130-
131-
@Override
132-
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
133-
if (!registry.containsBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
134-
return;
135-
}
136-
137-
String hmiRequestTransformerBeanName = HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + "RequestTransformer";
138-
if (!registry.containsBeanDefinition(PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME)
139-
&& !registry.containsBeanDefinition(hmiRequestTransformerBeanName)) {
140-
if (!registry.containsBeanDefinition(hmiRequestTransformerBeanName)) {
141-
BeanDefinition hmiRequestTransformer = BeanDefinitionBuilder
142-
.rootBeanDefinition(HandlerMappingIntrospectorRequestTransformer.class)
143-
.addConstructorArgReference(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)
144-
.getBeanDefinition();
145-
registry.registerBeanDefinition(hmiRequestTransformerBeanName, hmiRequestTransformer);
146-
}
147-
}
148-
149-
BeanDefinition filterChainProxy = registry
150-
.getBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
151-
152-
if (!filterChainProxy.getResolvableType().isInstance(CompositeFilterChainProxy.class)) {
153-
BeanDefinitionBuilder hmiCacheFilterBldr = BeanDefinitionBuilder
154-
.rootBeanDefinition(HandlerMappingIntrospectorCacheFilterFactoryBean.class)
155-
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
156-
157-
ManagedList<BeanMetadataElement> filters = new ManagedList<>();
158-
filters.add(hmiCacheFilterBldr.getBeanDefinition());
159-
filters.add(filterChainProxy);
160-
BeanDefinitionBuilder compositeSpringSecurityFilterChainBldr = BeanDefinitionBuilder
161-
.rootBeanDefinition(CompositeFilterChainProxy.class)
162-
.addConstructorArgValue(filters);
163-
164-
registry.removeBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
165-
registry.registerBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME,
166-
compositeSpringSecurityFilterChainBldr.getBeanDefinition());
167-
}
168-
}
169-
};
170-
}
171-
172-
/**
173-
* {@link FactoryBean} to defer creation of
174-
* {@link HandlerMappingIntrospector#createCacheFilter()}
175-
*
176-
* @deprecated see {@link WebSecurityConfiguration} for
177-
* {@link org.springframework.web.util.pattern.PathPattern} replacement
178-
*/
179-
@Deprecated
180-
static class HandlerMappingIntrospectorCacheFilterFactoryBean
181-
implements ApplicationContextAware, FactoryBean<Filter> {
182-
183-
private ApplicationContext applicationContext;
184-
185-
@Override
186-
public void setApplicationContext(ApplicationContext applicationContext) {
187-
this.applicationContext = applicationContext;
188-
}
189-
190-
@Override
191-
public Filter getObject() throws Exception {
192-
HandlerMappingIntrospector handlerMappingIntrospector = this.applicationContext
193-
.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, HandlerMappingIntrospector.class);
194-
return handlerMappingIntrospector.createCacheFilter();
195-
}
196-
197-
@Override
198-
public Class<?> getObjectType() {
199-
return Filter.class;
200-
}
201-
202-
}
203-
204109
/**
205110
* Extends {@link FilterChainProxy} to provide as much passivity as possible but
206111
* delegates to {@link CompositeFilter} for

0 commit comments

Comments
 (0)