diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurityFilterChainValidator.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurityFilterChainValidator.java index b0bf43fb3b7..23e3641dfe0 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurityFilterChainValidator.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurityFilterChainValidator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,6 +52,9 @@ public void validate(FilterChainProxy filterChainProxy) { private void checkForAnyRequestRequestMatcher(List chains) { DefaultSecurityFilterChain anyRequestFilterChain = null; for (SecurityFilterChain chain : chains) { + if (isWebIgnoredRequests(chain)) { + continue; + } if (anyRequestFilterChain != null) { String message = "A filter chain that matches any request [" + anyRequestFilterChain + "] has already been configured, which means that this filter chain [" + chain @@ -69,6 +72,9 @@ private void checkForAnyRequestRequestMatcher(List chains) private void checkForDuplicateMatchers(List chains) { DefaultSecurityFilterChain filterChain = null; for (SecurityFilterChain chain : chains) { + if (isWebIgnoredRequests(chain)) { + continue; + } if (filterChain != null) { if (chain instanceof DefaultSecurityFilterChain defaultChain) { if (defaultChain.getRequestMatcher().equals(filterChain.getRequestMatcher())) { @@ -110,4 +116,8 @@ private void checkAuthorizationFilters(List chains) { } } + private boolean isWebIgnoredRequests(SecurityFilterChain chain) { + return chain.getFilters().isEmpty(); + } + } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java index e5a3b3cc0b8..368ee6e2bc7 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -142,6 +142,32 @@ public void defaultFiltersPermitAll() throws IOException, ServletException { assertThat(response.getRedirectedUrl()).isEqualTo("/login?logout"); } + @Test + public void validateWhenUseIgnoredRequests() { + this.spring.register(FilterChainProxyWithWebSecurityCustomizer.class); + List filterChains = this.spring.getContext() + .getBean(FilterChainProxy.class) + .getFilterChains(); + assertThat(filterChains.size()).isEqualTo(2); + } + + @Configuration + @EnableWebSecurity + @EnableWebMvc + static class FilterChainProxyWithWebSecurityCustomizer { + + @Bean + WebSecurityCustomizer webSecurityCustomizer() { + return (web) -> web.ignoring().anyRequest(); + } + + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + return http.authorizeHttpRequests((a) -> a.anyRequest().authenticated()).build(); + } + + } + @Configuration @EnableWebSecurity static class FilterChainProxyBuilderMissingConfig {