Fix Customizer.withDefaults() for authorizeHttpRequests
For Spring Boot 3.1.6 with Spring Security where the respective version used behind the scene is 6.1.5
Consider the following code:
@Configuration
@Profile("security")
@EnableWebSecurity(debug=true)
class SecurityConfig {
...
@Bean
SecurityFilterChain filterChain(HttpSecurity http,
@Qualifier("inspectorFilter") Filter filter) throws Exception {
http.authorizeHttpRequests(Customizer.withDefaults())
.formLogin(Customizer.withDefaults())
.addFilterBefore(filter, AnonymousAuthenticationFilter.class);
return http.build();
}
}
Observe the authorizeHttpRequests and formLogin methods use Customizer.withDefaults() when the app starts well, it does not start but fails with the following error message:
[ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration':
Unsatisfied dependency expressed through method 'setFilterChains' parameter 0:
Error creating bean with name 'filterChain' defined in class path resource [com/manuel/jordan/config/SecurityConfig.class]:
Failed to instantiate [org.springframework.security.web.SecurityFilterChain]:
Factory method 'filterChain' threw exception with message:
At least one mapping is required (for example, authorizeHttpRequests().anyRequest().authenticated())
...
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration':
Unsatisfied dependency expressed through method 'setFilterChains' parameter 0:
Error creating bean with name 'filterChain' defined in class path resource [com/manuel/jordan/config/SecurityConfig.class]:
Failed to instantiate [org.springframework.security.web.SecurityFilterChain]:
Factory method 'filterChain' threw exception with message:
At least one mapping is required (for example, authorizeHttpRequests().anyRequest().authenticated())
at
...
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'filterChain' defined in class path resource [com/manuel/jordan/config/SecurityConfig.class]:
Failed to instantiate [org.springframework.security.web.SecurityFilterChain]:
Factory method 'filterChain' threw exception with message:
At least one mapping is required (for example, authorizeHttpRequests().anyRequest().authenticated())
at
...
Caused by: org.springframework.beans.BeanInstantiationException:
Failed to instantiate [org.springframework.security.web.SecurityFilterChain]:
Factory method 'filterChain' threw exception with message:
At least one mapping is required (for example, authorizeHttpRequests().anyRequest().authenticated())
at
...
Caused by: java.lang.IllegalStateException: At least one mapping is required (for example, authorizeHttpRequests().anyRequest().authenticated())
at
The solution is change:
- from
http.authorizeHttpRequests(Customizer.withDefaults()) - to
http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
It as indicated in the error stack trace.
I am not sure if it is expected, but if not - Fix Customizer.withDefaults() for authorizeHttpRequests
Thanks for your understanding
- Manuel
Hi, @manueljordan. This behavior is expected as you pointed out that the stack trace says:
At least one mapping is required (for example, authorizeHttpRequests().anyRequest().authenticated())
Spring Boot configures it to require authentication for every request, however, if you override it, you have to specify what are your authorization rules as Spring Security would not know what would be a proper default for your application.
Hi @marcusdacoregio
It is confuse in someway. So why from the beginning the default behavior is not authorizeHttpRequests().anyRequest().authenticated()?
Good point, @manueljordan. We recommend users be explicit about their security configuration, especially when dealing with request authorization. However, if we have a default for everything it makes sense to have a default for that too. The ServerHttpSecurity#authorizeExchange allows us to use Customizer.withDefaults() and considers the DelegatingReactiveAuthorizationManager defaults, which is to deny all. I will bring this to the team's attention and decide how we move forward.