Merge branch '6.1.x' into 6.2.x

Use CompositeFilterChainProxy
This commit is contained in:
Rob Winch 2023-12-15 01:16:21 -06:00
commit c7047add5d
1 changed files with 78 additions and 20 deletions

View File

@ -16,9 +16,14 @@
package org.springframework.security.config.annotation.web.configuration; package org.springframework.security.config.annotation.web.configuration;
import java.io.IOException;
import java.util.List; import java.util.List;
import jakarta.servlet.Filter; 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 jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.BeanMetadataElement;
@ -26,7 +31,6 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
@ -42,6 +46,8 @@ import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.HandlerMappingIntrospectorRequestTransformer; import org.springframework.security.web.access.HandlerMappingIntrospectorRequestTransformer;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.RequestRejectedHandler;
import org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver; import org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver;
import org.springframework.security.web.method.annotation.CsrfTokenArgumentResolver; import org.springframework.security.web.method.annotation.CsrfTokenArgumentResolver;
import org.springframework.security.web.method.annotation.CurrentSecurityContextArgumentResolver; import org.springframework.security.web.method.annotation.CurrentSecurityContextArgumentResolver;
@ -135,11 +141,8 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
registry.registerBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + "RequestTransformer", registry.registerBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + "RequestTransformer",
hmiRequestTransformer); hmiRequestTransformer);
String filterChainProxyBeanName = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME
+ "Proxy";
BeanDefinition filterChainProxy = registry BeanDefinition filterChainProxy = registry
.getBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME); .getBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
registry.registerBeanDefinition(filterChainProxyBeanName, filterChainProxy);
BeanDefinitionBuilder hmiCacheFilterBldr = BeanDefinitionBuilder BeanDefinitionBuilder hmiCacheFilterBldr = BeanDefinitionBuilder
.rootBeanDefinition(HandlerMappingIntrospectorCachFilterFactoryBean.class) .rootBeanDefinition(HandlerMappingIntrospectorCachFilterFactoryBean.class)
@ -147,9 +150,9 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
ManagedList<BeanMetadataElement> filters = new ManagedList<>(); ManagedList<BeanMetadataElement> filters = new ManagedList<>();
filters.add(hmiCacheFilterBldr.getBeanDefinition()); filters.add(hmiCacheFilterBldr.getBeanDefinition());
filters.add(new RuntimeBeanReference(filterChainProxyBeanName)); filters.add(filterChainProxy);
BeanDefinitionBuilder compositeSpringSecurityFilterChainBldr = BeanDefinitionBuilder BeanDefinitionBuilder compositeSpringSecurityFilterChainBldr = BeanDefinitionBuilder
.rootBeanDefinition(SpringSecurityFilterCompositeFilter.class) .rootBeanDefinition(CompositeFilterChainProxy.class)
.addConstructorArgValue(filters); .addConstructorArgValue(filters);
registry.removeBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME); registry.removeBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
@ -188,21 +191,73 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
} }
/** /**
* Extension to {@link CompositeFilter} to expose private methods used by Spring * Extends {@link FilterChainProxy} to provide as much passivity as possible but
* Security's test support * delegates to {@link CompositeFilter} for
* {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}.
*/ */
static class SpringSecurityFilterCompositeFilter extends CompositeFilter { static class CompositeFilterChainProxy extends FilterChainProxy {
private FilterChainProxy springSecurityFilterChain; /**
* Used for {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}
*/
private final Filter doFilterDelegate;
SpringSecurityFilterCompositeFilter(List<? extends Filter> filters) { private final FilterChainProxy springSecurityFilterChain;
setFilters(filters); // for the parent
/**
* Creates a new instance
* @param filters the Filters to delegate to. One of which must be
* FilterChainProxy.
*/
CompositeFilterChainProxy(List<? extends Filter> filters) {
this.doFilterDelegate = createDoFilterDelegate(filters);
this.springSecurityFilterChain = findFilterChainProxy(filters);
} }
@Override @Override
public void setFilters(List<? extends Filter> filters) { public void afterPropertiesSet() {
super.setFilters(filters); this.springSecurityFilterChain.afterPropertiesSet();
this.springSecurityFilterChain = findFilterChainProxy(filters); }
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
this.doFilterDelegate.doFilter(request, response, chain);
}
@Override
public List<Filter> getFilters(String url) {
return this.springSecurityFilterChain.getFilters(url);
}
@Override
public List<SecurityFilterChain> getFilterChains() {
return this.springSecurityFilterChain.getFilterChains();
}
@Override
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
this.springSecurityFilterChain.setSecurityContextHolderStrategy(securityContextHolderStrategy);
}
@Override
public void setFilterChainValidator(FilterChainValidator filterChainValidator) {
this.springSecurityFilterChain.setFilterChainValidator(filterChainValidator);
}
@Override
public void setFilterChainDecorator(FilterChainDecorator filterChainDecorator) {
this.springSecurityFilterChain.setFilterChainDecorator(filterChainDecorator);
}
@Override
public void setFirewall(HttpFirewall firewall) {
this.springSecurityFilterChain.setFirewall(firewall);
}
@Override
public void setRequestRejectedHandler(RequestRejectedHandler requestRejectedHandler) {
this.springSecurityFilterChain.setRequestRejectedHandler(requestRejectedHandler);
} }
/** /**
@ -212,7 +267,7 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
* @return * @return
*/ */
private List<? extends Filter> getFilters(HttpServletRequest request) { private List<? extends Filter> getFilters(HttpServletRequest request) {
List<SecurityFilterChain> filterChains = getFilterChainProxy().getFilterChains(); List<SecurityFilterChain> filterChains = this.springSecurityFilterChain.getFilterChains();
for (SecurityFilterChain chain : filterChains) { for (SecurityFilterChain chain : filterChains) {
if (chain.matches(request)) { if (chain.matches(request)) {
return chain.getFilters(); return chain.getFilters();
@ -222,11 +277,14 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
} }
/** /**
* Used by Spring Security's Test support to find the FilterChainProxy * Creates the Filter to delegate to for doFilter
* @return * @param filters the Filters to delegate to.
* @return the Filter for doFilter
*/ */
private FilterChainProxy getFilterChainProxy() { private static Filter createDoFilterDelegate(List<? extends Filter> filters) {
return this.springSecurityFilterChain; CompositeFilter delegate = new CompositeFilter();
delegate.setFilters(filters);
return delegate;
} }
/** /**