Bladeren bron

Improve Error Message for Conflicting Filter Chains

Closes gh-15874
Josh Cummings 10 maanden geleden
bovenliggende
commit
f46e56de78

+ 8 - 6
config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java

@@ -302,16 +302,18 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
 			requestMatcherPrivilegeEvaluatorsEntries
 			requestMatcherPrivilegeEvaluatorsEntries
 				.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
 				.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
 		}
 		}
-		boolean anyRequestConfigured = false;
+		DefaultSecurityFilterChain anyRequestFilterChain = null;
 		for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
 		for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
 			SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
 			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.");
+			if (anyRequestFilterChain != null) {
+				String message = "A filter chain that matches any request [" + anyRequestFilterChain
+						+ "] 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.";
+				throw new IllegalArgumentException(message);
+			}
 			if (securityFilterChain instanceof DefaultSecurityFilterChain defaultSecurityFilterChain) {
 			if (securityFilterChain instanceof DefaultSecurityFilterChain defaultSecurityFilterChain) {
 				if (defaultSecurityFilterChain.getRequestMatcher() instanceof AnyRequestMatcher) {
 				if (defaultSecurityFilterChain.getRequestMatcher() instanceof AnyRequestMatcher) {
-					anyRequestConfigured = true;
+					anyRequestFilterChain = defaultSecurityFilterChain;
 				}
 				}
 			}
 			}
 			securityFilterChains.add(securityFilterChain);
 			securityFilterChains.add(securityFilterChain);

+ 44 - 3
web/src/main/java/org/springframework/security/web/DefaultSecurityFilterChain.java

@@ -24,7 +24,14 @@ import jakarta.servlet.Filter;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletRequest;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.logging.LogFactory;
+import reactor.util.annotation.NonNull;
 
 
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.BeanNameAware;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
 import org.springframework.core.log.LogMessage;
 import org.springframework.core.log.LogMessage;
 import org.springframework.security.web.util.matcher.RequestMatcher;
 import org.springframework.security.web.util.matcher.RequestMatcher;
 import org.springframework.util.StringUtils;
 import org.springframework.util.StringUtils;
@@ -36,7 +43,7 @@ import org.springframework.util.StringUtils;
  * @author Jinwoo Bae
  * @author Jinwoo Bae
  * @since 3.1
  * @since 3.1
  */
  */
-public final class DefaultSecurityFilterChain implements SecurityFilterChain {
+public final class DefaultSecurityFilterChain implements SecurityFilterChain, BeanNameAware, BeanFactoryAware {
 
 
 	private static final Log logger = LogFactory.getLog(DefaultSecurityFilterChain.class);
 	private static final Log logger = LogFactory.getLog(DefaultSecurityFilterChain.class);
 
 
@@ -44,6 +51,10 @@ public final class DefaultSecurityFilterChain implements SecurityFilterChain {
 
 
 	private final List<Filter> filters;
 	private final List<Filter> filters;
 
 
+	private String beanName;
+
+	private ConfigurableListableBeanFactory beanFactory;
+
 	public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) {
 	public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) {
 		this(requestMatcher, Arrays.asList(filters));
 		this(requestMatcher, Arrays.asList(filters));
 	}
 	}
@@ -80,8 +91,38 @@ public final class DefaultSecurityFilterChain implements SecurityFilterChain {
 
 
 	@Override
 	@Override
 	public String toString() {
 	public String toString() {
-		return this.getClass().getSimpleName() + " [RequestMatcher=" + this.requestMatcher + ", Filters=" + this.filters
-				+ "]";
+		List<String> 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 + "'";
+			if (this.beanFactory != null) {
+				BeanDefinition bd = this.beanFactory.getBeanDefinition(this.beanName);
+				String description = bd.getResourceDescription();
+				if (description != null) {
+					declaration += " in [" + description + "]";
+				}
+			}
+		}
+		return declaration + " matching [" + this.requestMatcher + "] and having filters " + filterNames;
+	}
+
+	@Override
+	public void setBeanName(@NonNull String name) {
+		this.beanName = name;
+	}
+
+	@Override
+	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+		if (beanFactory instanceof ConfigurableListableBeanFactory listable) {
+			this.beanFactory = listable;
+		}
 	}
 	}
 
 
 }
 }