Creating a custom Bean of type OAuth2AuthorizedClientManager inside a class extending WebSecurityConfigurerAdapter and injection this bean somewhere in the application creates a circular reference.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientService oAuth2AuthorizedClientService) {
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.build();
AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager(
clientRegistrationRepository, oAuth2AuthorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
}
@Service
public class MyBean {
private final OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager;
@Autowired
public MyBean(OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager) {
this.oAuth2AuthorizedClientManager = oAuth2AuthorizedClientManager;
}
}
How to reproduce?
- Download https://github.com/knoobie/spring-2.5-oauth2manager-demo
- Compile the application with
mvn clean install - Test failed
Log
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myBean' defined in file [/home/knoobie/projects/bugs/spring-2.5-security-demo/target/classes/com/example/demo/MyBean.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityConfig': Unsatisfied dependency expressed through method 'setContentNegotationStrategy' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration': Unsatisfied dependency expressed through method 'setConfigurers' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.OAuth2ClientConfiguration$OAuth2ClientWebMvcSecurityConfiguration': Unsatisfied dependency expressed through method 'setAuthorizedClientManager' parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'authorizedClientManager': Requested bean is currently in creation: Is there an unresolvable circular reference?
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityConfig': Unsatisfied dependency expressed through method 'setContentNegotationStrategy' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration': Unsatisfied dependency expressed through method 'setConfigurers' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.OAuth2ClientConfiguration$OAuth2ClientWebMvcSecurityConfiguration': Unsatisfied dependency expressed through method 'setAuthorizedClientManager' parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'authorizedClientManager': Requested bean is currently in creation: Is there an unresolvable circular reference?
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration': Unsatisfied dependency expressed through method 'setConfigurers' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.OAuth2ClientConfiguration$OAuth2ClientWebMvcSecurityConfiguration': Unsatisfied dependency expressed through method 'setAuthorizedClientManager' parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'authorizedClientManager': Requested bean is currently in creation: Is there an unresolvable circular reference?
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.OAuth2ClientConfiguration$OAuth2ClientWebMvcSecurityConfiguration': Unsatisfied dependency expressed through method 'setAuthorizedClientManager' parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'authorizedClientManager': Requested bean is currently in creation: Is there an unresolvable circular reference?
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'authorizedClientManager': Requested bean is currently in creation: Is there an unresolvable circular reference?
Workaround:
- Create the
OAuth2AuthorizedClientManagerbean in another class annotated with@Configuration.
Comment From: wilkinsona
Thanks for the sample.
Your SecurityConfig extends WebSecurityConfigurerAdapter which means that a ContentNegotiationStrategy bean should be injected into it. This bean is defined by Boot's EnableWebMvcConfiguration due to it sub-classing WebMvcConfigurationSupport which defines mvcContentNegotiationManager. To allow EnableWebMvcConfiguration to define this bean, it must be initialized and this requires the injection of any WebMvcConfigurer beans. OAuth2ClientWebMvcSecurityConfiguration is a WebMvcConfigurer so it needs to be initialized and this requires the injection of any OAuth2AuthorizedClientManager beans. Your SecurityConfig defines a OAuth2AuthorizedClientManager bean so it needs to be initialized but its initialization is already in progress. This is a circular reference so initialization fails.
I don't think there's anything that we can do about this in Spring Boot. Defining OAuth2AuthorizedClientManager in another @Configuration class is a good solution. Alternatively, I believe it would also work if the @Bean method was declared static as this would allow the OAuth2AuthorizedClientManager bean to be created without SecurityConfig having to be initialized.
You may also want to raise a Spring Security issue to see if they can remove some of the interdependencies between components so that user code is less likely to inadvertently create a circular reference.
Comment From: knoobie
Thanks @wilkinsona for your explanation!