From 95e3f3714bbb6bda0c2046012209b14ab398522c Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Thu, 24 Oct 2024 20:38:57 -0600 Subject: [PATCH] Improve Error Message for Conflicting Filter Chains Closes gh-15874 --- .../annotation/web/builders/WebSecurity.java | 12 ++++----- .../web/DefaultSecurityFilterChain.java | 26 ++++++++++++++++--- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java index 43329137fcf..3b79973e2d8 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java @@ -302,16 +302,16 @@ protected Filter performBuild() throws Exception { requestMatcherPrivilegeEvaluatorsEntries .add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain)); } - boolean anyRequestConfigured = false; + DefaultSecurityFilterChain anyRequestConfigured = null; for (SecurityBuilder securityFilterChainBuilder : this.securityFilterChainBuilders) { SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build(); - Assert.isTrue(!anyRequestConfigured, - "A filter chain that matches any request has already been configured, which means that this filter chain [" - + securityFilterChain - + "] will never get invoked. Please use `HttpSecurity#securityMatcher` to ensure that there is only one filter chain configured for 'any request' and that the 'any request' filter chain is published last."); + Assert.isTrue(anyRequestConfigured == null, "A filter chain that matches any request [" + + anyRequestConfigured + "] has already been configured, which means that this filter chain [" + + securityFilterChain + + "] will never get invoked. Please use `HttpSecurity#securityMatcher` to ensure that there is only one filter chain configured for 'any request' and that the 'any request' filter chain is published last."); if (securityFilterChain instanceof DefaultSecurityFilterChain defaultSecurityFilterChain) { if (defaultSecurityFilterChain.getRequestMatcher() instanceof AnyRequestMatcher) { - anyRequestConfigured = true; + anyRequestConfigured = defaultSecurityFilterChain; } } securityFilterChains.add(securityFilterChain); diff --git a/web/src/main/java/org/springframework/security/web/DefaultSecurityFilterChain.java b/web/src/main/java/org/springframework/security/web/DefaultSecurityFilterChain.java index b5908be016c..06adfe5fe9d 100644 --- a/web/src/main/java/org/springframework/security/web/DefaultSecurityFilterChain.java +++ b/web/src/main/java/org/springframework/security/web/DefaultSecurityFilterChain.java @@ -24,7 +24,9 @@ import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import reactor.util.annotation.NonNull; +import org.springframework.beans.factory.BeanNameAware; import org.springframework.core.log.LogMessage; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.StringUtils; @@ -36,7 +38,7 @@ * @author Jinwoo Bae * @since 3.1 */ -public final class DefaultSecurityFilterChain implements SecurityFilterChain { +public final class DefaultSecurityFilterChain implements SecurityFilterChain, BeanNameAware { private static final Log logger = LogFactory.getLog(DefaultSecurityFilterChain.class); @@ -44,6 +46,8 @@ public final class DefaultSecurityFilterChain implements SecurityFilterChain { private final List filters; + private String beanName; + public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) { this(requestMatcher, Arrays.asList(filters)); } @@ -80,8 +84,24 @@ public boolean matches(HttpServletRequest request) { @Override public String toString() { - return this.getClass().getSimpleName() + " [RequestMatcher=" + this.requestMatcher + ", Filters=" + this.filters - + "]"; + List filterNames = new ArrayList<>(); + for (Filter filter : this.filters) { + String name = filter.getClass().getSimpleName(); + if (name.endsWith("Filter")) { + name = name.substring(0, name.length() - "Filter".length()); + } + filterNames.add(name); + } + String declaration = this.getClass().getSimpleName(); + if (this.beanName != null) { + declaration += " defined as '" + this.beanName + "'"; + } + return declaration + " matching [" + this.requestMatcher + "] and having filters " + filterNames; + } + + @Override + public void setBeanName(@NonNull String name) { + this.beanName = name; } }