Skip to content

Commit f93a7a2

Browse files
committed
Deprecate HandlerMappingIntrospectorRequestTransformer
Closes gh-16536
1 parent 1fb3fc8 commit f93a7a2

File tree

13 files changed

+540
-116
lines changed

13 files changed

+540
-116
lines changed

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

+43-27
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@
3535
import org.springframework.security.access.PermissionEvaluator;
3636
import org.springframework.security.access.expression.SecurityExpressionHandler;
3737
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
38+
import org.springframework.security.authorization.AuthorizationDecision;
3839
import org.springframework.security.authorization.AuthorizationManager;
40+
import org.springframework.security.authorization.SingleResultAuthorizationManager;
3941
import org.springframework.security.config.ObjectPostProcessor;
4042
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
4143
import org.springframework.security.config.annotation.SecurityBuilder;
@@ -58,13 +60,16 @@
5860
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
5961
import org.springframework.security.web.access.intercept.AuthorizationFilter;
6062
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
63+
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
64+
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
6165
import org.springframework.security.web.debug.DebugFilter;
6266
import org.springframework.security.web.firewall.CompositeRequestRejectedHandler;
6367
import org.springframework.security.web.firewall.HttpFirewall;
6468
import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandler;
6569
import org.springframework.security.web.firewall.ObservationMarkingRequestRejectedHandler;
6670
import org.springframework.security.web.firewall.RequestRejectedHandler;
6771
import org.springframework.security.web.firewall.StrictHttpFirewall;
72+
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
6873
import org.springframework.security.web.util.matcher.RequestMatcher;
6974
import org.springframework.security.web.util.matcher.RequestMatcherEntry;
7075
import org.springframework.util.Assert;
@@ -230,8 +235,8 @@ public WebSecurity addSecurityFilterChainBuilder(
230235

231236
/**
232237
* Set the {@link WebInvocationPrivilegeEvaluator} to be used. If this is not
233-
* specified, then a {@link RequestMatcherDelegatingWebInvocationPrivilegeEvaluator}
234-
* will be created based on the list of {@link SecurityFilterChain}.
238+
* specified, then a {@link AuthorizationManagerWebInvocationPrivilegeEvaluator} will
239+
* be created based on the list of {@link SecurityFilterChain}.
235240
* @param privilegeEvaluator the {@link WebInvocationPrivilegeEvaluator} to use
236241
* @return the {@link WebSecurity} for further customizations
237242
*/
@@ -300,24 +305,33 @@ protected Filter performBuild() throws Exception {
300305
+ ".addSecurityFilterChainBuilder directly");
301306
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
302307
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
303-
List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>();
308+
RequestMatcherDelegatingAuthorizationManager.Builder builder = RequestMatcherDelegatingAuthorizationManager
309+
.builder();
310+
boolean mappings = false;
304311
for (RequestMatcher ignoredRequest : this.ignoredRequests) {
305312
WebSecurity.this.logger.warn("You are asking Spring Security to ignore " + ignoredRequest
306313
+ ". This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.");
307314
SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
308315
securityFilterChains.add(securityFilterChain);
309-
requestMatcherPrivilegeEvaluatorsEntries
310-
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
316+
builder.add(ignoredRequest, SingleResultAuthorizationManager.permitAll());
317+
mappings = true;
311318
}
312319
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
313320
SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
314321
securityFilterChains.add(securityFilterChain);
315-
requestMatcherPrivilegeEvaluatorsEntries
316-
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
322+
mappings = addAuthorizationManager(securityFilterChain, builder) || mappings;
317323
}
318324
if (this.privilegeEvaluator == null) {
325+
AuthorizationManager<HttpServletRequest> authorizationManager = mappings ? builder.build()
326+
: SingleResultAuthorizationManager.permitAll();
327+
AuthorizationManagerWebInvocationPrivilegeEvaluator privilegeEvaluator = new AuthorizationManagerWebInvocationPrivilegeEvaluator(
328+
authorizationManager);
329+
privilegeEvaluator.setServletContext(this.servletContext);
330+
if (this.privilegeEvaluatorRequestTransformer != null) {
331+
privilegeEvaluator.setRequestTransformer(this.privilegeEvaluatorRequestTransformer);
332+
}
319333
this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
320-
requestMatcherPrivilegeEvaluatorsEntries);
334+
List.of(new RequestMatcherEntry<>(AnyRequestMatcher.INSTANCE, List.of(privilegeEvaluator))));
321335
}
322336
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
323337
if (this.httpFirewall != null) {
@@ -350,30 +364,32 @@ else if (!this.observationRegistry.isNoop()) {
350364
return result;
351365
}
352366

353-
private RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>> getRequestMatcherPrivilegeEvaluatorsEntry(
354-
SecurityFilterChain securityFilterChain) {
355-
List<WebInvocationPrivilegeEvaluator> privilegeEvaluators = new ArrayList<>();
367+
private boolean addAuthorizationManager(SecurityFilterChain securityFilterChain,
368+
RequestMatcherDelegatingAuthorizationManager.Builder builder) {
369+
boolean mappings = false;
356370
for (Filter filter : securityFilterChain.getFilters()) {
357-
if (filter instanceof FilterSecurityInterceptor) {
358-
DefaultWebInvocationPrivilegeEvaluator defaultWebInvocationPrivilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator(
359-
(FilterSecurityInterceptor) filter);
360-
defaultWebInvocationPrivilegeEvaluator.setServletContext(this.servletContext);
361-
privilegeEvaluators.add(defaultWebInvocationPrivilegeEvaluator);
371+
if (filter instanceof FilterSecurityInterceptor securityInterceptor) {
372+
DefaultWebInvocationPrivilegeEvaluator privilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator(
373+
securityInterceptor);
374+
privilegeEvaluator.setServletContext(this.servletContext);
375+
AuthorizationManager<RequestAuthorizationContext> authorizationManager = (authentication, context) -> {
376+
HttpServletRequest request = context.getRequest();
377+
boolean result = privilegeEvaluator.isAllowed(request.getContextPath(), request.getRequestURI(),
378+
request.getMethod(), authentication.get());
379+
return new AuthorizationDecision(result);
380+
};
381+
builder.add(securityFilterChain::matches, authorizationManager);
382+
mappings = true;
362383
continue;
363384
}
364-
if (filter instanceof AuthorizationFilter) {
365-
AuthorizationManager<HttpServletRequest> authorizationManager = ((AuthorizationFilter) filter)
366-
.getAuthorizationManager();
367-
AuthorizationManagerWebInvocationPrivilegeEvaluator evaluator = new AuthorizationManagerWebInvocationPrivilegeEvaluator(
368-
authorizationManager);
369-
evaluator.setServletContext(this.servletContext);
370-
if (this.privilegeEvaluatorRequestTransformer != null) {
371-
evaluator.setRequestTransformer(this.privilegeEvaluatorRequestTransformer);
372-
}
373-
privilegeEvaluators.add(evaluator);
385+
if (filter instanceof AuthorizationFilter authorization) {
386+
AuthorizationManager<HttpServletRequest> authorizationManager = authorization.getAuthorizationManager();
387+
builder.add(securityFilterChain::matches,
388+
(authentication, context) -> authorizationManager.check(authentication, context.getRequest()));
389+
mappings = true;
374390
}
375391
}
376-
return new RequestMatcherEntry<>(securityFilterChain::matches, privilegeEvaluators);
392+
return mappings;
377393
}
378394

379395
@Override

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

+20-17
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
7878

7979
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
8080

81+
private static final String PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME = "pathPatternRequestTransformer";
82+
8183
private BeanResolver beanResolver;
8284

8385
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
@@ -119,18 +121,8 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
119121
}
120122
}
121123

122-
/**
123-
* Used to ensure Spring MVC request matching is cached.
124-
*
125-
* Creates a {@link BeanDefinitionRegistryPostProcessor} that detects if a bean named
126-
* HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME is defined. If so, it moves the
127-
* AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME to another bean name
128-
* and then adds a {@link CompositeFilter} that contains
129-
* {@link HandlerMappingIntrospector#createCacheFilter()} and the original
130-
* FilterChainProxy under the original Bean name.
131-
* @return
132-
*/
133124
@Bean
125+
@Deprecated
134126
static BeanDefinitionRegistryPostProcessor springSecurityHandlerMappingIntrospectorBeanDefinitionRegistryPostProcessor() {
135127
return new BeanDefinitionRegistryPostProcessor() {
136128
@Override
@@ -144,12 +136,15 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) t
144136
}
145137

146138
String hmiRequestTransformerBeanName = HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + "RequestTransformer";
147-
if (!registry.containsBeanDefinition(hmiRequestTransformerBeanName)) {
148-
BeanDefinition hmiRequestTransformer = BeanDefinitionBuilder
149-
.rootBeanDefinition(HandlerMappingIntrospectorRequestTransformer.class)
150-
.addConstructorArgReference(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)
151-
.getBeanDefinition();
152-
registry.registerBeanDefinition(hmiRequestTransformerBeanName, hmiRequestTransformer);
139+
if (!registry.containsBeanDefinition(PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME)
140+
&& !registry.containsBeanDefinition(hmiRequestTransformerBeanName)) {
141+
if (!registry.containsBeanDefinition(hmiRequestTransformerBeanName)) {
142+
BeanDefinition hmiRequestTransformer = BeanDefinitionBuilder
143+
.rootBeanDefinition(HandlerMappingIntrospectorRequestTransformer.class)
144+
.addConstructorArgReference(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)
145+
.getBeanDefinition();
146+
registry.registerBeanDefinition(hmiRequestTransformerBeanName, hmiRequestTransformer);
147+
}
153148
}
154149

155150
BeanDefinition filterChainProxy = registry
@@ -178,7 +173,11 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) t
178173
/**
179174
* {@link FactoryBean} to defer creation of
180175
* {@link HandlerMappingIntrospector#createCacheFilter()}
176+
*
177+
* @deprecated see {@link WebSecurityConfiguration} for
178+
* {@link org.springframework.web.util.pattern.PathPattern} replacement
181179
*/
180+
@Deprecated
182181
static class HandlerMappingIntrospectorCacheFilterFactoryBean
183182
implements ApplicationContextAware, FactoryBean<Filter> {
184183

@@ -207,7 +206,11 @@ public Class<?> getObjectType() {
207206
* Extends {@link FilterChainProxy} to provide as much passivity as possible but
208207
* delegates to {@link CompositeFilter} for
209208
* {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}.
209+
*
210+
* @deprecated see {@link WebSecurityConfiguration} for
211+
* {@link org.springframework.web.util.pattern.PathPattern} replacement
210212
*/
213+
@Deprecated
211214
static class CompositeFilterChainProxy extends FilterChainProxy {
212215

213216
/**

0 commit comments

Comments
 (0)