While migrating to the new Spring Boot 3.4 version I am facing the following error in a project with RSocket, Spring Security and Spring Webflux:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method setAuthenticationManagerPostProcessor in org.springframework.security.config.annotation.web.reactive.ServerHttpSecurityConfiguration required a single bean, but 2 were found:
- authenticationManagerPostProcessor: defined by method 'authenticationManagerPostProcessor' in class path resource [org/springframework/security/config/annotation/web/reactive/ReactiveObservationConfiguration.class]
- rSocketAuthenticationManagerPostProcessor: defined by method 'rSocketAuthenticationManagerPostProcessor' in class path resource [org/springframework/security/config/annotation/rsocket/ReactiveObservationConfiguration.class]
This may be due to missing parameter name information
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
I was able to reproduce this in a simple project which you can find at https://github.com/joaodias14/Spring-Boot-RSocket. I simply used https://start.spring.io/ with Spring Boot 3.4.0 and RSocket, Spring Reactive Web and Spring Security as dependencies. If I run it with ./mvnw -o spring-boot:run I get the error above.
Comment From: jzheaux
Thanks for the report, @joaodias14. I'm able to reproduce this issue; we'll get a fix out in the next maintenance release.
In the meantime, if you are not using Security's Observability integration, then you can do:
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@Primary
static ObjectPostProcessor<ReactiveAuthorizationManager<ServerWebExchange>> primaryAuthorizationManagerPostProcessor() {
return ObjectPostProcessor.identity();
}
@Bean
@Role(2)
@Primary
static ObjectPostProcessor<ReactiveAuthenticationManager> primaryAuthenticationManagerPostProcessor() {
return ObjectPostProcessor.identity();
}
@Bean
@Role(2)
@Primary
static ObjectPostProcessor<WebFilterChainProxy.WebFilterChainDecorator> primaryFilterChainDecoratorPostProcessor() {
return ObjectPostProcessor.identity();
}
Or, if you are, then you can instead do:
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@Primary
static ObjectPostProcessor<ReactiveAuthorizationManager<ServerWebExchange>> primaryAuthorizationManagerPostProcessor(
ObjectProvider<ObservationRegistry> registry) {
return new ObjectPostProcessor<>() {
@Override
public ReactiveAuthorizationManager postProcess(ReactiveAuthorizationManager object) {
ObservationRegistry r = registry.getIfUnique(() -> ObservationRegistry.NOOP);
return new ObservationReactiveAuthorizationManager<>(r, object);
}
};
}
@Bean
@Role(2)
@Primary
static ObjectPostProcessor<ReactiveAuthenticationManager> primaryAuthenticationManagerPostProcessor(ObjectProvider<ObservationRegistry> registry) {
return new ObjectPostProcessor<>() {
public ReactiveAuthenticationManager postProcess(ReactiveAuthenticationManager object) {
ObservationRegistry r = registry.getIfUnique(() -> ObservationRegistry.NOOP);
return new ObservationReactiveAuthenticationManager(r, object);
}
};
}
@Bean
@Role(2)
@Primary
static ObjectPostProcessor<WebFilterChainProxy.WebFilterChainDecorator> primaryFilterChainDecoratorPostProcessor(ObjectProvider<ObservationRegistry> registry) {
return new ObjectPostProcessor<>() {
public WebFilterChainProxy.WebFilterChainDecorator postProcess(WebFilterChainProxy.WebFilterChainDecorator object) {
ObservationRegistry r = registry.getIfUnique(() -> ObservationRegistry.NOOP);
return new ObservationWebFilterChainDecorator(r);
}
};
}
Comment From: ngocnhan-tran1996
@jzheaux
We will add @Primary or have another handle way when both RSocket and Webflux are on classpath?
Comment From: joaodias14
Many thanks for the quick workaround @jzheaux !
Comment From: jzheaux
Good question, @ngocnhan-tran1996, please see the commit for details; it disambiguates in the setter to preserve Spring Security's getIfUnique semantics.