Parcourir la source

Polish gh-4557

Joe Grandja il y a 5 ans
Parent
commit
ff8002eb2e
27 fichiers modifiés avec 595 ajouts et 909 suppressions
  1. 36 39
      config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java
  2. 79 87
      config/src/main/java/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParser.java
  3. 1 1
      config/src/main/java/org/springframework/security/config/http/SecurityFilters.java
  4. 89 75
      config/src/main/java/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParser.java
  5. 16 16
      config/src/main/resources/org/springframework/security/config/spring-security-5.3.rnc
  6. 16 16
      config/src/main/resources/org/springframework/security/config/spring-security-5.3.xsd
  7. 155 298
      config/src/test/java/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests.java
  8. 90 103
      config/src/test/java/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParserTests.java
  9. 9 9
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-MultiClientRegistration-WithCustomConfiguration.xml
  10. 9 9
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-MultiClientRegistration-WithCustomGrantedAuthorities.xml
  11. 6 6
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-MultiClientRegistration-WithCustomLoginProcessingUrl.xml
  12. 1 1
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithCustomAuthenticationFailureHandler.xml
  13. 2 2
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithCustomAuthorizationRequestResolver.xml
  14. 7 7
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithJwtDecoderFactory.xml
  15. 9 10
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithJwtDecoderFactoryAndDefaultSuccessHandler.xml
  16. 0 57
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithTestConfiguration.xml
  17. 0 52
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithinSameFile.xml
  18. 24 1
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration.xml
  19. 0 49
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-WithCustomAuthorizationRequestRepository.xml
  20. 5 5
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-WithCustomAuthorizedClientRepository.xml
  21. 5 5
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-WithCustomAuthorizedClientService.xml
  22. 4 5
      config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-WithCustomClientRegistrationRepository.xml
  23. 0 39
      config/src/test/resources/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParserTests-FromIssuerUri.xml
  24. 1 1
      config/src/test/resources/org/springframework/security/config/oauth2/client/google-github-registration.xml
  25. 14 14
      docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc
  26. 12 1
      oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/TestOAuth2AccessTokenResponses.java
  27. 5 1
      oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/TestOAuth2AuthorizationRequests.java

+ 36 - 39
config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java

