diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerUtils.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerUtils.java index 646c32accf..bb62ef2422 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerUtils.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerUtils.java @@ -16,6 +16,7 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.client; import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoUniqueBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; @@ -23,6 +24,7 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.util.StringUtils; import java.util.Map; @@ -47,7 +49,16 @@ final class OAuth2ClientConfigurerUtils { } private static > ClientRegistrationRepository getClientRegistrationRepositoryBean(B builder) { - return builder.getSharedObject(ApplicationContext.class).getBean(ClientRegistrationRepository.class); + Map clientRegistrationRepositoryMap = BeanFactoryUtils.beansOfTypeIncludingAncestors( + builder.getSharedObject(ApplicationContext.class), ClientRegistrationRepository.class); + if (clientRegistrationRepositoryMap.isEmpty()) { + throw new NoSuchBeanDefinitionException(ClientRegistrationRepository.class); + } else if (clientRegistrationRepositoryMap.size() > 1) { + throw new NoUniqueBeanDefinitionException(ClientRegistrationRepository.class, clientRegistrationRepositoryMap.size(), + "Expected single matching bean of type '" + ClientRegistrationRepository.class.getName() + "' but found " + + clientRegistrationRepositoryMap.size() + ": " + StringUtils.collectionToCommaDelimitedString(clientRegistrationRepositoryMap.keySet())); + } + return clientRegistrationRepositoryMap.values().iterator().next(); } static > OAuth2AuthorizedClientService getAuthorizedClientService(B builder) { @@ -67,7 +78,8 @@ final class OAuth2ClientConfigurerUtils { builder.getSharedObject(ApplicationContext.class), OAuth2AuthorizedClientService.class); if (authorizedClientServiceMap.size() > 1) { throw new NoUniqueBeanDefinitionException(OAuth2AuthorizedClientService.class, authorizedClientServiceMap.size(), - "Only one matching @Bean of type " + OAuth2AuthorizedClientService.class.getName() + " should be registered."); + "Expected single matching bean of type '" + OAuth2AuthorizedClientService.class.getName() + "' but found " + + authorizedClientServiceMap.size() + ": " + StringUtils.collectionToCommaDelimitedString(authorizedClientServiceMap.keySet())); } return (!authorizedClientServiceMap.isEmpty() ? authorizedClientServiceMap.values().iterator().next() : null); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java index c548224549..86a7347694 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java @@ -17,6 +17,7 @@ package org.springframework.security.config.annotation.web.configuration; import org.junit.Rule; import org.junit.Test; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoUniqueBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -101,7 +102,8 @@ public class OAuth2ClientConfigurationTests { public void loadContextWhenOAuth2AuthorizedClientServiceRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() { assertThatThrownBy(() -> this.spring.register(OAuth2AuthorizedClientServiceRegisteredTwiceConfig.class).autowire()) .hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class) - .hasMessageContaining("Only one matching @Bean of type " + OAuth2AuthorizedClientService.class.getName() + " should be registered."); + .hasMessageContaining("Expected single matching bean of type '" + OAuth2AuthorizedClientService.class.getName() + + "' but found 2: authorizedClientService1,authorizedClientService2"); } @EnableWebMvc @@ -110,11 +112,13 @@ public class OAuth2ClientConfigurationTests { @Override protected void configure(HttpSecurity http) throws Exception { + // @formatter:off http .authorizeRequests() .anyRequest().authenticated() .and() .oauth2Login(); + // @formatter:on } @Bean @@ -132,4 +136,66 @@ public class OAuth2ClientConfigurationTests { return mock(OAuth2AuthorizedClientService.class); } } + + @Test + public void loadContextWhenClientRegistrationRepositoryNotRegisteredThenThrowNoSuchBeanDefinitionException() { + assertThatThrownBy(() -> this.spring.register(ClientRegistrationRepositoryNotRegisteredConfig.class).autowire()) + .hasRootCauseInstanceOf(NoSuchBeanDefinitionException.class) + .hasMessageContaining("No qualifying bean of type '" + ClientRegistrationRepository.class.getName() + "' available"); + } + + @EnableWebMvc + @EnableWebSecurity + static class ClientRegistrationRepositoryNotRegisteredConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().authenticated() + .and() + .oauth2Login(); + // @formatter:on + } + } + + @Test + public void loadContextWhenClientRegistrationRepositoryRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() { + assertThatThrownBy(() -> this.spring.register(ClientRegistrationRepositoryRegisteredTwiceConfig.class).autowire()) + .hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class) + .hasMessageContaining("Expected single matching bean of type '" + ClientRegistrationRepository.class.getName() + + "' but found 2: clientRegistrationRepository1,clientRegistrationRepository2"); + } + + @EnableWebMvc + @EnableWebSecurity + static class ClientRegistrationRepositoryRegisteredTwiceConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().authenticated() + .and() + .oauth2Login(); + // @formatter:on + } + + @Bean + public ClientRegistrationRepository clientRegistrationRepository1() { + return mock(ClientRegistrationRepository.class); + } + + @Bean + public ClientRegistrationRepository clientRegistrationRepository2() { + return mock(ClientRegistrationRepository.class); + } + + @Bean + public OAuth2AuthorizedClientService authorizedClientService() { + return mock(OAuth2AuthorizedClientService.class); + } + } }