I have below configuration for a simple project
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http.cors(corsSpec -> Customizer.withDefaults())
.oauth2Login(oAuth2LoginSpec -> Customizer.withDefaults())
.authorizeExchange(exchange -> exchange.pathMatchers("/actuator/**").permitAll().anyExchange().authenticated())
.headers(headers -> headers.frameOptions(option -> option.disable().xssProtection(ServerHttpSecurity.HeaderSpec.XssProtectionSpec::disable)))
.csrf(ServerHttpSecurity.CsrfSpec::disable)
.httpBasic(ServerHttpSecurity.HttpBasicSpec::disable)
.formLogin(ServerHttpSecurity.FormLoginSpec::disable)
.build();
}
}
After upgrade from 3.4.0 to 3.5.0, the application failed at startup.
Caused by: java.lang.IllegalArgumentException: clientRegistrationRepository cannot be null
at org.springframework.util.Assert.notNull(Assert.java:181) ~[spring-core-6.2.7.jar:6.2.7]
at org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService.<init>(InMemoryReactiveOAuth2AuthorizedClientService.java:54) ~[spring-security-oauth2-client-6.5.0.jar:6.5.0]
at org.springframework.security.config.web.server.ServerHttpSecurity$OAuth2LoginSpec.getAuthorizedClientService(ServerHttpSecurity.java:4692) ~[spring-security-config-6.5.0.jar:6.5.0]
at org.springframework.security.config.web.server.ServerHttpSecurity$OAuth2LoginSpec.getAuthorizedClientRepository(ServerHttpSecurity.java:4665) ~[spring-security-config-6.5.0.jar:6.5.0]
at org.springframework.security.config.web.server.ServerHttpSecurity$OAuth2LoginSpec.configure(ServerHttpSecurity.java:4487) ~[spring-security-config-6.5.0.jar:6.5.0]
at org.springframework.security.config.web.server.ServerHttpSecurity.build(ServerHttpSecurity.java:1676) ~[spring-security-config-6.5.0.jar:6.5.0]
at com.saikul.springbootadmin.config.SecurityConfig.springSecurityFilterChain(SecurityConfig.java:23) ~[classes/:na]
at com.saikul.springbootadmin.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$springSecurityFilterChain$0(<generated>) ~[classes/:na]
From trace logs, I can see this bean is actually registered
o.s.b.a.s.o.c.ClientsConfiguredCondition : Condition ClientsConfiguredCondition on org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientConfigurations$ClientRegistrationRepositoryConfiguration matched due to OAuth2 Clients Configured Condition found registered clients spring-boot-admin
o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'autoConfigurationReport'
o.s.b.a.condition.OnBeanCondition : Condition OnBeanCondition on org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientConfigurations$ClientRegistrationRepositoryConfiguration matched due to @ConditionalOnMissingBean (types: org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; SearchStrategy: all) did not find any beans
o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'autoConfigurationReport'
a.ConfigurationClassBeanDefinitionReader : Registered bean definition for imported class 'org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientConfigurations$ClientRegistrationRepositoryConfiguration'
a.ConfigurationClassBeanDefinitionReader : Registering bean definition for @Bean method org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientConfigurations$ClientRegistrationRepositoryConfiguration.clientRegistrationRepository()
o.s.b.a.condition.OnBeanCondition : Condition OnBeanCondition on org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientConfigurations$OAuth2AuthorizedClientServiceConfiguration matched due to @ConditionalOnBean (types: org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; SearchStrategy: all) found bean 'clientRegistrationRepository'
...
...
...
OAuth2ClientConfigurations.ClientRegistrationRepositoryConfiguration matched:
- OAuth2 Clients Configured Condition found registered clients spring-boot-admin (ClientsConfiguredCondition)
- @ConditionalOnMissingBean (types: org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; SearchStrategy: all) did not find any beans (OnBeanCondition)
OAuth2ClientConfigurations.OAuth2AuthorizedClientServiceConfiguration matched:
- @ConditionalOnBean (types: org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; SearchStrategy: all) found bean 'clientRegistrationRepository' (OnBeanCondition)
From source code of ServerHttpSecurity#getClientRegistrationRepository
, I can see this error is caused by not able to find bean clientRegistrationRepository. But from logs above, I can see the bean has been registered.
I tried to add break point in class OAuth2ClientConfigurations
, which produced this bean, but the break point was never hit.
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnOAuth2ClientRegistrationProperties
@EnableConfigurationProperties({OAuth2ClientProperties.class})
@ConditionalOnMissingBean({ClientRegistrationRepository.class})
static class ClientRegistrationRepositoryConfiguration {
@Bean
InMemoryClientRegistrationRepository clientRegistrationRepository(OAuth2ClientProperties properties) {
List<ClientRegistration> registrations = new ArrayList((new OAuth2ClientPropertiesMapper(properties)).asClientRegistrations().values());
return new InMemoryClientRegistrationRepository(registrations);
}
}
Below is my configuration in application.yaml
spring:
security:
oauth2:
client:
registration:
keycloak:
client-id: some-client-id
scope: openid
provider:
keycloak:
issuer-uri: https://keycloak/realms/sinzetech
user-name-attribute: preferred_username
Comment From: snicoll
@clockrun lots going on here. Pasting our own code is not very helpful I am afraid. Can you please prepare a small sample that reproduces the error you've described? You can share it with us by zipping up the code and attaching it here or pushing the code to a separate GitHub repository.
Comment From: clockrun
hi @snicoll , Below is our code. spring-boot-admin.zip
Comment From: wilkinsona
Thanks for the sample.
The sample depends on both spring-boot-starter-web and spring-boot-starter-webflux. The former is preferred so it's a servlet-based web application. However, you're trying to configure WebFlux-based security. This is an unsupported combinations and it fails as there is no ReactiveClientRegistrationRepository
bean available in the context. The clientRegistrationRepository
that has been configured is for non-reactive apps and cannot be used by Spring Security's WebFlux support.
You can avoid the problem by explicitly configuring your web application to be reactive:
spring:
main:
web-application-type: reactive
However, this may cause problems with your dependencies as Jolokia depends on spring-boot-starter-web for Servlet-based web apps. You may lose some Jolokia-related functionality as a result so I'd recommend reviewing your dependencies and adjusting them as required to meet your needs.
I should also note that I see the same problem with Spring Boot 3.4.x (both 3.4.0 and 3.4.6). That's to be expected due to trying to use WebFlux security with a Servlet-based app.
Comment From: clockrun
hi Wilkinsona, Thanks for your reply. You are right, it is caused by an unwanted dependency of spring-boot-starter-web. This dependency is introduced by jolokia 2.2.9. When I was using spring-boot 3.4.0 with jolokia 2.1.2, there was no such dependency. But in latest version, they added auto configurer for servlet based application, and this breaks my application which is based on webflux.
Regards, Clockrun
Comment From: tompson
We are encountering a very similar issue. We habe a Spring Web MVC application that contains both Service and Webflux dependencies (because of Spring AI)
we explicitly configured
spring.main.web-application-type=servlet
but still after upgrading from 3.4.7 to 3.5.3 the InMemoryClientRegistrationRepository
is missing
Comment From: snicoll
@tompson this issue is closed. Please open a new issue with a small sample that we can run ourselves to reproduce.