@@ -139,12 +139,10 @@ final class AuthenticationConfigBuilder {
 	private String openIDLoginPage;
 
 	private String oauth2LoginFilterId;
-	private String oauth2AuthorizationRequestRedirectFilterId;
 	private BeanDefinition oauth2AuthorizationRequestRedirectFilter;
 	private BeanDefinition oauth2LoginEntryPoint;
 	private BeanReference oauth2LoginAuthenticationProviderRef;
 	private BeanReference oauth2LoginOidcAuthenticationProviderRef;
-
 	private BeanDefinition oauth2LoginLinks;
 
 	AuthenticationConfigBuilder(Element element, boolean forceAutoConfig,
@@ -247,43 +245,42 @@ final class AuthenticationConfigBuilder {
 
 	void createOAuth2LoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
 		Element oauth2LoginElt = DomUtils.getChildElementByTagName(this.httpElt, Elements.OAUTH2_LOGIN);
-		if (oauth2LoginElt != null) {
-			OAuth2LoginBeanDefinitionParser parser = new OAuth2LoginBeanDefinitionParser(requestCache, portMapper,
-					portResolver, sessionStrategy, allowSessionCreation);
-			BeanDefinition oauth2LoginFilterBean = parser.parse(oauth2LoginElt, this.pc);
-			oauth2LoginFilterBean.getPropertyValues().addPropertyValue("authenticationManager", authManager);
-
-			// retrieve the other bean result
-			BeanDefinition oauth2LoginAuthProvider = parser.getOAuth2LoginAuthenticationProvider();
-			oauth2AuthorizationRequestRedirectFilter = parser.getOAuth2AuthorizationRequestRedirectFilter();
-			oauth2LoginEntryPoint = parser.getOAuth2LoginAuthenticationEntryPoint();
-
-			// generate bean name to be registered
-			String oauth2LoginAuthenticationProviderId = pc.getReaderContext()
-					.generateBeanName(oauth2LoginAuthProvider);
-			oauth2LoginFilterId = pc.getReaderContext().generateBeanName(oauth2LoginFilterBean);
-			oauth2AuthorizationRequestRedirectFilterId = pc.getReaderContext()
-					.generateBeanName(oauth2AuthorizationRequestRedirectFilter);
-			oauth2LoginLinks = parser.getOAuth2LoginLinks();
-
-			// register the component
-			pc.registerBeanComponent(new BeanComponentDefinition(oauth2AuthorizationRequestRedirectFilter,
-					oauth2AuthorizationRequestRedirectFilterId));
-			pc.registerBeanComponent(new BeanComponentDefinition(oauth2LoginFilterBean, oauth2LoginFilterId));
-			pc.registerBeanComponent(
-					new BeanComponentDefinition(oauth2LoginAuthProvider, oauth2LoginAuthenticationProviderId));
-
-			oauth2LoginAuthenticationProviderRef = new RuntimeBeanReference(oauth2LoginAuthenticationProviderId);
-
-			// oidc provider
-			BeanDefinition oauth2LoginOidcAuthProvider = parser.getOAuth2LoginOidcAuthenticationProvider();
-			String oauth2LoginOidcAuthenticationProviderId = pc.getReaderContext()
-					.generateBeanName(oauth2LoginOidcAuthProvider);
-			pc.registerBeanComponent(
-					new BeanComponentDefinition(oauth2LoginOidcAuthProvider, oauth2LoginOidcAuthenticationProviderId));
-			oauth2LoginOidcAuthenticationProviderRef = new RuntimeBeanReference(
-					oauth2LoginOidcAuthenticationProviderId);
+		if (oauth2LoginElt == null) {
+			return;
 		}
+
+		OAuth2LoginBeanDefinitionParser parser = new OAuth2LoginBeanDefinitionParser(requestCache, portMapper,
+				portResolver, sessionStrategy, allowSessionCreation);
+		BeanDefinition oauth2LoginFilterBean = parser.parse(oauth2LoginElt, this.pc);
+		oauth2LoginFilterBean.getPropertyValues().addPropertyValue("authenticationManager", authManager);
+
+		// retrieve the other bean result
+		BeanDefinition oauth2LoginAuthProvider = parser.getOAuth2LoginAuthenticationProvider();
+		oauth2AuthorizationRequestRedirectFilter = parser.getOAuth2AuthorizationRequestRedirectFilter();
+		oauth2LoginEntryPoint = parser.getOAuth2LoginAuthenticationEntryPoint();
+
+		// generate bean name to be registered
+		String oauth2LoginAuthProviderId = pc.getReaderContext()
+				.generateBeanName(oauth2LoginAuthProvider);
+		oauth2LoginFilterId = pc.getReaderContext().generateBeanName(oauth2LoginFilterBean);
+		String oauth2AuthorizationRequestRedirectFilterId = pc.getReaderContext()
+				.generateBeanName(oauth2AuthorizationRequestRedirectFilter);
+		oauth2LoginLinks = parser.getOAuth2LoginLinks();
+
+		// register the component
+		pc.registerBeanComponent(new BeanComponentDefinition(oauth2LoginFilterBean, oauth2LoginFilterId));
+		pc.registerBeanComponent(new BeanComponentDefinition(
+				oauth2AuthorizationRequestRedirectFilter, oauth2AuthorizationRequestRedirectFilterId));
+		pc.registerBeanComponent(new BeanComponentDefinition(oauth2LoginAuthProvider, oauth2LoginAuthProviderId));
+
+		oauth2LoginAuthenticationProviderRef = new RuntimeBeanReference(oauth2LoginAuthProviderId);
+
+		// oidc provider
+		BeanDefinition oauth2LoginOidcAuthProvider = parser.getOAuth2LoginOidcAuthenticationProvider();
+		String oauth2LoginOidcAuthProviderId = pc.getReaderContext().generateBeanName(oauth2LoginOidcAuthProvider);
+		pc.registerBeanComponent(new BeanComponentDefinition(
+				oauth2LoginOidcAuthProvider, oauth2LoginOidcAuthProviderId));
+		oauth2LoginOidcAuthenticationProviderRef = new RuntimeBeanReference(oauth2LoginOidcAuthProviderId);
 	}
 
 	void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
@@ -870,7 +867,7 @@ final class AuthenticationConfigBuilder {
 
 		if (oauth2LoginFilterId != null) {
 			filters.add(new OrderDecorator(new RuntimeBeanReference(oauth2LoginFilterId), OAUTH2_LOGIN_FILTER));
-			filters.add(new OrderDecorator(oauth2AuthorizationRequestRedirectFilter, OAUTH2_REDIRECT_FILTER));
+			filters.add(new OrderDecorator(oauth2AuthorizationRequestRedirectFilter, OAUTH2_AUTHORIZATION_REQUEST_FILTER));
 		}
 
 		if (openIDFilterId != null) {

+ 79 - 87
config/src/main/java/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParser.java

@@ -92,7 +92,7 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 	private static final String ATT_AUTHENTICATION_FAILURE_HANDLER_REF = "authentication-failure-handler-ref";
 	private static final String ATT_JWT_DECODER_FACTORY_REF = "jwt-decoder-factory-ref";
 
-	private BeanReference requestCache;
+	private final BeanReference requestCache;
 	private final BeanReference portMapper;
 	private final BeanReference portResolver;
 	private final BeanReference sessionStrategy;
@@ -123,8 +123,8 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 		BeanDefinition oauth2LoginBeanConfig = BeanDefinitionBuilder.rootBeanDefinition(OAuth2LoginBeanConfig.class)
 				.getBeanDefinition();
 		String oauth2LoginBeanConfigId = parserContext.getReaderContext().generateBeanName(oauth2LoginBeanConfig);
-		parserContext
-				.registerBeanComponent(new BeanComponentDefinition(oauth2LoginBeanConfig, oauth2LoginBeanConfigId));
+		parserContext.registerBeanComponent(
+				new BeanComponentDefinition(oauth2LoginBeanConfig, oauth2LoginBeanConfigId));
 
 		// configure filter
 		BeanMetadataElement clientRegistrationRepository = getClientRegistrationRepository(element);
@@ -132,12 +132,13 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 				clientRegistrationRepository);
 		BeanMetadataElement accessTokenResponseClient = getAccessTokenResponseClient(element);
 		BeanMetadataElement oauth2UserService = getOAuth2UserService(element);
-		BeanMetadataElement oauth2AuthRequestRepository = getOAuth2AuthorizationRequestRepository(element);
+		BeanMetadataElement authorizationRequestRepository = getAuthorizationRequestRepository(element);
 
 		BeanDefinitionBuilder oauth2LoginAuthenticationFilterBuilder = BeanDefinitionBuilder
 				.rootBeanDefinition(OAuth2LoginAuthenticationFilter.class)
-				.addConstructorArgValue(clientRegistrationRepository).addConstructorArgValue(authorizedClientRepository)
-				.addPropertyValue("authorizationRequestRepository", oauth2AuthRequestRepository);
+				.addConstructorArgValue(clientRegistrationRepository)
+				.addConstructorArgValue(authorizedClientRepository)
+				.addPropertyValue("authorizationRequestRepository", authorizationRequestRepository);
 
 		if (sessionStrategy != null) {
 			oauth2LoginAuthenticationFilterBuilder.addPropertyValue("sessionAuthenticationStrategy", sessionStrategy);
@@ -145,8 +146,8 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 
 		Object source = parserContext.extractSource(element);
 		String loginProcessingUrl = element.getAttribute(ATT_LOGIN_PROCESSING_URL);
-		WebConfigUtils.validateHttpRedirect(loginProcessingUrl, parserContext, source);
 		if (!StringUtils.isEmpty(loginProcessingUrl)) {
+			WebConfigUtils.validateHttpRedirect(loginProcessingUrl, parserContext, source);
 			oauth2LoginAuthenticationFilterBuilder.addConstructorArgValue(loginProcessingUrl);
 		} else {
 			oauth2LoginAuthenticationFilterBuilder
@@ -155,31 +156,32 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 
 		BeanDefinitionBuilder oauth2LoginAuthenticationProviderBuilder = BeanDefinitionBuilder
 				.rootBeanDefinition(OAuth2LoginAuthenticationProvider.class)
-				.addConstructorArgValue(accessTokenResponseClient).addConstructorArgValue(oauth2UserService);
+				.addConstructorArgValue(accessTokenResponseClient)
+				.addConstructorArgValue(oauth2UserService);
 
-		String oauth2UserAuthMapperRef = element.getAttribute(ATT_USER_AUTHORITIES_MAPPER_REF);
-		if (!StringUtils.isEmpty(oauth2UserAuthMapperRef)) {
-			oauth2LoginAuthenticationProviderBuilder.addPropertyReference("authoritiesMapper", oauth2UserAuthMapperRef);
+		String userAuthoritiesMapperRef = element.getAttribute(ATT_USER_AUTHORITIES_MAPPER_REF);
+		if (!StringUtils.isEmpty(userAuthoritiesMapperRef)) {
+			oauth2LoginAuthenticationProviderBuilder.addPropertyReference("authoritiesMapper", userAuthoritiesMapperRef);
 		}
 
 		oauth2LoginAuthenticationProvider = oauth2LoginAuthenticationProviderBuilder.getBeanDefinition();
 
-		oauth2LoginOidcAuthenticationProvider = getOAuth2OidcAuthProvider(element, accessTokenResponseClient,
-				oauth2UserAuthMapperRef, parserContext);
+		oauth2LoginOidcAuthenticationProvider = getOidcAuthProvider(
+				element, accessTokenResponseClient, userAuthoritiesMapperRef);
 
 		BeanDefinitionBuilder oauth2AuthorizationRequestRedirectFilterBuilder = BeanDefinitionBuilder
 				.rootBeanDefinition(OAuth2AuthorizationRequestRedirectFilter.class);
 
-		String oauth2AuthorizationRequestResolverRef = element.getAttribute(ATT_AUTHORIZATION_REQUEST_RESOLVER_REF);
-		if (!StringUtils.isEmpty(oauth2AuthorizationRequestResolverRef)) {
+		String authorizationRequestResolverRef = element.getAttribute(ATT_AUTHORIZATION_REQUEST_RESOLVER_REF);
+		if (!StringUtils.isEmpty(authorizationRequestResolverRef)) {
 			oauth2AuthorizationRequestRedirectFilterBuilder
-					.addConstructorArgReference(oauth2AuthorizationRequestResolverRef);
+					.addConstructorArgReference(authorizationRequestResolverRef);
 		} else {
 			oauth2AuthorizationRequestRedirectFilterBuilder.addConstructorArgValue(clientRegistrationRepository);
 		}
 
 		oauth2AuthorizationRequestRedirectFilterBuilder
-				.addPropertyValue("authorizationRequestRepository", oauth2AuthRequestRepository)
+				.addPropertyValue("authorizationRequestRepository", authorizationRequestRepository)
 				.addPropertyValue("requestCache", requestCache);
 		oauth2AuthorizationRequestRedirectFilter = oauth2AuthorizationRequestRedirectFilterBuilder.getBeanDefinition();
 
@@ -187,21 +189,29 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 		if (!StringUtils.isEmpty(authenticationSuccessHandlerRef)) {
 			oauth2LoginAuthenticationFilterBuilder.addPropertyReference("authenticationSuccessHandler",
 					authenticationSuccessHandlerRef);
+		} else {
+			BeanDefinitionBuilder successHandlerBuilder = BeanDefinitionBuilder.rootBeanDefinition(
+					"org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler")
+					.addPropertyValue("requestCache", requestCache);
+			oauth2LoginAuthenticationFilterBuilder.addPropertyValue("authenticationSuccessHandler",
+					successHandlerBuilder.getBeanDefinition());
 		}
 
 		String loginPage = element.getAttribute(ATT_LOGIN_PAGE);
-		WebConfigUtils.validateHttpRedirect(loginPage, parserContext, source);
 		if (!StringUtils.isEmpty(loginPage)) {
+			WebConfigUtils.validateHttpRedirect(loginPage, parserContext, source);
 			oauth2LoginAuthenticationEntryPoint = BeanDefinitionBuilder
-					.rootBeanDefinition(LoginUrlAuthenticationEntryPoint.class).addConstructorArgValue(loginPage)
-					.addPropertyValue("portMapper", portMapper).addPropertyValue("portResolver", portResolver)
+					.rootBeanDefinition(LoginUrlAuthenticationEntryPoint.class)
+					.addConstructorArgValue(loginPage)
+					.addPropertyValue("portMapper", portMapper)
+					.addPropertyValue("portResolver", portResolver)
 					.getBeanDefinition();
 		} else {
-			Map<RequestMatcher, AuthenticationEntryPoint> entryPoint = getLoginEntryPoint(element, parserContext);
-
+			Map<RequestMatcher, AuthenticationEntryPoint> entryPoint = getLoginEntryPoint(element);
 			if (entryPoint != null) {
 				oauth2LoginAuthenticationEntryPoint = BeanDefinitionBuilder
-						.rootBeanDefinition(DelegatingAuthenticationEntryPoint.class).addConstructorArgValue(entryPoint)
+						.rootBeanDefinition(DelegatingAuthenticationEntryPoint.class)
+						.addConstructorArgValue(entryPoint)
 						.addPropertyValue("defaultEntryPoint", new LoginUrlAuthenticationEntryPoint(DEFAULT_LOGIN_URI))
 						.getBeanDefinition();
 			}
@@ -217,7 +227,6 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 			failureHandlerBuilder.addConstructorArgValue(
 					DEFAULT_LOGIN_URI + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME);
 			failureHandlerBuilder.addPropertyValue("allowSessionCreation", allowSessionCreation);
-
 			oauth2LoginAuthenticationFilterBuilder.addPropertyValue("authenticationFailureHandler",
 					failureHandlerBuilder.getBeanDefinition());
 		}
@@ -229,49 +238,45 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 		return oauth2LoginAuthenticationFilterBuilder.getBeanDefinition();
 	}
 
-	private BeanMetadataElement getOAuth2AuthorizationRequestRepository(Element element) {
-		BeanMetadataElement oauth2AuthRequestRepository = null;
-		String oauth2AuthRequestRepositoryRef = element.getAttribute(ATT_AUTHORIZATION_REQUEST_REPOSITORY_REF);
-		if (!StringUtils.isEmpty(oauth2AuthRequestRepositoryRef)) {
-			oauth2AuthRequestRepository = new RuntimeBeanReference(oauth2AuthRequestRepositoryRef);
+	private BeanMetadataElement getAuthorizationRequestRepository(Element element) {
+		BeanMetadataElement authorizationRequestRepository;
+		String authorizationRequestRepositoryRef = element.getAttribute(ATT_AUTHORIZATION_REQUEST_REPOSITORY_REF);
+		if (!StringUtils.isEmpty(authorizationRequestRepositoryRef)) {
+			authorizationRequestRepository = new RuntimeBeanReference(authorizationRequestRepositoryRef);
 		} else {
-			oauth2AuthRequestRepository = BeanDefinitionBuilder.rootBeanDefinition(
+			authorizationRequestRepository = BeanDefinitionBuilder.rootBeanDefinition(
 					"org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizationRequestRepository")
 					.getBeanDefinition();
 		}
-		return oauth2AuthRequestRepository;
+		return authorizationRequestRepository;
 	}
 
 	private BeanMetadataElement getAuthorizedClientRepository(Element element,
 			BeanMetadataElement clientRegistrationRepository) {
-		BeanMetadataElement authorizedClientRepository = null;
-
+		BeanMetadataElement authorizedClientRepository;
 		String authorizedClientRepositoryRef = element.getAttribute(ATT_AUTHORIZED_CLIENT_REPOSITORY_REF);
 		if (!StringUtils.isEmpty(authorizedClientRepositoryRef)) {
 			authorizedClientRepository = new RuntimeBeanReference(authorizedClientRepositoryRef);
 		} else {
-			BeanMetadataElement oauth2AuthorizedClientService = null;
+			BeanMetadataElement authorizedClientService;
 			String authorizedClientServiceRef = element.getAttribute(ATT_AUTHORIZED_CLIENT_SERVICE_REF);
 			if (!StringUtils.isEmpty(authorizedClientServiceRef)) {
-				oauth2AuthorizedClientService = new RuntimeBeanReference(authorizedClientServiceRef);
+				authorizedClientService = new RuntimeBeanReference(authorizedClientServiceRef);
 			} else {
-				oauth2AuthorizedClientService = BeanDefinitionBuilder
+				authorizedClientService = BeanDefinitionBuilder
 						.rootBeanDefinition(
 								"org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService")
 						.addConstructorArgValue(clientRegistrationRepository).getBeanDefinition();
 			}
-
 			authorizedClientRepository = BeanDefinitionBuilder.rootBeanDefinition(
 					"org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository")
-					.addConstructorArgValue(oauth2AuthorizedClientService).getBeanDefinition();
+					.addConstructorArgValue(authorizedClientService).getBeanDefinition();
 		}
-
 		return authorizedClientRepository;
 	}
 
 	private BeanMetadataElement getClientRegistrationRepository(Element element) {
-		BeanMetadataElement clientRegistrationRepository = null;
-
+		BeanMetadataElement clientRegistrationRepository;
 		String clientRegistrationRepositoryRef = element.getAttribute(ATT_CLIENT_REGISTRATION_REPOSITORY_REF);
 		if (!StringUtils.isEmpty(clientRegistrationRepositoryRef)) {
 			clientRegistrationRepository = new RuntimeBeanReference(clientRegistrationRepositoryRef);
@@ -281,52 +286,49 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 		return clientRegistrationRepository;
 	}
 
-	private BeanDefinition getOAuth2OidcAuthProvider(Element element, BeanMetadataElement accessTokenResponseClient,
-			String oauth2UserAuthMapperRef, ParserContext parserContext) {
-		BeanDefinition oauth2OidcAuthProvider = null;
-		boolean oidcAuthenticationProviderEnabled = ClassUtils
-				.isPresent("org.springframework.security.oauth2.jwt.JwtDecoder", this.getClass().getClassLoader());
+	private BeanDefinition getOidcAuthProvider(Element element,
+			BeanMetadataElement accessTokenResponseClient, String userAuthoritiesMapperRef) {
 
-		if (oidcAuthenticationProviderEnabled) {
-			BeanMetadataElement oidcUserService = getOAuth2OidcUserService(element);
+		boolean oidcAuthenticationProviderEnabled = ClassUtils.isPresent(
+				"org.springframework.security.oauth2.jwt.JwtDecoder", this.getClass().getClassLoader());
+		if (!oidcAuthenticationProviderEnabled) {
+			return BeanDefinitionBuilder.rootBeanDefinition(OidcAuthenticationRequestChecker.class).getBeanDefinition();
+		}
 
-			BeanDefinitionBuilder oauth2OidcAuthProviderBuilder = BeanDefinitionBuilder.rootBeanDefinition(
-					"org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider")
-					.addConstructorArgValue(accessTokenResponseClient).addConstructorArgValue(oidcUserService);
+		BeanMetadataElement oidcUserService = getOidcUserService(element);
 
-			if (!StringUtils.isEmpty(oauth2UserAuthMapperRef)) {
-				oauth2OidcAuthProviderBuilder.addPropertyReference("authoritiesMapper", oauth2UserAuthMapperRef);
-			}
+		BeanDefinitionBuilder oidcAuthProviderBuilder = BeanDefinitionBuilder.rootBeanDefinition(
+				"org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider")
+				.addConstructorArgValue(accessTokenResponseClient)
+				.addConstructorArgValue(oidcUserService);
 
-			String jwtDecoderFactoryRef = element.getAttribute(ATT_JWT_DECODER_FACTORY_REF);
-			if (!StringUtils.isEmpty(jwtDecoderFactoryRef)) {
-				oauth2OidcAuthProviderBuilder.addPropertyReference("jwtDecoderFactory", jwtDecoderFactoryRef);
-			}
+		if (!StringUtils.isEmpty(userAuthoritiesMapperRef)) {
+			oidcAuthProviderBuilder.addPropertyReference("authoritiesMapper", userAuthoritiesMapperRef);
+		}
 
-			oauth2OidcAuthProvider = oauth2OidcAuthProviderBuilder.getBeanDefinition();
-		} else {
-			oauth2OidcAuthProvider = BeanDefinitionBuilder.rootBeanDefinition(OidcAuthenticationRequestChecker.class)
-					.getBeanDefinition();
+		String jwtDecoderFactoryRef = element.getAttribute(ATT_JWT_DECODER_FACTORY_REF);
+		if (!StringUtils.isEmpty(jwtDecoderFactoryRef)) {
+			oidcAuthProviderBuilder.addPropertyReference("jwtDecoderFactory", jwtDecoderFactoryRef);
 		}
 
-		return oauth2OidcAuthProvider;
+		return oidcAuthProviderBuilder.getBeanDefinition();
 	}
 
-	private BeanMetadataElement getOAuth2OidcUserService(Element element) {
-		BeanMetadataElement oauth2OidcUserService = null;
-		String oauth2UserServiceRef = element.getAttribute(ATT_OIDC_USER_SERVICE_REF);
-		if (!StringUtils.isEmpty(oauth2UserServiceRef)) {
-			oauth2OidcUserService = new RuntimeBeanReference(oauth2UserServiceRef);
+	private BeanMetadataElement getOidcUserService(Element element) {
+		BeanMetadataElement oidcUserService;
+		String oidcUserServiceRef = element.getAttribute(ATT_OIDC_USER_SERVICE_REF);
+		if (!StringUtils.isEmpty(oidcUserServiceRef)) {
+			oidcUserService = new RuntimeBeanReference(oidcUserServiceRef);
 		} else {
-			oauth2OidcUserService = BeanDefinitionBuilder
+			oidcUserService = BeanDefinitionBuilder
 					.rootBeanDefinition("org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService")
 					.getBeanDefinition();
 		}
-		return oauth2OidcUserService;
+		return oidcUserService;
 	}
 
 	private BeanMetadataElement getOAuth2UserService(Element element) {
-		BeanMetadataElement oauth2UserService = null;
+		BeanMetadataElement oauth2UserService;
 		String oauth2UserServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
 		if (!StringUtils.isEmpty(oauth2UserServiceRef)) {
 			oauth2UserService = new RuntimeBeanReference(oauth2UserServiceRef);
@@ -339,8 +341,7 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 	}
 
 	private BeanMetadataElement getAccessTokenResponseClient(Element element) {
-		BeanMetadataElement accessTokenResponseClient = null;
-
+		BeanMetadataElement accessTokenResponseClient;
 		String accessTokenResponseClientRef = element.getAttribute(ATT_ACCESS_TOKEN_RESPONSE_CLIENT_REF);
 		if (!StringUtils.isEmpty(accessTokenResponseClientRef)) {
 			accessTokenResponseClient = new RuntimeBeanReference(accessTokenResponseClientRef);
@@ -372,15 +373,12 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 		return oauth2LoginLinks;
 	}
 
-	private Map<RequestMatcher, AuthenticationEntryPoint> getLoginEntryPoint(Element element,
-			ParserContext parserContext) {
+	private Map<RequestMatcher, AuthenticationEntryPoint> getLoginEntryPoint(Element element) {
 		Map<RequestMatcher, AuthenticationEntryPoint> entryPoints = null;
 		Element clientRegsElt = DomUtils.getChildElementByTagName(element.getOwnerDocument().getDocumentElement(),
 				Elements.CLIENT_REGISTRATIONS);
-
 		if (clientRegsElt != null) {
 			List<Element> clientRegList = DomUtils.getChildElementsByTagName(clientRegsElt, ELT_CLIENT_REGISTRATION);
-
 			if (clientRegList.size() == 1) {
 				RequestMatcher loginPageMatcher = new AntPathRequestMatcher(DEFAULT_LOGIN_URI);
 				RequestMatcher faviconMatcher = new AntPathRequestMatcher("/favicon.ico");
@@ -397,24 +395,19 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 						new AndRequestMatcher(notXRequestedWith, new NegatedRequestMatcher(defaultLoginPageMatcher)),
 						new LoginUrlAuthenticationEntryPoint(DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/"
 								+ clientRegElt.getAttribute(ATT_REGISTRATION_ID)));
-
 			}
 		}
-
 		return entryPoints;
 	}
 
 	private RequestMatcher getAuthenticationEntryPointMatcher() {
 		ContentNegotiationStrategy contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
-
 		MediaTypeRequestMatcher mediaMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy,
 				MediaType.APPLICATION_XHTML_XML, new MediaType("image", "*"), MediaType.TEXT_HTML,
 				MediaType.TEXT_PLAIN);
 		mediaMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
-
 		RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
 				new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
-
 		return new AndRequestMatcher(Arrays.asList(notXRequestedWith, mediaMatcher));
 	}
 
@@ -452,17 +445,17 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 	 */
 	private static class OAuth2LoginBeanConfig implements ApplicationContextAware {
 
-		private ApplicationContext appContext;
+		private ApplicationContext context;
 
 		@Override
-		public void setApplicationContext(ApplicationContext appContext) throws BeansException {
-			this.appContext = appContext;
+		public void setApplicationContext(ApplicationContext context) throws BeansException {
+			this.context = context;
 		}
 
 		@SuppressWarnings({ "unchecked", "unused" })
 		public Map<String, String> getLoginLinks() {
 			Iterable<ClientRegistration> clientRegistrations = null;
-			ClientRegistrationRepository clientRegistrationRepository = appContext
+			ClientRegistrationRepository clientRegistrationRepository = context
 					.getBean(ClientRegistrationRepository.class);
 			ResolvableType type = ResolvableType.forInstance(clientRegistrationRepository).as(Iterable.class);
 			if (type != ResolvableType.NONE && ClientRegistration.class.isAssignableFrom(type.resolveGenerics()[0])) {
@@ -480,6 +473,5 @@ final class OAuth2LoginBeanDefinitionParser implements BeanDefinitionParser {
 
 			return loginUrlToClientName;
 		}
-
 	}
 }

+ 1 - 1
config/src/main/java/org/springframework/security/config/http/SecurityFilters.java

@@ -34,7 +34,7 @@ enum SecurityFilters {
 	HEADERS_FILTER, CORS_FILTER,
 	CSRF_FILTER,
 	LOGOUT_FILTER,
-	OAUTH2_REDIRECT_FILTER,
+	OAUTH2_AUTHORIZATION_REQUEST_FILTER,
 	X509_FILTER,
 	PRE_AUTH_FILTER,
 	CAS_FILTER,

+ 89 - 75
config/src/main/java/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParser.java

@@ -15,14 +15,6 @@
  */
 package org.springframework.security.config.oauth2.client;
 
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.parsing.BeanComponentDefinition;
 import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
@@ -39,6 +31,13 @@ import org.springframework.util.StringUtils;
 import org.springframework.util.xml.DomUtils;
 import org.w3c.dom.Element;
 
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
 /**
  * @author Ruby Hartono
  * @since 5.3
@@ -70,85 +69,94 @@ public final class ClientRegistrationsBeanDefinitionParser implements BeanDefini
 				parserContext.extractSource(element));
 		parserContext.pushContainingComponent(compositeDef);
 
-		Map<String, Map<String, String>> providerDetailMap = getProviders(element);
+		Map<String, Map<String, String>> providers = getProviders(element);
+		List<ClientRegistration> clientRegistrations = getClientRegistrations(element, parserContext, providers);
 
-		List<ClientRegistration> clientRegs = getClientRegistrations(element, parserContext, providerDetailMap);
-
-		BeanDefinition inMemClientRegRepoBeanDef = BeanDefinitionBuilder
-				.rootBeanDefinition(InMemoryClientRegistrationRepository.class).addConstructorArgValue(clientRegs)
+		BeanDefinition clientRegistrationRepositoryBean = BeanDefinitionBuilder
+				.rootBeanDefinition(InMemoryClientRegistrationRepository.class)
+				.addConstructorArgValue(clientRegistrations)
 				.getBeanDefinition();
-		String beanName = parserContext.getReaderContext().generateBeanName(inMemClientRegRepoBeanDef);
-		parserContext.registerBeanComponent(new BeanComponentDefinition(inMemClientRegRepoBeanDef, beanName));
+		String clientRegistrationRepositoryId = parserContext.getReaderContext().generateBeanName(
+				clientRegistrationRepositoryBean);
+		parserContext.registerBeanComponent(new BeanComponentDefinition(
+				clientRegistrationRepositoryBean, clientRegistrationRepositoryId));
 
 		parserContext.popAndRegisterContainingComponent();
 		return null;
 	}
 
 	private List<ClientRegistration> getClientRegistrations(Element element, ParserContext parserContext,
-			Map<String, Map<String, String>> providerDetailMap) {
-		List<Element> clientRegElts = DomUtils.getChildElementsByTagName(element, ELT_CLIENT_REGISTRATION);
-		List<ClientRegistration> clientRegs = new ArrayList<>();
-
-		for (Element clientRegElt : clientRegElts) {
-			String regId = clientRegElt.getAttribute(ATT_REGISTRATION_ID);
-			String clientId = clientRegElt.getAttribute(ATT_CLIENT_ID);
-			String clientSecret = clientRegElt.getAttribute(ATT_CLIENT_SECRET);
-			String clientAuthMethod = clientRegElt.getAttribute(ATT_CLIENT_AUTHENTICATION_METHOD);
-			String authGrantType = clientRegElt.getAttribute(ATT_AUTHORIZATION_GRANT_TYPE);
-			String redirectUri = clientRegElt.getAttribute(ATT_REDIRECT_URI);
-			String scope = clientRegElt.getAttribute(ATT_SCOPE);
-			String clientName = clientRegElt.getAttribute(ATT_CLIENT_NAME);
-			String providerId = clientRegElt.getAttribute(ATT_PROVIDER_ID);
-
-			Set<String> scopes = StringUtils.commaDelimitedListToSet(scope);
-			ClientRegistration.Builder builder = getBuilderFromIssuerIfPossible(regId, providerId, providerDetailMap);
+			Map<String, Map<String, String>> providers) {
+		List<Element> clientRegistrationElts = DomUtils.getChildElementsByTagName(element, ELT_CLIENT_REGISTRATION);
+		List<ClientRegistration> clientRegistrations = new ArrayList<>();
+
+		for (Element clientRegistrationElt : clientRegistrationElts) {
+			String registrationId = clientRegistrationElt.getAttribute(ATT_REGISTRATION_ID);
+			String providerId = clientRegistrationElt.getAttribute(ATT_PROVIDER_ID);
+			ClientRegistration.Builder builder = getBuilderFromIssuerIfPossible(registrationId, providerId, providers);
 			if (builder == null) {
-				builder = getBuilder(regId, providerId, providerDetailMap);
+				builder = getBuilder(registrationId, providerId, providers);
 				if (builder == null) {
 					Object source = parserContext.extractSource(element);
-					parserContext.getReaderContext().error(getErrorMessage(providerId, regId), source);
+					parserContext.getReaderContext().error(getErrorMessage(providerId, registrationId), source);
 					// error on the config skip to next element
-					break;
+					continue;
 				}
 			}
-
-			ClientRegistration clientReg = builder.clientId(clientId)
-					.clientSecret(clientSecret)
-					.clientAuthenticationMethod(new ClientAuthenticationMethod(clientAuthMethod))
-					.authorizationGrantType(new AuthorizationGrantType(authGrantType))
-					.redirectUriTemplate(redirectUri)
-					.scope(scopes)
-					.clientName(clientName)
-					.build();
-			clientRegs.add(clientReg);
+			getOptionalIfNotEmpty(clientRegistrationElt.getAttribute(ATT_CLIENT_ID))
+					.ifPresent(builder::clientId);
+			getOptionalIfNotEmpty(clientRegistrationElt.getAttribute(ATT_CLIENT_SECRET))
+					.ifPresent(builder::clientSecret);
+			getOptionalIfNotEmpty(clientRegistrationElt.getAttribute(ATT_CLIENT_AUTHENTICATION_METHOD))
+					.map(ClientAuthenticationMethod::new)
+					.ifPresent(builder::clientAuthenticationMethod);
+			getOptionalIfNotEmpty(clientRegistrationElt.getAttribute(ATT_AUTHORIZATION_GRANT_TYPE))
+					.map(AuthorizationGrantType::new)
+					.ifPresent(builder::authorizationGrantType);
+			getOptionalIfNotEmpty(clientRegistrationElt.getAttribute(ATT_REDIRECT_URI))
+					.ifPresent(builder::redirectUriTemplate);
+			getOptionalIfNotEmpty(clientRegistrationElt.getAttribute(ATT_SCOPE))
+					.map(StringUtils::commaDelimitedListToSet)
+					.ifPresent(builder::scope);
+			getOptionalIfNotEmpty(clientRegistrationElt.getAttribute(ATT_CLIENT_NAME))
+					.ifPresent(builder::clientName);
+			clientRegistrations.add(builder.build());
 		}
-		return clientRegs;
+
+		return clientRegistrations;
 	}
 
 	private Map<String, Map<String, String>> getProviders(Element element) {
-		List<Element> providerRegElts = DomUtils.getChildElementsByTagName(element, ELT_PROVIDER);
-		Map<String, Map<String, String>> providerDetailMap = new HashMap<>();
-		for (Element providerRegElt : providerRegElts) {
-			Map<String, String> detail = new HashMap<String, String>();
-			String providerId = providerRegElt.getAttribute(ATT_PROVIDER_ID);
-			detail.put(ATT_PROVIDER_ID, providerId);
-			detail.put(ATT_AUTHORIZATION_URI, providerRegElt.getAttribute(ATT_AUTHORIZATION_URI));
-			detail.put(ATT_TOKEN_URI, providerRegElt.getAttribute(ATT_TOKEN_URI));
-			detail.put(ATT_USERINFO_URI, providerRegElt.getAttribute(ATT_USERINFO_URI));
-			detail.put(ATT_USERINFO_AUTHENTICATION_METHOD,
-					providerRegElt.getAttribute(ATT_USERINFO_AUTHENTICATION_METHOD));
-			detail.put(ATT_USERNAME_ATTRIBUTE_NAME, providerRegElt.getAttribute(ATT_USERNAME_ATTRIBUTE_NAME));
-			detail.put(ATT_JWKSET_URI, providerRegElt.getAttribute(ATT_JWKSET_URI));
-			detail.put(ATT_ISSUER_URI, providerRegElt.getAttribute(ATT_ISSUER_URI));
-
-			providerDetailMap.put(providerId, detail);
+		List<Element> providerElts = DomUtils.getChildElementsByTagName(element, ELT_PROVIDER);
+		Map<String, Map<String, String>> providers = new HashMap<>();
+
+		for (Element providerElt : providerElts) {
+			Map<String, String> provider = new HashMap<>();
+			String providerId = providerElt.getAttribute(ATT_PROVIDER_ID);
+			provider.put(ATT_PROVIDER_ID, providerId);
+			getOptionalIfNotEmpty(providerElt.getAttribute(ATT_AUTHORIZATION_URI))
+					.ifPresent(value -> provider.put(ATT_AUTHORIZATION_URI, value));
+			getOptionalIfNotEmpty(providerElt.getAttribute(ATT_TOKEN_URI))
+					.ifPresent(value -> provider.put(ATT_TOKEN_URI, value));
+			getOptionalIfNotEmpty(providerElt.getAttribute(ATT_USERINFO_URI))
+					.ifPresent(value -> provider.put(ATT_USERINFO_URI, value));
+			getOptionalIfNotEmpty(providerElt.getAttribute(ATT_USERINFO_AUTHENTICATION_METHOD))
+					.ifPresent(value -> provider.put(ATT_USERINFO_AUTHENTICATION_METHOD, value));
+			getOptionalIfNotEmpty(providerElt.getAttribute(ATT_USERNAME_ATTRIBUTE_NAME))
+					.ifPresent(value -> provider.put(ATT_USERNAME_ATTRIBUTE_NAME, value));
+			getOptionalIfNotEmpty(providerElt.getAttribute(ATT_JWKSET_URI))
+					.ifPresent(value -> provider.put(ATT_JWKSET_URI, value));
+			getOptionalIfNotEmpty(providerElt.getAttribute(ATT_ISSUER_URI))
+					.ifPresent(value -> provider.put(ATT_ISSUER_URI, value));
+			providers.put(providerId, provider);
 		}
-		return providerDetailMap;
+
+		return providers;
 	}
 
 	private static ClientRegistration.Builder getBuilderFromIssuerIfPossible(String registrationId,
 			String configuredProviderId, Map<String, Map<String, String>> providers) {
-		String providerId = (configuredProviderId != null) ? configuredProviderId : registrationId;
+		String providerId = configuredProviderId != null ? configuredProviderId : registrationId;
 		if (providers.containsKey(providerId)) {
 			Map<String, String> provider = providers.get(providerId);
 			String issuer = provider.get(ATT_ISSUER_URI);
@@ -168,7 +176,7 @@ public final class ClientRegistrationsBeanDefinitionParser implements BeanDefini
 		if (provider == null && !providers.containsKey(providerId)) {
 			return null;
 		}
-		ClientRegistration.Builder builder = (provider != null) ? provider.getBuilder(registrationId)
+		ClientRegistration.Builder builder = provider != null ? provider.getBuilder(registrationId)
 				: ClientRegistration.withRegistrationId(registrationId);
 		if (providers.containsKey(providerId)) {
 			return getBuilder(builder, providers.get(providerId));
@@ -178,13 +186,19 @@ public final class ClientRegistrationsBeanDefinitionParser implements BeanDefini
 
 	private static ClientRegistration.Builder getBuilder(ClientRegistration.Builder builder,
 			Map<String, String> provider) {
-		getOptionalIfNotEmpty(provider.get(ATT_AUTHORIZATION_URI)).ifPresent(builder::authorizationUri);
-		getOptionalIfNotEmpty(provider.get(ATT_TOKEN_URI)).ifPresent(builder::tokenUri);
-		getOptionalIfNotEmpty(provider.get(ATT_USERINFO_URI)).ifPresent(builder::userInfoUri);
-		getOptionalIfNotEmpty(provider.get(ATT_USERINFO_AUTHENTICATION_METHOD)).map(AuthenticationMethod::new)
+		getOptionalIfNotEmpty(provider.get(ATT_AUTHORIZATION_URI))
+				.ifPresent(builder::authorizationUri);
+		getOptionalIfNotEmpty(provider.get(ATT_TOKEN_URI))
+				.ifPresent(builder::tokenUri);
+		getOptionalIfNotEmpty(provider.get(ATT_USERINFO_URI))
+				.ifPresent(builder::userInfoUri);
+		getOptionalIfNotEmpty(provider.get(ATT_USERINFO_AUTHENTICATION_METHOD))
+				.map(AuthenticationMethod::new)
 				.ifPresent(builder::userInfoAuthenticationMethod);
-		getOptionalIfNotEmpty(provider.get(ATT_JWKSET_URI)).ifPresent(builder::jwkSetUri);
-		getOptionalIfNotEmpty(provider.get(ATT_USERNAME_ATTRIBUTE_NAME)).ifPresent(builder::userNameAttributeName);
+		getOptionalIfNotEmpty(provider.get(ATT_JWKSET_URI))
+				.ifPresent(builder::jwkSetUri);
+		getOptionalIfNotEmpty(provider.get(ATT_USERNAME_ATTRIBUTE_NAME))
+				.ifPresent(builder::userNameAttributeName);
 		return builder;
 	}
 
@@ -194,7 +208,7 @@ public final class ClientRegistrationsBeanDefinitionParser implements BeanDefini
 
 	private static CommonOAuth2Provider getCommonProvider(String providerId) {
 		try {
-			String value = providerId.toString().trim();
+			String value = providerId.trim();
 			if (value.isEmpty()) {
 				return null;
 			}
@@ -223,12 +237,12 @@ public final class ClientRegistrationsBeanDefinitionParser implements BeanDefini
 	private static String getCanonicalName(String name) {
 		StringBuilder canonicalName = new StringBuilder(name.length());
 		name.chars().filter(Character::isLetterOrDigit).map(Character::toLowerCase)
-				.forEach((c) -> canonicalName.append((char) c));
+				.forEach(c -> canonicalName.append((char) c));
 		return canonicalName.toString();
 	}
 
 	private static String getErrorMessage(String configuredProviderId, String registrationId) {
-		return ((configuredProviderId != null) ? "Unknown provider ID '" + configuredProviderId + "'"
-				: "Provider ID must be specified for client registration '" + registrationId + "'");
+		return configuredProviderId != null ? "Unknown provider ID '" + configuredProviderId + "'"
+				: "Provider ID must be specified for client registration '" + registrationId + "'";
 	}
 }

+ 16 - 16
config/src/main/resources/org/springframework/security/config/spring-security-5.3.rnc

@@ -441,46 +441,46 @@ oauth2-login =
 	## Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 Provider.
 	element oauth2-login {oauth2-login.attlist}
 oauth2-login.attlist &=
-	## Reference to ClientRegistrationRepository
+	## Reference to the ClientRegistrationRepository
 	attribute client-registration-repository-ref {xsd:token}?
 oauth2-login.attlist &=
-	## Reference to OAuth2AuthorizedClientRepository
+	## Reference to the OAuth2AuthorizedClientRepository
 	attribute authorized-client-repository-ref {xsd:token}?
 oauth2-login.attlist &=
-	## Reference to OAuth2AuthorizedClientService
+	## Reference to the OAuth2AuthorizedClientService
 	attribute authorized-client-service-ref {xsd:token}?
 oauth2-login.attlist &=
-	## Reference to AuthorizationRequestRepository
+	## Reference to the AuthorizationRequestRepository
 	attribute authorization-request-repository-ref {xsd:token}?
 oauth2-login.attlist &=
-	## Reference to OAuth2AuthorizationRequestResolver
+	## Reference to the OAuth2AuthorizationRequestResolver
 	attribute authorization-request-resolver-ref {xsd:token}?
 oauth2-login.attlist &=
-	## Reference to OAuth2AccessTokenResponseClient
+	## Reference to the OAuth2AccessTokenResponseClient
 	attribute access-token-response-client-ref {xsd:token}?
 oauth2-login.attlist &=
-	## Reference to GrantedAuthoritiesMapper
+	## Reference to the GrantedAuthoritiesMapper
 	attribute user-authorities-mapper-ref {xsd:token}?
 oauth2-login.attlist &=
-	## Reference to OAuth2UserService
+	## Reference to the OAuth2UserService
 	attribute user-service-ref {xsd:token}?
 oauth2-login.attlist &=
-	## Reference to OidcUserService
+	## Reference to the OpenID Connect OAuth2UserService
 	attribute oidc-user-service-ref {xsd:token}?
 oauth2-login.attlist &=
-	## Specifies the URL to validate the credentials.
+	## The URI where the filter processes authentication requests
 	attribute login-processing-url {xsd:token}?
 oauth2-login.attlist &=
-	## Specifies the URL to send users to if login is required
+	## The URI to send users to login
 	attribute login-page {xsd:token}?
 oauth2-login.attlist &=
-	## Specifies authentication success handler
+	## Reference to the AuthenticationSuccessHandler
 	attribute authentication-success-handler-ref {xsd:token}?
 oauth2-login.attlist &=
-	## Specifies authentication failure handler
+	## Reference to the AuthenticationFailureHandler
 	attribute authentication-failure-handler-ref {xsd:token}?
 oauth2-login.attlist &=
-	## Specifies JWT decoder factory for OidcAuthorizationCodeAuthenticationProvider
+	## Reference to the JwtDecoderFactory used by OidcAuthorizationCodeAuthenticationProvider
 	attribute jwt-decoder-factory-ref {xsd:token}?
 
 client-registrations =
@@ -504,7 +504,7 @@ client-registration.attlist &=
 	attribute client-authentication-method {"basic" | "post" | "none"}?
 client-registration.attlist &=
 	## The OAuth 2.0 Authorization Framework defines four Authorization Grant types. The supported values are authorization_code, client_credentials, password and implicit.
-	attribute authorization-grant-type {"authorization_code" | "client_credentials" | "password" | "implicit"}
+	attribute authorization-grant-type {"authorization_code" | "client_credentials" | "password" | "implicit"}?
 client-registration.attlist &=
 	## The client’s registered redirect URI that the Authorization Server redirects the end-user’s user-agent to after the end-user has authenticated and authorized access to the client.
 	attribute redirect-uri {xsd:token}?
@@ -1024,4 +1024,4 @@ position =
 	## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.
 	attribute position {named-security-filter}
 
-named-security-filter = "FIRST" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CORS_FILTER" | "CSRF_FILTER" | "LOGOUT_FILTER" | "OAUTH2_REDIRECT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "OAUTH2_LOGIN_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" | "LOGIN_PAGE_FILTER" |"LOGOUT_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BEARER_TOKEN_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
+named-security-filter = "FIRST" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CORS_FILTER" | "CSRF_FILTER" | "LOGOUT_FILTER" | "OAUTH2_AUTHORIZATION_REQUEST_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "OAUTH2_LOGIN_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" | "LOGIN_PAGE_FILTER" |"LOGOUT_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BEARER_TOKEN_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"

+ 16 - 16
config/src/main/resources/org/springframework/security/config/spring-security-5.3.xsd

@@ -1463,85 +1463,85 @@
   <xs:attributeGroup name="oauth2-login.attlist">
       <xs:attribute name="client-registration-repository-ref" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Reference to ClientRegistrationRepository
+            <xs:documentation>Reference to the ClientRegistrationRepository
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
       <xs:attribute name="authorized-client-repository-ref" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Reference to OAuth2AuthorizedClientRepository
+            <xs:documentation>Reference to the OAuth2AuthorizedClientRepository
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
       <xs:attribute name="authorized-client-service-ref" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Reference to OAuth2AuthorizedClientService
+            <xs:documentation>Reference to the OAuth2AuthorizedClientService
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
       <xs:attribute name="authorization-request-repository-ref" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Reference to AuthorizationRequestRepository
+            <xs:documentation>Reference to the AuthorizationRequestRepository
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
       <xs:attribute name="authorization-request-resolver-ref" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Reference to OAuth2AuthorizationRequestResolver
+            <xs:documentation>Reference to the OAuth2AuthorizationRequestResolver
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
       <xs:attribute name="access-token-response-client-ref" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Reference to OAuth2AccessTokenResponseClient
+            <xs:documentation>Reference to the OAuth2AccessTokenResponseClient
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
       <xs:attribute name="user-authorities-mapper-ref" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Reference to GrantedAuthoritiesMapper
+            <xs:documentation>Reference to the GrantedAuthoritiesMapper
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
       <xs:attribute name="user-service-ref" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Reference to OAuth2UserService
+            <xs:documentation>Reference to the OAuth2UserService
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
       <xs:attribute name="oidc-user-service-ref" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Reference to OidcUserService
+            <xs:documentation>Reference to the OpenID Connect OAuth2UserService
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
       <xs:attribute name="login-processing-url" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Specifies the URL to validate the credentials.
+            <xs:documentation>The URI where the filter processes authentication requests
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
       <xs:attribute name="login-page" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Specifies the URL to send users to if login is required
+            <xs:documentation>The URI to send users to login
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
       <xs:attribute name="authentication-success-handler-ref" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Specifies authentication success handler
+            <xs:documentation>Reference to the AuthenticationSuccessHandler
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
       <xs:attribute name="authentication-failure-handler-ref" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Specifies authentication failure handler
+            <xs:documentation>Reference to the AuthenticationFailureHandler
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
       <xs:attribute name="jwt-decoder-factory-ref" type="xs:token">
          <xs:annotation>
-            <xs:documentation>Specifies JWT decoder factory for OidcAuthorizationCodeAuthenticationProvider
+            <xs:documentation>Reference to the JwtDecoderFactory used by OidcAuthorizationCodeAuthenticationProvider
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
@@ -1601,7 +1601,7 @@
             </xs:restriction>
          </xs:simpleType>
       </xs:attribute>
-      <xs:attribute name="authorization-grant-type" use="required">
+      <xs:attribute name="authorization-grant-type">
          <xs:annotation>
             <xs:documentation>The OAuth 2.0 Authorization Framework defines four Authorization Grant types. The
                 supported values are authorization_code, client_credentials, password and implicit.
@@ -2989,7 +2989,7 @@
          <xs:enumeration value="CORS_FILTER"/>
          <xs:enumeration value="CSRF_FILTER"/>
          <xs:enumeration value="LOGOUT_FILTER"/>
-         <xs:enumeration value="OAUTH2_REDIRECT_FILTER"/>
+         <xs:enumeration value="OAUTH2_AUTHORIZATION_REQUEST_FILTER"/>
          <xs:enumeration value="X509_FILTER"/>
          <xs:enumeration value="PRE_AUTH_FILTER"/>
          <xs:enumeration value="CAS_FILTER"/>

+ 155 - 298
config/src/test/java/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests.java

@@ -18,16 +18,14 @@ package org.springframework.security.config.http;
 import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
-import org.mockito.internal.util.MockUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationListener;
-import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
 import org.springframework.security.config.test.SpringTestRule;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.AuthorityUtils;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
 import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
@@ -38,17 +36,15 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
 import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
 import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
 import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
-import org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository;
 import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
 import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
 import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
-import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter;
 import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
 import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
 import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests;
-import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
+import org.springframework.security.oauth2.core.oidc.user.OidcUser;
 import org.springframework.security.oauth2.core.user.OAuth2User;
 import org.springframework.security.oauth2.core.user.TestOAuth2Users;
 import org.springframework.security.oauth2.jwt.Jwt;
@@ -56,7 +52,7 @@ import org.springframework.security.oauth2.jwt.JwtDecoderFactory;
 import org.springframework.security.oauth2.jwt.TestJwts;
 import org.springframework.security.web.authentication.AuthenticationFailureHandler;
 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
-import org.springframework.security.web.context.SecurityContextRepository;
+import org.springframework.security.web.savedrequest.RequestCache;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.MvcResult;
 import org.springframework.util.LinkedMultiValueMap;
@@ -68,19 +64,15 @@ import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.springframework.security.oauth2.core.endpoint.TestOAuth2AccessTokenResponses.accessTokenResponse;
+import static org.springframework.security.oauth2.core.endpoint.TestOAuth2AccessTokenResponses.oidcAccessTokenResponse;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
-import java.lang.reflect.Field;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 /**
  * Tests for {@link OAuth2LoginBeanDefinitionParser}.
  *
@@ -95,17 +87,11 @@ public class OAuth2LoginBeanDefinitionParserTests {
 	@Autowired
 	private ClientRegistrationRepository clientRegistrationRepository;
 
-	@Autowired
-	private OAuth2LoginAuthenticationFilter oauth2LoginAuthenticationFilter;
-
 	@Autowired(required = false)
-	private OAuth2AuthorizedClientRepository oauth2AuthorizedClientRepository;
+	private OAuth2AuthorizedClientRepository authorizedClientRepository;
 
 	@Autowired(required = false)
-	private OAuth2AuthorizedClientService oauth2AuthorizedClientService;
-
-	@Autowired
-	SecurityContextRepository securityContextRepository;
+	private OAuth2AuthorizedClientService authorizedClientService;
 
 	@Autowired(required = false)
 	private ApplicationListener<AuthenticationSuccessEvent> authenticationSuccessListener;
@@ -113,6 +99,9 @@ public class OAuth2LoginBeanDefinitionParserTests {
 	@Autowired(required = false)
 	private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;
 
+	@Autowired(required = false)
+	private OAuth2AuthorizationRequestResolver authorizationRequestResolver;
+
 	@Autowired(required = false)
 	private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;
 
@@ -123,10 +112,7 @@ public class OAuth2LoginBeanDefinitionParserTests {
 	private JwtDecoderFactory<ClientRegistration> jwtDecoderFactory;
 
 	@Autowired(required = false)
-	private OAuth2AuthorizationRequestResolver oauth2AuthorizationRequestResolver;
-
-	@Autowired(required = false)
-	private GrantedAuthoritiesMapper grantedAuthoritiesMapper;
+	private GrantedAuthoritiesMapper userAuthoritiesMapper;
 
 	@Autowired(required = false)
 	private AuthenticationFailureHandler authenticationFailureHandler;
@@ -134,14 +120,19 @@ public class OAuth2LoginBeanDefinitionParserTests {
 	@Autowired(required = false)
 	private AuthenticationSuccessHandler authenticationSuccessHandler;
 
+	@Autowired(required = false)
+	private RequestCache requestCache;
+
 	@Autowired
 	private MockMvc mvc;
 
 	@Test
-	public void requestLoginWhenMultiClientRegistrationThenReturnLoginPageWithOauth2Login() throws Exception {
+	public void requestLoginWhenMultiClientRegistrationThenReturnLoginPageWithClients() throws Exception {
 		this.spring.configLocations(this.xml("MultiClientRegistration")).autowire();
 
-		MvcResult result = this.mvc.perform(get("/login")).andExpect(status().is2xxSuccessful()).andReturn();
+		MvcResult result = this.mvc.perform(get("/login"))
+				.andExpect(status().is2xxSuccessful())
+				.andReturn();
 
 		assertThat(result.getResponse().getContentAsString())
 				.contains("<a href=\"/oauth2/authorization/google-login\">Google</a>");
@@ -152,10 +143,13 @@ public class OAuth2LoginBeanDefinitionParserTests {
 	// gh-5347
 	@Test
 	public void requestWhenSingleClientRegistrationThenAutoRedirect() throws Exception {
-		this.spring.configLocations(this.xml("SingleClientRegistration-WithinSameFile")).autowire();
+		this.spring.configLocations(this.xml("SingleClientRegistration")).autowire();
 
-		this.mvc.perform(get("/")).andExpect(status().is3xxRedirection())
+		this.mvc.perform(get("/"))
+				.andExpect(status().is3xxRedirection())
 				.andExpect(redirectedUrl("http://localhost/oauth2/authorization/google-login"));
+
+		verify(requestCache).saveRequest(any(), any());
 	}
 
 	// gh-5347
@@ -164,7 +158,8 @@ public class OAuth2LoginBeanDefinitionParserTests {
 			throws Exception {
 		this.spring.configLocations(this.xml("SingleClientRegistration")).autowire();
 
-		this.mvc.perform(get("/favicon.ico").accept(new MediaType("image", "*"))).andExpect(status().is3xxRedirection())
+		this.mvc.perform(get("/favicon.ico").accept(new MediaType("image", "*")))
+				.andExpect(status().is3xxRedirection())
 				.andExpect(redirectedUrl("http://localhost/login"));
 	}
 
@@ -174,7 +169,8 @@ public class OAuth2LoginBeanDefinitionParserTests {
 			throws Exception {
 		this.spring.configLocations(this.xml("SingleClientRegistration")).autowire();
 
-		this.mvc.perform(get("/").header("X-Requested-With", "XMLHttpRequest")).andExpect(status().is3xxRedirection())
+		this.mvc.perform(get("/").header("X-Requested-With", "XMLHttpRequest"))
+				.andExpect(status().is3xxRedirection())
 				.andExpect(redirectedUrl("http://localhost/login"));
 	}
 
@@ -188,66 +184,65 @@ public class OAuth2LoginBeanDefinitionParserTests {
 		params.add("state", "state123");
 		this.mvc.perform(get("/login/oauth2/code/google").params(params));
 
-		// assertions
 		ArgumentCaptor<AuthenticationException> exceptionCaptor = ArgumentCaptor
 				.forClass(AuthenticationException.class);
 		verify(authenticationFailureHandler).onAuthenticationFailure(any(), any(), exceptionCaptor.capture());
-		AuthenticationException excValue = exceptionCaptor.getValue();
-		assertThat(excValue).isInstanceOf(OAuth2AuthenticationException.class);
-		assertThat(((OAuth2AuthenticationException) excValue).getError().getErrorCode())
+		AuthenticationException exception = exceptionCaptor.getValue();
+		assertThat(exception).isInstanceOf(OAuth2AuthenticationException.class);
+		assertThat(((OAuth2AuthenticationException) exception).getError().getErrorCode())
 				.isEqualTo("authorization_request_not_found");
 	}
 
 	@Test
 	public void requestWhenAuthorizationResponseValidThenAuthenticate() throws Exception {
-		this.spring.configLocations(this.xml("SingleClientRegistration-WithTestConfiguration")).autowire();
+		this.spring.configLocations(this.xml("MultiClientRegistration-WithCustomConfiguration")).autowire();
+
+		Map<String, Object> attributes = new HashMap<>();
+		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "github-login");
+		OAuth2AuthorizationRequest authorizationRequest = TestOAuth2AuthorizationRequests.request()
+				.attributes(attributes).build();
+		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authorizationRequest);
+
 		OAuth2AccessTokenResponse accessTokenResponse = accessTokenResponse().build();
 		when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
 
 		OAuth2User oauth2User = TestOAuth2Users.create();
 		when(this.oauth2UserService.loadUser(any())).thenReturn(oauth2User);
 
-		Map<String, Object> attributes = new HashMap<>();
-		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "google-login");
-		OAuth2AuthorizationRequest authRequest = TestOAuth2AuthorizationRequests.request().attributes(attributes)
-				.build();
-		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authRequest);
-
 		MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
 		params.add("code", "code123");
-		params.add("state", authRequest.getState());
-		this.mvc.perform(get("/login/oauth2/code/google").params(params)).andExpect(status().is2xxSuccessful());
+		params.add("state", authorizationRequest.getState());
+		this.mvc.perform(get("/login/oauth2/code/github-login").params(params))
+				.andExpect(status().is2xxSuccessful());
 
 		ArgumentCaptor<Authentication> authenticationCaptor = ArgumentCaptor.forClass(Authentication.class);
 		verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), authenticationCaptor.capture());
-		Authentication authenticationValue = authenticationCaptor.getValue();
-		assertThat(authenticationValue.getAuthorities()).hasSize(1);
-		assertThat(authenticationValue.getAuthorities()).first().isInstanceOf(SimpleGrantedAuthority.class)
-				.hasToString("ROLE_USER");
+		Authentication authentication = authenticationCaptor.getValue();
+		assertThat(authentication.getPrincipal()).isInstanceOf(OAuth2User.class);
 	}
 
 	// gh-6009
 	@Test
 	public void requestWhenAuthorizationResponseValidThenAuthenticationSuccessEventPublished() throws Exception {
-		this.spring.configLocations(this.xml("SingleClientRegistration-WithTestConfiguration")).autowire();
+		this.spring.configLocations(this.xml("MultiClientRegistration-WithCustomConfiguration")).autowire();
+
+		Map<String, Object> attributes = new HashMap<>();
+		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "github-login");
+		OAuth2AuthorizationRequest authorizationRequest = TestOAuth2AuthorizationRequests.request()
+				.attributes(attributes).build();
+		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authorizationRequest);
+
 		OAuth2AccessTokenResponse accessTokenResponse = accessTokenResponse().build();
 		when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
 
 		OAuth2User oauth2User = TestOAuth2Users.create();
 		when(this.oauth2UserService.loadUser(any())).thenReturn(oauth2User);
 
-		Map<String, Object> attributes = new HashMap<>();
-		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "google-login");
-		OAuth2AuthorizationRequest authRequest = TestOAuth2AuthorizationRequests.request().attributes(attributes)
-				.build();
-		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authRequest);
-
 		MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
 		params.add("code", "code123");
-		params.add("state", authRequest.getState());
-		this.mvc.perform(get("/login/oauth2/code/google").params(params));
+		params.add("state", authorizationRequest.getState());
+		this.mvc.perform(get("/login/oauth2/code/github-login").params(params));
 
-		// assertions
 		verify(authenticationSuccessListener).onApplicationEvent(any(AuthenticationSuccessEvent.class));
 	}
 
@@ -255,149 +250,120 @@ public class OAuth2LoginBeanDefinitionParserTests {
 	public void requestWhenOidcAuthenticationResponseValidThenJwtDecoderFactoryCalled() throws Exception {
 		this.spring.configLocations(this.xml("SingleClientRegistration-WithJwtDecoderFactoryAndDefaultSuccessHandler"))
 				.autowire();
-		Map<String, Object> additionalParameters = new HashMap<>();
-		additionalParameters.put(OidcParameterNames.ID_TOKEN, "token123");
-		OAuth2AccessTokenResponse accessTokenResponse = accessTokenResponse().additionalParameters(additionalParameters)
-				.build();
+
+		Map<String, Object> attributes = new HashMap<>();
+		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "google-login");
+		OAuth2AuthorizationRequest authorizationRequest = TestOAuth2AuthorizationRequests.oidcRequest()
+				.attributes(attributes).build();
+		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authorizationRequest);
+
+		OAuth2AccessTokenResponse accessTokenResponse = oidcAccessTokenResponse().build();
 		when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
 
 		Jwt jwt = TestJwts.user();
 		when(this.jwtDecoderFactory.createDecoder(any())).thenReturn(token -> jwt);
 
-		Map<String, Object> attributes = new HashMap<>();
-		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "google-login");
-		OAuth2AuthorizationRequest authRequest = TestOAuth2AuthorizationRequests.request().attributes(attributes)
-				.scope("openid").build();
-		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authRequest);
-
 		MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
 		params.add("code", "code123");
-		params.add("state", authRequest.getState());
-		this.mvc.perform(get("/login/oauth2/code/google").params(params)).andExpect(status().is3xxRedirection())
+		params.add("state", authorizationRequest.getState());
+		this.mvc.perform(get("/login/oauth2/code/google-login").params(params))
+				.andExpect(status().is3xxRedirection())
 				.andExpect(redirectedUrl("/"));
+
+		verify(this.jwtDecoderFactory).createDecoder(any());
+		verify(this.requestCache).getRequest(any(), any());
 	}
 
 	@SuppressWarnings({ "unchecked", "rawtypes" })
 	@Test
 	public void requestWhenCustomGrantedAuthoritiesMapperThenCalled() throws Exception {
-		this.spring.configLocations(this.xml("SingleClientRegistration-WithCustomGrantedAuthorities")).autowire();
-		Map<String, Object> additionalParameters = new HashMap<>();
-		additionalParameters.put(OidcParameterNames.ID_TOKEN, "token123");
-		OAuth2AccessTokenResponse accessTokenResponse = accessTokenResponse().additionalParameters(additionalParameters)
-				.build();
+		this.spring.configLocations(this.xml("MultiClientRegistration-WithCustomGrantedAuthorities")).autowire();
+
+		Map<String, Object> attributes = new HashMap<>();
+		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "github-login");
+		OAuth2AuthorizationRequest authorizationRequest = TestOAuth2AuthorizationRequests.request()
+				.attributes(attributes).build();
+		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authorizationRequest);
+
+		OAuth2AccessTokenResponse accessTokenResponse = accessTokenResponse().build();
 		when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
 
 		OAuth2User oauth2User = TestOAuth2Users.create();
 		when(this.oauth2UserService.loadUser(any())).thenReturn(oauth2User);
 
-		GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_OAUTH2_USER");
-		when(this.grantedAuthoritiesMapper.mapAuthorities(any()))
-				.thenReturn((Collection) Collections.singletonList(grantedAuthority));
-
-		Map<String, Object> attributes = new HashMap<>();
-		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "google-login");
-		OAuth2AuthorizationRequest authRequest = TestOAuth2AuthorizationRequests.request().attributes(attributes)
-				.build();
-		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authRequest);
+		when(this.userAuthoritiesMapper.mapAuthorities(any())).thenReturn(
+				(Collection) AuthorityUtils.createAuthorityList("ROLE_OAUTH2_USER"));
 
 		MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
 		params.add("code", "code123");
-		params.add("state", authRequest.getState());
-		this.mvc.perform(get("/login/oauth2/code/google").params(params)).andExpect(status().is2xxSuccessful());
+		params.add("state", authorizationRequest.getState());
+		this.mvc.perform(get("/login/oauth2/code/github-login").params(params))
+				.andExpect(status().is2xxSuccessful());
 
 		ArgumentCaptor<Authentication> authenticationCaptor = ArgumentCaptor.forClass(Authentication.class);
 		verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), authenticationCaptor.capture());
-		Authentication authenticationValue = authenticationCaptor.getValue();
-		assertThat(authenticationValue.getAuthorities()).hasSize(1);
-		assertThat(authenticationValue.getAuthorities()).first().isInstanceOf(SimpleGrantedAuthority.class)
+		Authentication authentication = authenticationCaptor.getValue();
+		assertThat(authentication.getPrincipal()).isInstanceOf(OAuth2User.class);
+		assertThat(authentication.getAuthorities()).hasSize(1);
+		assertThat(authentication.getAuthorities()).first().isInstanceOf(SimpleGrantedAuthority.class)
 				.hasToString("ROLE_OAUTH2_USER");
 
 		// re-setup for OIDC test
+		attributes = new HashMap<>();
+		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "google-login");
+		authorizationRequest = TestOAuth2AuthorizationRequests.oidcRequest()
+				.attributes(attributes).build();
+		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authorizationRequest);
+
+		accessTokenResponse = oidcAccessTokenResponse().build();
+		when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
+
 		Jwt jwt = TestJwts.user();
 		when(this.jwtDecoderFactory.createDecoder(any())).thenReturn(token -> jwt);
 
-		grantedAuthority = new SimpleGrantedAuthority("ROLE_OIDC_USER");
-		when(this.grantedAuthoritiesMapper.mapAuthorities(any()))
-				.thenReturn((Collection) Collections.singletonList(grantedAuthority));
-
-		authRequest = TestOAuth2AuthorizationRequests.request().attributes(attributes).scope("openid").build();
-		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authRequest);
+		when(this.userAuthoritiesMapper.mapAuthorities(any()))
+				.thenReturn((Collection) AuthorityUtils.createAuthorityList("ROLE_OIDC_USER"));
 
-		this.mvc.perform(get("/login/oauth2/code/google").params(params)).andExpect(status().is2xxSuccessful());
+		this.mvc.perform(get("/login/oauth2/code/google-login").params(params))
+				.andExpect(status().is2xxSuccessful());
 
 		authenticationCaptor = ArgumentCaptor.forClass(Authentication.class);
 		verify(authenticationSuccessHandler, times(2)).onAuthenticationSuccess(any(), any(),
 				authenticationCaptor.capture());
-		authenticationValue = authenticationCaptor.getValue();
-		assertThat(authenticationValue.getAuthorities()).hasSize(1);
-		assertThat(authenticationValue.getAuthorities()).first().isInstanceOf(SimpleGrantedAuthority.class)
+		authentication = authenticationCaptor.getValue();
+		assertThat(authentication.getPrincipal()).isInstanceOf(OidcUser.class);
+		assertThat(authentication.getAuthorities()).hasSize(1);
+		assertThat(authentication.getAuthorities()).first().isInstanceOf(SimpleGrantedAuthority.class)
 				.hasToString("ROLE_OIDC_USER");
 	}
 
-	@SuppressWarnings({ "unchecked", "rawtypes" })
+	// gh-5488
 	@Test
-	public void successOidcLoginWhenSingleClientRegistrationAndCustomAuthoritiesThenReturnSuccessWithCorrectAuthorities()
-			throws Exception {
-		this.spring.configLocations(this.xml("SingleClientRegistration-WithJwtDecoderFactory")).autowire();
-		Map<String, Object> additionalParameters = new HashMap<>();
-		additionalParameters.put(OidcParameterNames.ID_TOKEN, "token123");
-		OAuth2AccessTokenResponse accessTokenResponse = accessTokenResponse().additionalParameters(additionalParameters)
-				.build();
-		when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
-
-		Jwt jwt = TestJwts.user();
-		when(this.jwtDecoderFactory.createDecoder(any())).thenReturn(token -> jwt);
-
-		GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_OIDC_USER");
-		when(this.grantedAuthoritiesMapper.mapAuthorities(any()))
-				.thenReturn((Collection) Collections.singletonList(grantedAuthority));
+	public void requestWhenCustomLoginProcessingUrlThenProcessAuthentication() throws Exception {
+		this.spring.configLocations(this.xml("MultiClientRegistration-WithCustomLoginProcessingUrl")).autowire();
 
 		Map<String, Object> attributes = new HashMap<>();
-		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "google-login");
-		OAuth2AuthorizationRequest authRequest = TestOAuth2AuthorizationRequests.request().attributes(attributes)
-				.scope("openid").build();
-		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authRequest);
-
-		MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
-		params.add("code", "code123");
-		params.add("state", authRequest.getState());
-		this.mvc.perform(get("/login/oauth2/code/google").params(params)).andExpect(status().is2xxSuccessful());
-
-		ArgumentCaptor<Authentication> authenticationCaptor = ArgumentCaptor.forClass(Authentication.class);
-		verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), authenticationCaptor.capture());
-		Authentication authenticationValue = authenticationCaptor.getValue();
-		assertThat(authenticationValue.getAuthorities()).hasSize(1);
-		assertThat(authenticationValue.getAuthorities()).first().isInstanceOf(SimpleGrantedAuthority.class)
-				.hasToString("ROLE_OIDC_USER");
-	}
+		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "github-login");
+		OAuth2AuthorizationRequest authorizationRequest = TestOAuth2AuthorizationRequests.request()
+				.attributes(attributes).build();
+		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authorizationRequest);
 
-	// gh-5488
-	@Test
-	public void requestWhenCustomLoginProcessingUrlThenProcessAuthentication() throws Exception {
-		this.spring.configLocations(this.xml("SingleClientRegistration-WithCustomLoginProcessingUrl")).autowire();
 		OAuth2AccessTokenResponse accessTokenResponse = accessTokenResponse().build();
 		when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
 
 		OAuth2User oauth2User = TestOAuth2Users.create();
 		when(this.oauth2UserService.loadUser(any())).thenReturn(oauth2User);
 
-		Map<String, Object> attributes = new HashMap<>();
-		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "google-login");
-		OAuth2AuthorizationRequest authRequest = TestOAuth2AuthorizationRequests.request().attributes(attributes)
-				.build();
-		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authRequest);
-
 		MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
 		params.add("code", "code123");
-		params.add("state", authRequest.getState());
-		this.mvc.perform(get("/login/oauth2/google").params(params)).andExpect(status().is2xxSuccessful());
+		params.add("state", authorizationRequest.getState());
+		this.mvc.perform(get("/login/oauth2/github-login").params(params))
+				.andExpect(status().is2xxSuccessful());
 
 		ArgumentCaptor<Authentication> authenticationCaptor = ArgumentCaptor.forClass(Authentication.class);
 		verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), authenticationCaptor.capture());
-		Authentication authenticationValue = authenticationCaptor.getValue();
-		assertThat(authenticationValue.getAuthorities()).hasSize(1);
-		assertThat(authenticationValue.getAuthorities()).first().isInstanceOf(SimpleGrantedAuthority.class)
-				.hasToString("ROLE_USER");
+		Authentication authentication = authenticationCaptor.getValue();
+		assertThat(authentication.getPrincipal()).isInstanceOf(OAuth2User.class);
 	}
 
 	// gh-5521
@@ -406,17 +372,19 @@ public class OAuth2LoginBeanDefinitionParserTests {
 		this.spring.configLocations(this.xml("SingleClientRegistration-WithCustomAuthorizationRequestResolver"))
 				.autowire();
 
-		this.mvc.perform(get("/oauth2/authorization/google")).andExpect(status().is3xxRedirection());
+		this.mvc.perform(get("/oauth2/authorization/google-login"))
+				.andExpect(status().is3xxRedirection());
 
-		verify(oauth2AuthorizationRequestResolver).resolve(any());
+		verify(authorizationRequestResolver).resolve(any());
 	}
 
 	// gh-5347
 	@Test
-	public void requestWhenMultipleClientsConfiguredThenRedirectDefaultLoginPage() throws Exception {
+	public void requestWhenMultiClientRegistrationThenRedirectDefaultLoginPage() throws Exception {
 		this.spring.configLocations(this.xml("MultiClientRegistration")).autowire();
 
-		this.mvc.perform(get("/")).andExpect(status().is3xxRedirection())
+		this.mvc.perform(get("/"))
+				.andExpect(status().is3xxRedirection())
 				.andExpect(redirectedUrl("http://localhost/login"));
 	}
 
@@ -424,7 +392,8 @@ public class OAuth2LoginBeanDefinitionParserTests {
 	public void requestWhenCustomLoginPageThenRedirectCustomLoginPage() throws Exception {
 		this.spring.configLocations(this.xml("SingleClientRegistration-WithCustomLoginPage")).autowire();
 
-		this.mvc.perform(get("/")).andExpect(status().is3xxRedirection())
+		this.mvc.perform(get("/"))
+				.andExpect(status().is3xxRedirection())
 				.andExpect(redirectedUrl("http://localhost/custom-login"));
 	}
 
@@ -434,7 +403,8 @@ public class OAuth2LoginBeanDefinitionParserTests {
 			throws Exception {
 		this.spring.configLocations(this.xml("SingleClientRegistration-WithFormLogin")).autowire();
 
-		this.mvc.perform(get("/")).andExpect(status().is3xxRedirection())
+		this.mvc.perform(get("/"))
+				.andExpect(status().is3xxRedirection())
 				.andExpect(redirectedUrl("http://localhost/login"));
 	}
 
@@ -442,39 +412,41 @@ public class OAuth2LoginBeanDefinitionParserTests {
 	public void requestWhenCustomClientRegistrationRepositoryThenCalled() throws Exception {
 		this.spring.configLocations(this.xml("WithCustomClientRegistrationRepository")).autowire();
 
+		ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
+		when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(clientRegistration);
+
+		Map<String, Object> attributes = new HashMap<>();
+		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, clientRegistration.getRegistrationId());
+		OAuth2AuthorizationRequest authorizationRequest = TestOAuth2AuthorizationRequests.request()
+				.attributes(attributes).build();
+		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authorizationRequest);
+
 		OAuth2AccessTokenResponse accessTokenResponse = accessTokenResponse().build();
 		when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
 
 		OAuth2User oauth2User = TestOAuth2Users.create();
 		when(this.oauth2UserService.loadUser(any())).thenReturn(oauth2User);
 
-		Map<String, Object> attributes = new HashMap<>();
-		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "google-login");
-		OAuth2AuthorizationRequest authRequest = TestOAuth2AuthorizationRequests.request().attributes(attributes)
-				.build();
-		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authRequest);
-
 		MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
 		params.add("code", "code123");
-		params.add("state", authRequest.getState());
-		this.mvc.perform(get("/login/oauth2/code/google").params(params));
-
-		assertThat(MockUtil.isMock(clientRegistrationRepository)).isTrue();
-		verify(clientRegistrationRepository).findByRegistrationId("google-login");
+		params.add("state", authorizationRequest.getState());
+		this.mvc.perform(get("/login/oauth2/code/" + clientRegistration.getRegistrationId()).params(params));
 
-		Field field = oauth2LoginAuthenticationFilter.getClass().getDeclaredField("clientRegistrationRepository");
-		field.setAccessible(true);
-		Object fieldVal = field.get(oauth2LoginAuthenticationFilter);
-		assertThat(MockUtil.isMock(fieldVal)).isTrue();
-		assertThat(fieldVal).isSameAs(clientRegistrationRepository);
+		verify(clientRegistrationRepository).findByRegistrationId(clientRegistration.getRegistrationId());
 	}
 
 	@Test
 	public void requestWhenCustomAuthorizedClientRepositoryThenCalled() throws Exception {
 		this.spring.configLocations(this.xml("WithCustomAuthorizedClientRepository")).autowire();
 
-		ClientRegistration clientReg = TestClientRegistrations.clientRegistration().build();
-		when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(clientReg);
+		ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
+		when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(clientRegistration);
+
+		Map<String, Object> attributes = new HashMap<>();
+		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, clientRegistration.getRegistrationId());
+		OAuth2AuthorizationRequest authorizationRequest = TestOAuth2AuthorizationRequests.request()
+				.attributes(attributes).build();
+		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authorizationRequest);
 
 		OAuth2AccessTokenResponse accessTokenResponse = accessTokenResponse().build();
 		when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
@@ -482,157 +454,42 @@ public class OAuth2LoginBeanDefinitionParserTests {
 		OAuth2User oauth2User = TestOAuth2Users.create();
 		when(this.oauth2UserService.loadUser(any())).thenReturn(oauth2User);
 
-		Map<String, Object> attributes = new HashMap<>();
-		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "google-login");
-		OAuth2AuthorizationRequest authRequest = TestOAuth2AuthorizationRequests.request().attributes(attributes)
-				.build();
-		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authRequest);
-
 		MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
 		params.add("code", "code123");
-		params.add("state", authRequest.getState());
-		this.mvc.perform(get("/login/oauth2/code/registration-id").params(params));
-
-		assertThat(MockUtil.isMock(oauth2AuthorizedClientRepository)).isTrue();
-		verify(oauth2AuthorizedClientRepository).saveAuthorizedClient(any(), any(), any(), any());
+		params.add("state", authorizationRequest.getState());
+		this.mvc.perform(get("/login/oauth2/code/" + clientRegistration.getRegistrationId()).params(params));
 
-		Field field = oauth2LoginAuthenticationFilter.getClass().getDeclaredField("authorizedClientRepository");
-		field.setAccessible(true);
-		Object fieldVal = field.get(oauth2LoginAuthenticationFilter);
-		assertThat(MockUtil.isMock(fieldVal)).isTrue();
-		assertThat(fieldVal).isSameAs(oauth2AuthorizedClientRepository);
+		verify(authorizedClientRepository).saveAuthorizedClient(any(), any(), any(), any());
 	}
 
 	@Test
 	public void requestWhenCustomAuthorizedClientServiceThenCalled() throws Exception {
 		this.spring.configLocations(this.xml("WithCustomAuthorizedClientService")).autowire();
 
-		ClientRegistration clientReg = TestClientRegistrations.clientRegistration().build();
-		when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(clientReg);
-
-		OAuth2AccessTokenResponse accessTokenResponse = accessTokenResponse().build();
-		when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
-
-		OAuth2User oauth2User = TestOAuth2Users.create();
-		when(this.oauth2UserService.loadUser(any())).thenReturn(oauth2User);
+		ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
+		when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(clientRegistration);
 
 		Map<String, Object> attributes = new HashMap<>();
-		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "google-login");
-		OAuth2AuthorizationRequest authRequest = TestOAuth2AuthorizationRequests.request().attributes(attributes)
-				.build();
-		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authRequest);
-
-		MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
-		params.add("code", "code123");
-		params.add("state", authRequest.getState());
-		this.mvc.perform(get("/login/oauth2/code/registration-id").params(params));
-
-		assertThat(MockUtil.isMock(oauth2AuthorizedClientService)).isTrue();
-		verify(oauth2AuthorizedClientService).saveAuthorizedClient(any(), any());
-
-		Field authorizedClientRepositoryField = oauth2LoginAuthenticationFilter.getClass()
-				.getDeclaredField("authorizedClientRepository");
-		authorizedClientRepositoryField.setAccessible(true);
-		Object authorizedClientRepositoryFieldVal = authorizedClientRepositoryField
-				.get(oauth2LoginAuthenticationFilter);
-		assertThat(authorizedClientRepositoryFieldVal)
-				.isInstanceOf(AuthenticatedPrincipalOAuth2AuthorizedClientRepository.class);
-
-		Field authorizedClientServiceField = authorizedClientRepositoryFieldVal.getClass()
-				.getDeclaredField("authorizedClientService");
-		authorizedClientServiceField.setAccessible(true);
-		Object authorizedClientServiceFieldVal = authorizedClientServiceField.get(authorizedClientRepositoryFieldVal);
-		assertThat(MockUtil.isMock(authorizedClientServiceFieldVal)).isTrue();
-		assertThat(authorizedClientServiceFieldVal).isSameAs(oauth2AuthorizedClientService);
-	}
+		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, clientRegistration.getRegistrationId());
+		OAuth2AuthorizationRequest authorizationRequest = TestOAuth2AuthorizationRequests.request()
+				.attributes(attributes).build();
+		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authorizationRequest);
 
-	@Test
-	public void requestWhenCustomAuthorizationRequestRepositoryThenCalled() throws Exception {
-		this.spring.configLocations(this.xml("WithCustomAuthorizationRequestRepository")).autowire();
-
-		ClientRegistration clientReg = TestClientRegistrations.clientRegistration().build();
-		when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(clientReg);
-
-		OAuth2AccessTokenResponse accessTokenResponse = accessTokenResponse().build();
-		when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
-
-		OAuth2User oauth2User = TestOAuth2Users.create();
-		when(this.oauth2UserService.loadUser(any())).thenReturn(oauth2User);
-
-		MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
-		params.add("code", "code123");
-		params.add("state", "state");
-		this.mvc.perform(get("/login/oauth2/code/registration-id").params(params));
-
-		assertThat(MockUtil.isMock(authorizationRequestRepository)).isTrue();
-		verify(authorizationRequestRepository).removeAuthorizationRequest(any(), any());
-
-		Field authorizationRequestRepositoryField = oauth2LoginAuthenticationFilter.getClass()
-				.getDeclaredField("authorizationRequestRepository");
-		authorizationRequestRepositoryField.setAccessible(true);
-		Object authorizationRequestRepositoryFieldVal = authorizationRequestRepositoryField
-				.get(oauth2LoginAuthenticationFilter);
-		assertThat(MockUtil.isMock(authorizationRequestRepositoryFieldVal)).isTrue();
-		assertThat(authorizationRequestRepositoryFieldVal).isSameAs(authorizationRequestRepository);
-	}
-
-	@Test
-	public void requestWhenCustomAuthenticationSuccessHandlerThenCalled() throws Exception {
-		this.spring.configLocations(this.xml("SingleClientRegistration-WithCustomAuthenticationHandler")).autowire();
 		OAuth2AccessTokenResponse accessTokenResponse = accessTokenResponse().build();
 		when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
 
 		OAuth2User oauth2User = TestOAuth2Users.create();
 		when(this.oauth2UserService.loadUser(any())).thenReturn(oauth2User);
 
-		Map<String, Object> attributes = new HashMap<>();
-		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, "google-login");
-		OAuth2AuthorizationRequest authRequest = TestOAuth2AuthorizationRequests.request().attributes(attributes)
-				.build();
-		when(this.authorizationRequestRepository.removeAuthorizationRequest(any(), any())).thenReturn(authRequest);
-
 		MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
 		params.add("code", "code123");
-		params.add("state", authRequest.getState());
-		this.mvc.perform(get("/login/oauth2/code/google").params(params)).andExpect(status().is2xxSuccessful());
-
-		ArgumentCaptor<Authentication> authenticationCaptor = ArgumentCaptor.forClass(Authentication.class);
-		verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), authenticationCaptor.capture());
-		Authentication authenticationValue = authenticationCaptor.getValue();
-		assertThat(authenticationValue.getAuthorities()).hasSize(1);
-		assertThat(authenticationValue.getAuthorities()).first().isInstanceOf(SimpleGrantedAuthority.class)
-				.hasToString("ROLE_USER");
+		params.add("state", authorizationRequest.getState());
+		this.mvc.perform(get("/login/oauth2/code/" + clientRegistration.getRegistrationId()).params(params));
 
-	}
-
-	@Test
-	public void requestWhenCustomAuthenticationFailureHandlerThenCalled() throws Exception {
-		this.spring.configLocations(this.xml("SingleClientRegistration-WithCustomAuthenticationHandler")).autowire();
-
-		MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
-		params.add("code", "code123");
-		params.add("state", "state123");
-		this.mvc.perform(get("/login/oauth2/code/google").params(params)).andExpect(status().isIAmATeapot());
+		verify(authorizedClientService).saveAuthorizedClient(any(), any());
 	}
 
 	private String xml(String configName) {
 		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
 	}
-
-	public static class TeapotAuthenticationHandler
-			implements AuthenticationSuccessHandler, AuthenticationFailureHandler {
-
-		@Override
-		public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
-				AuthenticationException exception) {
-			response.setStatus(HttpStatus.I_AM_A_TEAPOT.value());
-		}
-
-		@Override
-		public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
-				Authentication authentication) {
-			response.setStatus(HttpStatus.I_AM_A_TEAPOT.value());
-		}
-	}
-
 }

+ 90 - 103
config/src/test/java/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParserTests.java

@@ -15,9 +15,9 @@
  */
 package org.springframework.security.config.oauth2.client;
 
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.Map;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import org.junit.After;
 import org.junit.Rule;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -33,13 +33,7 @@ import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
 import org.springframework.util.StringUtils;
 
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import okhttp3.mockwebserver.Dispatcher;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.MockWebServer;
-import okhttp3.mockwebserver.RecordedRequest;
+import static org.assertj.core.api.Assertions.assertThat;
 
 /**
  * Tests for {@link ClientRegistrationsBeanDefinitionParser}.
@@ -49,13 +43,24 @@ import okhttp3.mockwebserver.RecordedRequest;
 public class ClientRegistrationsBeanDefinitionParserTests {
 	private static final String CONFIG_LOCATION_PREFIX = "classpath:org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParserTests";
 
-	@Rule
-	public final SpringTestRule spring = new SpringTestRule();
-
-	@Autowired
-	private ClientRegistrationRepository clientRegistrationRepository;
-
-	private static final String DEFAULT_RESPONSE =
+	private static final String ISSUER_URI_XML_CONFIG = "<b:beans xmlns:b=\"http://www.springframework.org/schema/beans\"\n" +
+			"\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+			"\t\txmlns=\"http://www.springframework.org/schema/security\"\n" +
+			"\t\txsi:schemaLocation=\"\n" +
+			"\t\t\thttp://www.springframework.org/schema/security\n" +
+			"\t\t\thttps://www.springframework.org/schema/security/spring-security.xsd\n" +
+			"\t\t\thttp://www.springframework.org/schema/beans\n" +
+			"\t\t\thttps://www.springframework.org/schema/beans/spring-beans.xsd\">\n" +
+			"\n" +
+			"\t<client-registrations>\n" +
+			"\t\t<client-registration registration-id=\"google-login\" client-id=\"google-client-id\" \n" +
+			"\t\t\t\t\t\t\t client-secret=\"google-client-secret\" provider-id=\"google\"/>\n" +
+			"\t\t<provider provider-id=\"google\" issuer-uri=\"${issuer-uri}\"/>\n" +
+			"\t</client-registrations>\n" +
+			"\n" +
+			"</b:beans>\n";
+
+	private static final String OIDC_DISCOVERY_RESPONSE =
 			"{\n"
 			+ "    \"authorization_endpoint\": \"https://example.com/o/oauth2/v2/auth\", \n"
 			+ "    \"claims_supported\": [\n"
@@ -79,7 +84,7 @@ public class ClientRegistrationsBeanDefinitionParserTests {
 			+ "    \"id_token_signing_alg_values_supported\": [\n"
 			+ "        \"RS256\"\n"
 			+ "    ], \n"
-			+ "    \"issuer\": \"http://localhost:49259\", \n"
+			+ "    \"issuer\": \"${issuer-uri}\", \n"
 			+ "    \"jwks_uri\": \"https://example.com/oauth2/v3/certs\", \n"
 			+ "    \"response_types_supported\": [\n"
 			+ "        \"code\", \n"
@@ -110,71 +115,47 @@ public class ClientRegistrationsBeanDefinitionParserTests {
 			+ "    \"userinfo_endpoint\": \"https://example.com/oauth2/v3/userinfo\"\n"
 			+ "}";
 
+	@Autowired
+	private ClientRegistrationRepository clientRegistrationRepository;
+
+	@Rule
+	public final SpringTestRule spring = new SpringTestRule();
+
+	private MockWebServer server;
+
+	@After
+	public void cleanup() throws Exception {
+		if (this.server != null) {
+			this.server.shutdown();
+		}
+	}
+
 	@Test
 	public void parseWhenIssuerUriConfiguredThenRequestConfigFromIssuer() throws Exception {
-		MockWebServer server = new MockWebServer();
-		ObjectMapper mapper = new ObjectMapper();
-		server.start(49259);
-		Map<String, Object> response = mapper.readValue(DEFAULT_RESPONSE, new TypeReference<Map<String, Object>>() {
-		});
-		final String responseBody = mapper.writeValueAsString(response);
-
-		final Dispatcher oidcDispatcher = new Dispatcher() {
-			@Override
-			public MockResponse dispatch(RecordedRequest request) {
-				switch (request.getPath()) {
-				case "/issuer1/.well-known/openid-configuration":
-				case "/.well-known/openid-configuration":
-					return new MockResponse().setResponseCode(200).setBody(responseBody)
-							.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
-				}
-				return new MockResponse().setResponseCode(404);
-			}
-		};
-
-		final Dispatcher oauthDispatcher = new Dispatcher() {
-			@Override
-			public MockResponse dispatch(RecordedRequest request) {
-				switch (request.getPath()) {
-				case "/.well-known/oauth-authorization-server/issuer1":
-				case "/.well-known/oauth-authorization-server":
-					return new MockResponse().setResponseCode(200).setBody(responseBody)
-							.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
-				}
-				return new MockResponse().setResponseCode(404);
-			}
-		};
-
-		server.setDispatcher(oidcDispatcher);
-
-		this.spring.configLocations(this.xml("FromIssuerUri")).autowire();
-
-		assertThat(clientRegistrationRepository).isInstanceOf(InMemoryClientRegistrationRepository.class);
+		this.server = new MockWebServer();
+		this.server.start();
+		String serverUrl = this.server.url("/").toString();
 
-		testIssuerUriResponse(clientRegistrationRepository);
+		String discoveryResponse = OIDC_DISCOVERY_RESPONSE.replace("${issuer-uri}", serverUrl);
+		this.server.enqueue(jsonResponse(discoveryResponse));
 
-		// test oauth
-		server.setDispatcher(oauthDispatcher);
-		this.spring.configLocations(this.xml("FromIssuerUri")).autowire();
-		testIssuerUriResponse(clientRegistrationRepository);
+		String contextConfig = ISSUER_URI_XML_CONFIG.replace("${issuer-uri}", serverUrl);
+		this.spring.context(contextConfig).autowire();
 
-		server.shutdown();
-		server.close();
-	}
+		assertThat(clientRegistrationRepository).isInstanceOf(InMemoryClientRegistrationRepository.class);
 
-	private void testIssuerUriResponse(ClientRegistrationRepository clientRegistrationRepository) {
-		ClientRegistration googleLogin = clientRegistrationRepository.findByRegistrationId("google-login");
-		assertThat(googleLogin).isNotNull();
-		assertThat(googleLogin.getRegistrationId()).isEqualTo("google-login");
-		assertThat(googleLogin.getClientId()).isEqualTo("google-client-id");
-		assertThat(googleLogin.getClientSecret()).isEqualTo("google-client-secret");
-		assertThat(googleLogin.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
-		assertThat(googleLogin.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
-		assertThat(googleLogin.getRedirectUriTemplate()).isEqualTo("{baseUrl}/login/oauth2/code/{registrationId}");
-		assertThat(googleLogin.getScopes()).isEqualTo(StringUtils.commaDelimitedListToSet("openid,profile,email"));
-		assertThat(googleLogin.getClientName()).isEqualTo("Google");
-
-		ProviderDetails googleProviderDetails = googleLogin.getProviderDetails();
+		ClientRegistration googleRegistration = clientRegistrationRepository.findByRegistrationId("google-login");
+		assertThat(googleRegistration).isNotNull();
+		assertThat(googleRegistration.getRegistrationId()).isEqualTo("google-login");
+		assertThat(googleRegistration.getClientId()).isEqualTo("google-client-id");
+		assertThat(googleRegistration.getClientSecret()).isEqualTo("google-client-secret");
+		assertThat(googleRegistration.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
+		assertThat(googleRegistration.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
+		assertThat(googleRegistration.getRedirectUriTemplate()).isEqualTo("{baseUrl}/{action}/oauth2/code/{registrationId}");
+		assertThat(googleRegistration.getScopes()).isEqualTo(StringUtils.commaDelimitedListToSet("openid,profile,email"));
+		assertThat(googleRegistration.getClientName()).isEqualTo(serverUrl);
+
+		ProviderDetails googleProviderDetails = googleRegistration.getProviderDetails();
 		assertThat(googleProviderDetails).isNotNull();
 		assertThat(googleProviderDetails.getAuthorizationUri()).isEqualTo("https://example.com/o/oauth2/v2/auth");
 		assertThat(googleProviderDetails.getTokenUri()).isEqualTo("https://example.com/oauth2/v4/token");
@@ -187,23 +168,23 @@ public class ClientRegistrationsBeanDefinitionParserTests {
 	}
 
 	@Test
-	public void parseWhenMultipleClientsConfiguredThenAvailableInRepository() throws Exception {
+	public void parseWhenMultipleClientsConfiguredThenAvailableInRepository() {
 		this.spring.configLocations(this.xml("MultiClientRegistration")).autowire();
 
 		assertThat(clientRegistrationRepository).isInstanceOf(InMemoryClientRegistrationRepository.class);
 
-		ClientRegistration googleLogin = clientRegistrationRepository.findByRegistrationId("google-login");
-		assertThat(googleLogin).isNotNull();
-		assertThat(googleLogin.getRegistrationId()).isEqualTo("google-login");
-		assertThat(googleLogin.getClientId()).isEqualTo("google-client-id");
-		assertThat(googleLogin.getClientSecret()).isEqualTo("google-client-secret");
-		assertThat(googleLogin.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
-		assertThat(googleLogin.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
-		assertThat(googleLogin.getRedirectUriTemplate()).isEqualTo("{baseUrl}/login/oauth2/code/{registrationId}");
-		assertThat(googleLogin.getScopes()).isEqualTo(StringUtils.commaDelimitedListToSet("openid,profile,email"));
-		assertThat(googleLogin.getClientName()).isEqualTo("Google");
-
-		ProviderDetails googleProviderDetails = googleLogin.getProviderDetails();
+		ClientRegistration googleRegistration = clientRegistrationRepository.findByRegistrationId("google-login");
+		assertThat(googleRegistration).isNotNull();
+		assertThat(googleRegistration.getRegistrationId()).isEqualTo("google-login");
+		assertThat(googleRegistration.getClientId()).isEqualTo("google-client-id");
+		assertThat(googleRegistration.getClientSecret()).isEqualTo("google-client-secret");
+		assertThat(googleRegistration.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
+		assertThat(googleRegistration.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
+		assertThat(googleRegistration.getRedirectUriTemplate()).isEqualTo("{baseUrl}/login/oauth2/code/{registrationId}");
+		assertThat(googleRegistration.getScopes()).isEqualTo(StringUtils.commaDelimitedListToSet("openid,profile,email"));
+		assertThat(googleRegistration.getClientName()).isEqualTo("Google");
+
+		ProviderDetails googleProviderDetails = googleRegistration.getProviderDetails();
 		assertThat(googleProviderDetails).isNotNull();
 		assertThat(googleProviderDetails.getAuthorizationUri())
 				.isEqualTo("https://accounts.google.com/o/oauth2/v2/auth");
@@ -215,18 +196,18 @@ public class ClientRegistrationsBeanDefinitionParserTests {
 		assertThat(googleProviderDetails.getUserInfoEndpoint().getUserNameAttributeName()).isEqualTo("sub");
 		assertThat(googleProviderDetails.getJwkSetUri()).isEqualTo("https://www.googleapis.com/oauth2/v3/certs");
 
-		ClientRegistration githubLogin = clientRegistrationRepository.findByRegistrationId("github-login");
-		assertThat(githubLogin).isNotNull();
-		assertThat(githubLogin.getRegistrationId()).isEqualTo("github-login");
-		assertThat(githubLogin.getClientId()).isEqualTo("github-client-id");
-		assertThat(githubLogin.getClientSecret()).isEqualTo("github-client-secret");
-		assertThat(githubLogin.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
-		assertThat(githubLogin.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
-		assertThat(githubLogin.getRedirectUriTemplate()).isEqualTo("{baseUrl}/login/oauth2/code/{registrationId}");
-		assertThat(googleLogin.getScopes()).isEqualTo(StringUtils.commaDelimitedListToSet("openid,profile,email"));
-		assertThat(githubLogin.getClientName()).isEqualTo("Github");
-
-		ProviderDetails githubProviderDetails = githubLogin.getProviderDetails();
+		ClientRegistration githubRegistration = clientRegistrationRepository.findByRegistrationId("github-login");
+		assertThat(githubRegistration).isNotNull();
+		assertThat(githubRegistration.getRegistrationId()).isEqualTo("github-login");
+		assertThat(githubRegistration.getClientId()).isEqualTo("github-client-id");
+		assertThat(githubRegistration.getClientSecret()).isEqualTo("github-client-secret");
+		assertThat(githubRegistration.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
+		assertThat(githubRegistration.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
+		assertThat(githubRegistration.getRedirectUriTemplate()).isEqualTo("{baseUrl}/login/oauth2/code/{registrationId}");
+		assertThat(googleRegistration.getScopes()).isEqualTo(StringUtils.commaDelimitedListToSet("openid,profile,email"));
+		assertThat(githubRegistration.getClientName()).isEqualTo("Github");
+
+		ProviderDetails githubProviderDetails = githubRegistration.getProviderDetails();
 		assertThat(githubProviderDetails).isNotNull();
 		assertThat(githubProviderDetails.getAuthorizationUri()).isEqualTo("https://github.com/login/oauth/authorize");
 		assertThat(githubProviderDetails.getTokenUri()).isEqualTo("https://github.com/login/oauth/access_token");
@@ -236,7 +217,13 @@ public class ClientRegistrationsBeanDefinitionParserTests {
 		assertThat(githubProviderDetails.getUserInfoEndpoint().getUserNameAttributeName()).isEqualTo("id");
 	}
 
-	private String xml(String configName) {
+	private static MockResponse jsonResponse(String json) {
+		return new MockResponse()
+				.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
+				.setBody(json);
+	}
+
+	private static String xml(String configName) {
 		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
 	}
 }

+ 9 - 9
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithCustomAuthenticationHandler.xml → config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-MultiClientRegistration-WithCustomConfiguration.xml

@@ -29,25 +29,25 @@
 		<oauth2-login access-token-response-client-ref="accessTokenResponseClient"
 						user-service-ref="oauth2UserService"
 						authorization-request-repository-ref="authorizationRequestRepository"
-						authentication-success-handler-ref="authenticationSuccessHandler"
-						authentication-failure-handler-ref="testHandler"/>
+						authentication-success-handler-ref="authenticationSuccessHandler"/>
 	</http>
 
-	<b:bean name="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient"/>
 	</b:bean>
-	<b:bean name="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.userinfo.OAuth2UserService"/>
 	</b:bean>
-	<b:bean name="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authenticationSuccessListener" class="org.mockito.Mockito" factory-method="mock">
+			<b:constructor-arg value="org.springframework.context.ApplicationListener"/>
+	</b:bean>
+	<b:bean id="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.web.AuthorizationRequestRepository"/>
 	</b:bean>
-	<b:bean name="authenticationSuccessHandler" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authenticationSuccessHandler" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.web.authentication.AuthenticationSuccessHandler"/>
 	</b:bean>
 
-	<b:bean id="testHandler" class="org.springframework.security.config.http.OAuth2LoginBeanDefinitionParserTests.TeapotAuthenticationHandler"/>
-
-	<b:import resource="../oauth2/client/google-registration.xml"/>
+	<b:import resource="../oauth2/client/google-github-registration.xml"/>
 	<b:import resource="userservice.xml"/>
 </b:beans>

+ 9 - 9
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithCustomGrantedAuthorities.xml → config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-MultiClientRegistration-WithCustomGrantedAuthorities.xml

@@ -28,31 +28,31 @@
 		<intercept-url pattern="/**" access="authenticated"/>
 		<oauth2-login access-token-response-client-ref="accessTokenResponseClient"
 						user-service-ref="oauth2UserService"
-						user-authorities-mapper-ref="grantedAuthoritiesMapper"
+						user-authorities-mapper-ref="userAuthoritiesMapper"
 						jwt-decoder-factory-ref="jwtDecoderFactory"
 						authorization-request-repository-ref="authorizationRequestRepository"
 						authentication-success-handler-ref="authenticationSuccessHandler"/>
 	</http>
-	
-	<b:bean name="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
+
+	<b:bean id="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient"/>
 	</b:bean>
-	<b:bean name="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.userinfo.OAuth2UserService"/>
 	</b:bean>
-	<b:bean name="grantedAuthoritiesMapper" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="userAuthoritiesMapper" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper"/>
 	</b:bean>
-	<b:bean name="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.web.AuthorizationRequestRepository"/>
 	</b:bean>
-	<b:bean name="authenticationSuccessHandler" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authenticationSuccessHandler" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.web.authentication.AuthenticationSuccessHandler"/>
 	</b:bean>
-	<b:bean name="jwtDecoderFactory" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="jwtDecoderFactory" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.jwt.JwtDecoderFactory"/>
 	</b:bean>
 
-	<b:import resource="../oauth2/client/google-registration.xml"/>
+	<b:import resource="../oauth2/client/google-github-registration.xml"/>
 	<b:import resource="userservice.xml"/>
 </b:beans>

+ 6 - 6
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithCustomLoginProcessingUrl.xml → config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-MultiClientRegistration-WithCustomLoginProcessingUrl.xml

@@ -32,20 +32,20 @@
 						authorization-request-repository-ref="authorizationRequestRepository"
 						authentication-success-handler-ref="authenticationSuccessHandler" />
 	</http>
-	
-	<b:bean name="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
+
+	<b:bean id="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient"/>
 	</b:bean>
-	<b:bean name="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.userinfo.OAuth2UserService"/>
 	</b:bean>
-	<b:bean name="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.web.AuthorizationRequestRepository"/>
 	</b:bean>
-	<b:bean name="authenticationSuccessHandler" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authenticationSuccessHandler" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.web.authentication.AuthenticationSuccessHandler"/>
 	</b:bean>
 
-	<b:import resource="../oauth2/client/google-registration.xml"/>
+	<b:import resource="../oauth2/client/google-github-registration.xml"/>
 	<b:import resource="userservice.xml"/>
 </b:beans>

+ 1 - 1
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithCustomAuthenticationFailureHandler.xml

@@ -29,7 +29,7 @@
 		<oauth2-login authentication-failure-handler-ref="authenticationFailureHandler"/>
 	</http>
 
-	<b:bean name="authenticationFailureHandler" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authenticationFailureHandler" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.web.authentication.AuthenticationFailureHandler"/>
 	</b:bean>
 

+ 2 - 2
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithCustomAuthorizationRequestResolver.xml

@@ -26,10 +26,10 @@
 
 	<http auto-config="true">
 		<intercept-url pattern="/**" access="authenticated"/>
-		<oauth2-login authorization-request-resolver-ref="oauth2AuthorizationRequestResolver"/>
+		<oauth2-login authorization-request-resolver-ref="authorizationRequestResolver"/>
 	</http>
 
-	<b:bean name="oauth2AuthorizationRequestResolver" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authorizationRequestResolver" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver"/>
 	</b:bean>
 

+ 7 - 7
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithJwtDecoderFactory.xml

@@ -28,24 +28,24 @@
 		<intercept-url pattern="/**" access="authenticated"/>
 		<oauth2-login access-token-response-client-ref="accessTokenResponseClient"
 						jwt-decoder-factory-ref="jwtDecoderFactory"
-						user-authorities-mapper-ref="grantedAuthoritiesMapper"
+						user-authorities-mapper-ref="userAuthoritiesMapper"
 						authorization-request-repository-ref="authorizationRequestRepository"
 						authentication-success-handler-ref="authenticationSuccessHandler"/>
 	</http>
-	
-	<b:bean name="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
+
+	<b:bean id="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient"/>
 	</b:bean>
-	<b:bean name="jwtDecoderFactory" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="jwtDecoderFactory" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.jwt.JwtDecoderFactory"/>
 	</b:bean>
-	<b:bean name="grantedAuthoritiesMapper" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="userAuthoritiesMapper" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper"/>
 	</b:bean>
-	<b:bean name="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.web.AuthorizationRequestRepository"/>
 	</b:bean>
-	<b:bean name="authenticationSuccessHandler" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authenticationSuccessHandler" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.web.authentication.AuthenticationSuccessHandler"/>
 	</b:bean>
 

+ 9 - 10
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithJwtDecoderFactoryAndDefaultSuccessHandler.xml

@@ -28,23 +28,22 @@
 		<intercept-url pattern="/**" access="authenticated"/>
 		<oauth2-login access-token-response-client-ref="accessTokenResponseClient"
 						jwt-decoder-factory-ref="jwtDecoderFactory"
-						user-authorities-mapper-ref="grantedAuthoritiesMapper"
-						authorization-request-repository-ref="authorizationRequestRepository"
-						/>
+						authorization-request-repository-ref="authorizationRequestRepository"/>
+		<request-cache ref="requestCache" />
 	</http>
-	
-	<b:bean name="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
+
+	<b:bean id="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient"/>
 	</b:bean>
-	<b:bean name="jwtDecoderFactory" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="jwtDecoderFactory" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.jwt.JwtDecoderFactory"/>
 	</b:bean>
-	<b:bean name="grantedAuthoritiesMapper" class="org.mockito.Mockito" factory-method="mock">
-			<b:constructor-arg value="org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper"/>
-	</b:bean>
-	<b:bean name="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.web.AuthorizationRequestRepository"/>
 	</b:bean>
+	<b:bean id="requestCache" class="org.mockito.Mockito" factory-method="mock">
+		<b:constructor-arg value="org.springframework.security.web.savedrequest.RequestCache"/>
+	</b:bean>
 
 	<b:import resource="../oauth2/client/google-registration.xml"/>
 	<b:import resource="userservice.xml"/>

+ 0 - 57
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithTestConfiguration.xml

@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2002-2020 the original author or authors.
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~       https://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<b:beans xmlns:b="http://www.springframework.org/schema/beans"
-		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-		xmlns="http://www.springframework.org/schema/security"
-		xsi:schemaLocation="
-			http://www.springframework.org/schema/security
-			https://www.springframework.org/schema/security/spring-security.xsd
-			http://www.springframework.org/schema/beans
-			https://www.springframework.org/schema/beans/spring-beans.xsd">
-
-	<http auto-config="true">
-		<intercept-url pattern="/**" access="authenticated"/>
-		<oauth2-login access-token-response-client-ref="accessTokenResponseClient"
-						user-service-ref="oauth2UserService"
-						oidc-user-service-ref="oauth2UserService"
-						authorization-request-repository-ref="authorizationRequestRepository"
-						authentication-success-handler-ref="authenticationSuccessHandler"/>
-	</http>
-	
-	<b:bean name="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
-			<b:constructor-arg value="org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient"/>
-	</b:bean>
-	<b:bean name="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
-			<b:constructor-arg value="org.springframework.security.oauth2.client.userinfo.OAuth2UserService"/>
-	</b:bean>
-	<b:bean name="jwtDecoderFactory" class="org.mockito.Mockito" factory-method="mock">
-			<b:constructor-arg value="org.springframework.security.oauth2.jwt.JwtDecoderFactory"/>
-	</b:bean>
-	<b:bean name="authenticationSuccessListener" class="org.mockito.Mockito" factory-method="mock">
-			<b:constructor-arg value="org.springframework.context.ApplicationListener"/>
-	</b:bean>
-	<b:bean name="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
-			<b:constructor-arg value="org.springframework.security.oauth2.client.web.AuthorizationRequestRepository"/>
-	</b:bean>
-	<b:bean name="authenticationSuccessHandler" class="org.mockito.Mockito" factory-method="mock">
-			<b:constructor-arg value="org.springframework.security.web.authentication.AuthenticationSuccessHandler"/>
-	</b:bean>
-
-	<b:import resource="../oauth2/client/google-registration.xml"/>
-	<b:import resource="userservice.xml"/>
-</b:beans>

+ 0 - 52
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration-WithinSameFile.xml

@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2002-2020 the original author or authors.
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~       https://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<b:beans xmlns:b="http://www.springframework.org/schema/beans"
-		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-		xmlns="http://www.springframework.org/schema/security"
-		xsi:schemaLocation="
-			http://www.springframework.org/schema/security
-			https://www.springframework.org/schema/security/spring-security.xsd
-			http://www.springframework.org/schema/beans
-			https://www.springframework.org/schema/beans/spring-beans.xsd">
-
-	<http auto-config="true">
-		<intercept-url pattern="/**" access="authenticated"/>
-		<oauth2-login/>
-	</http>
-
-	<client-registrations>
-		<client-registration registration-id="google-login"
-							 client-id="google-client-id"
-							 client-secret="google-client-secret"
-							 client-authentication-method="basic"
-							 authorization-grant-type="authorization_code"
-							 redirect-uri="{baseUrl}/login/oauth2/code/{registrationId}"
-							 scope="openid,profile,email"
-							 client-name="Google"
-							 provider-id="google"/>
-		<provider provider-id="google"
-				  authorization-uri="https://accounts.google.com/o/oauth2/v2/auth"
-				  token-uri="https://www.googleapis.com/oauth2/v4/token"
-				  userinfo-uri="https://www.googleapis.com/oauth2/v3/userinfo"
-				  userinfo-authentication-method="header"
-				  username-attribute-name="sub"
-				  jwkset-uri="https://www.googleapis.com/oauth2/v3/certs"/>
-	</client-registrations>
-
-	<b:import resource="userservice.xml"/>
-</b:beans>

+ 24 - 1
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-SingleClientRegistration.xml

@@ -27,8 +27,31 @@
 	<http auto-config="true">
 		<intercept-url pattern="/**" access="authenticated"/>
 		<oauth2-login/>
+		<request-cache ref="requestCache" />
 	</http>
 
-	<b:import resource="../oauth2/client/google-registration.xml"/>
+	<client-registrations>
+		<client-registration registration-id="google-login"
+							 client-id="google-client-id"
+							 client-secret="google-client-secret"
+							 client-authentication-method="basic"
+							 authorization-grant-type="authorization_code"
+							 redirect-uri="{baseUrl}/login/oauth2/code/{registrationId}"
+							 scope="openid,profile,email"
+							 client-name="Google"
+							 provider-id="google"/>
+		<provider provider-id="google"
+				  authorization-uri="https://accounts.google.com/o/oauth2/v2/auth"
+				  token-uri="https://www.googleapis.com/oauth2/v4/token"
+				  userinfo-uri="https://www.googleapis.com/oauth2/v3/userinfo"
+				  userinfo-authentication-method="header"
+				  username-attribute-name="sub"
+				  jwkset-uri="https://www.googleapis.com/oauth2/v3/certs"/>
+	</client-registrations>
+
+	<b:bean id="requestCache" class="org.mockito.Mockito" factory-method="mock">
+		<b:constructor-arg value="org.springframework.security.web.savedrequest.RequestCache"/>
+	</b:bean>
+
 	<b:import resource="userservice.xml"/>
 </b:beans>

+ 0 - 49
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-WithCustomAuthorizationRequestRepository.xml

@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2002-2020 the original author or authors.
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~       https://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<b:beans xmlns:b="http://www.springframework.org/schema/beans"
-		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-		xmlns="http://www.springframework.org/schema/security"
-		xsi:schemaLocation="
-			http://www.springframework.org/schema/security
-			https://www.springframework.org/schema/security/spring-security.xsd
-			http://www.springframework.org/schema/beans
-			https://www.springframework.org/schema/beans/spring-beans.xsd">
-
-	<http auto-config="true">
-		<intercept-url pattern="/**" access="authenticated"/>
-		<oauth2-login client-registration-repository-ref="clientRegistrationRepository"
-						access-token-response-client-ref="accessTokenResponseClient"
-						user-service-ref="oauth2UserService"
-						authorization-request-repository-ref="authorizationRequestRepository"/>
-	</http>
-
-	<b:bean name="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
-			<b:constructor-arg value="org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient"/>
-	</b:bean>
-	<b:bean name="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
-			<b:constructor-arg value="org.springframework.security.oauth2.client.userinfo.OAuth2UserService"/>
-	</b:bean>
-	<b:bean name="clientRegistrationRepository" class="org.mockito.Mockito" factory-method="mock">
-			<b:constructor-arg value="org.springframework.security.oauth2.client.registration.ClientRegistrationRepository"/>
-	</b:bean>
-	<b:bean name="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
-			<b:constructor-arg value="org.springframework.security.oauth2.client.web.AuthorizationRequestRepository"/>
-	</b:bean>
-
-	<b:import resource="userservice.xml"/>
-</b:beans>

+ 5 - 5
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-WithCustomAuthorizedClientRepository.xml

@@ -33,19 +33,19 @@
 						authorization-request-repository-ref="authorizationRequestRepository"/>
 	</http>
 
-	<b:bean name="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient"/>
 	</b:bean>
-	<b:bean name="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.userinfo.OAuth2UserService"/>
 	</b:bean>
-	<b:bean name="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.web.AuthorizationRequestRepository"/>
 	</b:bean>
-	<b:bean name="clientRegistrationRepository" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="clientRegistrationRepository" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.registration.ClientRegistrationRepository"/>
 	</b:bean>
-	<b:bean name="authorizedClientRepository" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authorizedClientRepository" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository"/>
 	</b:bean>
 

+ 5 - 5
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-WithCustomAuthorizedClientService.xml

@@ -33,19 +33,19 @@
 						authorized-client-service-ref="authorizedClientService"/>
 	</http>
 
-	<b:bean name="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient"/>
 	</b:bean>
-	<b:bean name="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.userinfo.OAuth2UserService"/>
 	</b:bean>
-	<b:bean name="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.web.AuthorizationRequestRepository"/>
 	</b:bean>
-	<b:bean name="clientRegistrationRepository" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="clientRegistrationRepository" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.registration.ClientRegistrationRepository"/>
 	</b:bean>
-	<b:bean name="authorizedClientService" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authorizedClientService" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.OAuth2AuthorizedClientService"/>
 	</b:bean>
 

+ 4 - 5
config/src/test/resources/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests-WithCustomClientRegistrationRepository.xml

@@ -32,19 +32,18 @@
 						authorization-request-repository-ref="authorizationRequestRepository"/>
 	</http>
 
-	<b:bean name="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="accessTokenResponseClient" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient"/>
 	</b:bean>
-	<b:bean name="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="oauth2UserService" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.userinfo.OAuth2UserService"/>
 	</b:bean>
-	<b:bean name="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="authorizationRequestRepository" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.web.AuthorizationRequestRepository"/>
 	</b:bean>
-	<b:bean name="clientRegistrationRepository" class="org.mockito.Mockito" factory-method="mock">
+	<b:bean id="clientRegistrationRepository" class="org.mockito.Mockito" factory-method="mock">
 			<b:constructor-arg value="org.springframework.security.oauth2.client.registration.ClientRegistrationRepository"/>
 	</b:bean>
-	
 
 	<b:import resource="userservice.xml"/>
 </b:beans>

+ 0 - 39
config/src/test/resources/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParserTests-FromIssuerUri.xml

@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2002-2020 the original author or authors.
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~       https://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<b:beans xmlns:b="http://www.springframework.org/schema/beans"
-		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-		xmlns="http://www.springframework.org/schema/security"
-		xsi:schemaLocation="
-			http://www.springframework.org/schema/security
-			https://www.springframework.org/schema/security/spring-security.xsd
-			http://www.springframework.org/schema/beans
-			https://www.springframework.org/schema/beans/spring-beans.xsd">
-	<client-registrations>
-		<client-registration registration-id="google-login"
-							 client-id="google-client-id"
-							 client-secret="google-client-secret"
-							 client-authentication-method="basic"
-							 authorization-grant-type="authorization_code"
-							 redirect-uri="{baseUrl}/login/oauth2/code/{registrationId}"
-							 scope="openid,profile,email"
-							 client-name="Google"
-							 provider-id="google"/>
-		<provider 	provider-id="google"
-					issuer-uri="http://localhost:49259"/>
-	</client-registrations>
-</b:beans>

+ 1 - 1
config/src/test/resources/org/springframework/security/config/oauth2/client/google-github-registration.xml

@@ -39,7 +39,7 @@
 							 client-authentication-method="basic"
 							 authorization-grant-type="authorization_code"
 							 redirect-uri="{baseUrl}/login/oauth2/code/{registrationId}"
-							 scope="openid,profile,email"
+							 scope="read:user"
 							 client-name="Github"
 							 provider-id="github"/>
 		<provider provider-id="google"

+ 14 - 14
docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc

@@ -897,72 +897,72 @@ The <<oauth2login,OAuth 2.0 Login>> feature configures authentication support us
 
 [[nsa-oauth2-login-client-registration-repository-ref]]
 * **client-registration-repository-ref**
-Reference to `ClientRegistrationRepository`.
+Reference to the `ClientRegistrationRepository`.
 
 
 [[nsa-oauth2-login-authorized-client-repository-ref]]
 * **authorized-client-repository-ref**
-Reference to `OAuth2AuthorizedClientRepository`.
+Reference to the `OAuth2AuthorizedClientRepository`.
 
 
 [[nsa-oauth2-login-authorized-client-service-ref]]
 * **authorized-client-service-ref**
-Reference to `OAuth2AuthorizedClientService`.
+Reference to the `OAuth2AuthorizedClientService`.
 
 
 [[nsa-oauth2-login-authorization-request-repository-ref]]
 * **authorization-request-repository-ref**
-Reference to `AuthorizationRequestRepository`.
+Reference to the `AuthorizationRequestRepository`.
 
 
 [[nsa-oauth2-login-authorization-request-resolver-ref]]
 * **authorization-request-resolver-ref**
-Reference to `OAuth2AuthorizationRequestResolver`.
+Reference to the `OAuth2AuthorizationRequestResolver`.
 
 
 [[nsa-oauth2-login-access-token-response-client-ref]]
 * **access-token-response-client-ref**
-Reference to `OAuth2AccessTokenResponseClient`.
+Reference to the `OAuth2AccessTokenResponseClient`.
 
 
 [[nsa-oauth2-login-user-authorities-mapper-ref]]
 * **user-authorities-mapper-ref**
-Reference to `GrantedAuthoritiesMapper`.
+Reference to the `GrantedAuthoritiesMapper`.
 
 
 [[nsa-oauth2-login-user-service-ref]]
 * **user-service-ref**
-Reference to `OAuth2UserService`.
+Reference to the `OAuth2UserService`.
 
 
 [[nsa-oauth2-login-oidc-user-service-ref]]
 * **oidc-user-service-ref**
-Reference to `OidcUserService`.
+Reference to the OpenID Connect `OAuth2UserService`.
 
 
 [[nsa-oauth2-login-login-processing-url]]
 * **login-processing-url**
-Specifies the URL to validate the credentials.
+The URI where the filter processes authentication requests.
 
 
 [[nsa-oauth2-login-login-page]]
 * **login-page**
-Specifies the URL to send users to if login is required
+The URI to send users to login.
 
 
 [[nsa-oauth2-login-authentication-success-handler-ref]]
 * **authentication-success-handler-ref**
-Specifies authentication success handler
+Reference to the `AuthenticationSuccessHandler`.
 
 
 [[nsa-oauth2-login-authentication-failure-handler-ref]]
 * **authentication-failure-handler-ref**
-Specifies authentication failure handler
+Reference to the `AuthenticationFailureHandler`.
 
 
 [[nsa-oauth2-login-jwt-decoder-factory-ref]]
 * **jwt-decoder-factory-ref**
-Specifies JWT decoder factory for OidcAuthorizationCodeAuthenticationProvider
+Reference to the `JwtDecoderFactory` used by `OidcAuthorizationCodeAuthenticationProvider`.
 
 
 [[nsa-client-registrations]]

+ 12 - 1
oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/TestOAuth2AccessTokenResponses.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,6 +17,10 @@
 package org.springframework.security.oauth2.core.endpoint;
 
 import org.springframework.security.oauth2.core.OAuth2AccessToken;
+import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
+
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * @author Rob Winch
@@ -27,4 +31,11 @@ public class TestOAuth2AccessTokenResponses {
 		return OAuth2AccessTokenResponse.withToken("token")
 				.tokenType(OAuth2AccessToken.TokenType.BEARER);
 	}
+
+	public static OAuth2AccessTokenResponse.Builder oidcAccessTokenResponse() {
+		Map<String, Object> additionalParameters = new HashMap<>();
+		additionalParameters.put(OidcParameterNames.ID_TOKEN, "id-token");
+		return accessTokenResponse()
+				.additionalParameters(additionalParameters);
+	}
 }

+ 5 - 1
oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/TestOAuth2AuthorizationRequests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2020 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -36,4 +36,8 @@ public class TestOAuth2AuthorizationRequests {
 				.state("state")
 				.attributes(attributes);
 	}
+
+	public static OAuth2AuthorizationRequest.Builder oidcRequest() {
+		return request().scope("openid");
+	}
 }