Parcourir la source

Rename OAuth2/OIDC ClientAuthenticationToken -> AuthorizedClient

Fixes gh-4695
Joe Grandja il y a 8 ans
Parent
commit
5a584e5ccb
14 fichiers modifiés avec 117 ajouts et 125 suppressions
  1. 16 26
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizedClient.java
  2. 12 9
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProvider.java
  3. 4 6
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/CustomUserTypesOAuth2UserService.java
  4. 5 5
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/DefaultOAuth2UserService.java
  5. 4 4
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/DelegatingOAuth2UserService.java
  6. 4 5
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/NimbusUserInfoRetriever.java
  7. 12 12
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/OAuth2AuthenticationToken.java
  8. 4 4
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/OAuth2UserService.java
  9. 4 5
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/UserInfoRetriever.java
  10. 15 11
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcAuthorizationCodeAuthenticationProvider.java
  11. 14 15
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcAuthorizedClient.java
  12. 14 14
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/userinfo/OidcUserService.java
  13. 6 6
      oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilterTests.java
  14. 3 3
      samples/boot/oauth2login/src/main/java/sample/web/MainController.java

+ 16 - 26
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2ClientAuthenticationToken.java → oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizedClient.java

@@ -15,26 +15,22 @@
  */
 package org.springframework.security.oauth2.client.authentication;
 
-import org.springframework.security.authentication.AbstractAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.SpringSecurityCoreVersion;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.core.AccessToken;
 import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
 
-import java.util.Collections;
 import java.util.Set;
 
 /**
- * An implementation of an {@link AbstractAuthenticationToken}
- * that represents an <i>OAuth 2.0 Client</i> {@link Authentication}.
- *
+ * A representation of an OAuth 2.0 <i>&quot;Authorized Client&quot;</i>.
+ * <p>
+ * A client is considered <i>&quot;authorized&quot;</i>
+ * when it receives a successful response from the <i>Token Endpoint</i>.
  * <p>
- * A client is considered <i>&quot;authenticated&quot;</i>,
- * if it receives a successful response from the <i>Token Endpoint</i>.
- * This {@link Authentication} associates the client identified in {@link #getClientRegistration()}
- * to the {@link #getAccessToken()} granted by the resource owner.
+ * This class associates the {@link #getClientRegistration() Client}
+ * to the {@link #getAccessToken() Access Token}
+ * granted/authorized by the {@link #getPrincipalName() Resource Owner}.
  *
  * @author Joe Grandja
  * @since 5.0
@@ -42,34 +38,28 @@ import java.util.Set;
  * @see AccessToken
  * @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-5.1">Section 5.1 Access Token Response</a>
  */
-public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken {
-	private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
+public class AuthorizedClient {
 	private final ClientRegistration clientRegistration;
+	private final String principalName;
 	private final AccessToken accessToken;
 
-	public OAuth2ClientAuthenticationToken(ClientRegistration clientRegistration, AccessToken accessToken) {
-		super(Collections.emptyList());
+	public AuthorizedClient(ClientRegistration clientRegistration, String principalName, AccessToken accessToken) {
 		Assert.notNull(clientRegistration, "clientRegistration cannot be null");
+		Assert.hasText(principalName, "principalName cannot be empty");
 		Assert.notNull(accessToken, "accessToken cannot be null");
 		this.clientRegistration = clientRegistration;
+		this.principalName = principalName;
 		this.accessToken = accessToken;
-		this.setAuthenticated(true);		// The Client is authenticated by the Authorization Server
-	}
-
-	@Override
-	public Object getPrincipal() {
-		return this.getClientRegistration().getClientId();
-	}
-
-	@Override
-	public Object getCredentials() {
-		return "";		// No need to expose this.getClientRegistration().getClientSecret()
 	}
 
 	public ClientRegistration getClientRegistration() {
 		return this.clientRegistration;
 	}
 
+	public String getPrincipalName() {
+		return this.principalName;
+	}
+
 	public AccessToken getAccessToken() {
 		return this.accessToken;
 	}

+ 12 - 9
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProvider.java

@@ -51,7 +51,7 @@ import java.util.Collection;
  * @see AuthorizationCodeAuthenticationToken
  * @see SecurityTokenRepository
  * @see OAuth2AuthenticationToken
- * @see OAuth2ClientAuthenticationToken
+ * @see AuthorizedClient
  * @see OAuth2UserService
  * @see OAuth2User
  * @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">Section 4.1 Authorization Code Grant Flow</a>
@@ -118,22 +118,25 @@ public class OAuth2LoginAuthenticationProvider implements AuthenticationProvider
 			tokenResponse.getTokenValue(), tokenResponse.getIssuedAt(),
 			tokenResponse.getExpiresAt(), tokenResponse.getScopes());
 
-		OAuth2ClientAuthenticationToken clientAuthentication =
-			new OAuth2ClientAuthenticationToken(authorizationCodeAuthentication.getClientRegistration(), accessToken);
-		clientAuthentication.setDetails(authorizationCodeAuthentication.getDetails());
+		AuthorizedClient authorizedClient = new AuthorizedClient(
+			authorizationCodeAuthentication.getClientRegistration(), "unknown", accessToken);
 
 		this.accessTokenRepository.saveSecurityToken(
-			clientAuthentication.getAccessToken(),
-			clientAuthentication.getClientRegistration());
+			authorizedClient.getAccessToken(),
+			authorizedClient.getClientRegistration());
 
-		OAuth2User oauth2User = this.userService.loadUser(clientAuthentication);
+		OAuth2User oauth2User = this.userService.loadUser(authorizedClient);
+
+		// Update AuthorizedClient now that we know the 'principalName'
+		authorizedClient = new AuthorizedClient(
+			authorizationCodeAuthentication.getClientRegistration(), oauth2User.getName(), accessToken);
 
 		Collection<? extends GrantedAuthority> mappedAuthorities =
 			this.authoritiesMapper.mapAuthorities(oauth2User.getAuthorities());
 
 		OAuth2AuthenticationToken authenticationResult = new OAuth2AuthenticationToken(
-			oauth2User, mappedAuthorities, clientAuthentication);
-		authenticationResult.setDetails(clientAuthentication.getDetails());
+			oauth2User, mappedAuthorities, authorizedClient);
+		authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
 
 		return authenticationResult;
 	}

+ 4 - 6
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/CustomUserTypesOAuth2UserService.java

@@ -15,10 +15,8 @@
  */
 package org.springframework.security.oauth2.client.authentication.userinfo;
 
-import org.springframework.beans.BeanWrapper;
-import org.springframework.beans.PropertyAccessorFactory;
+import org.springframework.security.oauth2.client.authentication.AuthorizedClient;
 import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
-import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
 import org.springframework.security.oauth2.core.user.OAuth2User;
 import org.springframework.util.Assert;
 
@@ -53,14 +51,14 @@ public class CustomUserTypesOAuth2UserService implements OAuth2UserService {
 	}
 
 	@Override
-	public OAuth2User loadUser(OAuth2ClientAuthenticationToken clientAuthentication) throws OAuth2AuthenticationException {
-		URI userInfoUri = URI.create(clientAuthentication.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri());
+	public OAuth2User loadUser(AuthorizedClient authorizedClient) throws OAuth2AuthenticationException {
+		URI userInfoUri = URI.create(authorizedClient.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri());
 		Class<? extends OAuth2User> customUserType;
 		if ((customUserType = this.customUserTypes.get(userInfoUri)) == null) {
 			return null;
 		}
 
-		return this.userInfoRetriever.retrieve(clientAuthentication, customUserType);
+		return this.userInfoRetriever.retrieve(authorizedClient, customUserType);
 	}
 
 	public final void setUserInfoRetriever(UserInfoRetriever userInfoRetriever) {

+ 5 - 5
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/DefaultOAuth2UserService.java

@@ -17,7 +17,7 @@ package org.springframework.security.oauth2.client.authentication.userinfo;
 
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
-import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
+import org.springframework.security.oauth2.client.authentication.AuthorizedClient;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
 import org.springframework.security.oauth2.core.user.OAuth2User;
@@ -52,15 +52,15 @@ public class DefaultOAuth2UserService implements OAuth2UserService {
 	private UserInfoRetriever userInfoRetriever = new NimbusUserInfoRetriever();
 
 	@Override
-	public OAuth2User loadUser(OAuth2ClientAuthenticationToken clientAuthentication) throws OAuth2AuthenticationException {
-		String userNameAttributeName = clientAuthentication.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName();
+	public OAuth2User loadUser(AuthorizedClient authorizedClient) throws OAuth2AuthenticationException {
+		String userNameAttributeName = authorizedClient.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName();
 		if (!StringUtils.hasText(userNameAttributeName)) {
 			throw new IllegalArgumentException(
 				"Missing required \"user name\" attribute name in UserInfoEndpoint for Client Registration: " +
-					clientAuthentication.getClientRegistration().getRegistrationId());
+					authorizedClient.getClientRegistration().getRegistrationId());
 		}
 
-		Map<String, Object> userAttributes = this.userInfoRetriever.retrieve(clientAuthentication, Map.class);
+		Map<String, Object> userAttributes = this.userInfoRetriever.retrieve(authorizedClient, Map.class);
 		GrantedAuthority authority = new OAuth2UserAuthority(userAttributes);
 		Set<GrantedAuthority> authorities = new HashSet<>();
 		authorities.add(authority);

+ 4 - 4
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/DelegatingOAuth2UserService.java

@@ -16,7 +16,7 @@
 package org.springframework.security.oauth2.client.authentication.userinfo;
 
 import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
-import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
+import org.springframework.security.oauth2.client.authentication.AuthorizedClient;
 import org.springframework.security.oauth2.core.user.OAuth2User;
 import org.springframework.util.Assert;
 
@@ -30,7 +30,7 @@ import java.util.Objects;
  * to it's internal <code>List</code> of {@link OAuth2UserService}'s.
  * <p>
  * Each {@link OAuth2UserService} is given a chance to
- * {@link OAuth2UserService#loadUser(OAuth2ClientAuthenticationToken) load} an {@link OAuth2User}
+ * {@link OAuth2UserService#loadUser(AuthorizedClient) load} an {@link OAuth2User}
  * with the first <code>non-null</code> {@link OAuth2User} being returned.
  *
  * @author Joe Grandja
@@ -47,9 +47,9 @@ public class DelegatingOAuth2UserService implements OAuth2UserService {
 	}
 
 	@Override
-	public OAuth2User loadUser(OAuth2ClientAuthenticationToken clientAuthentication) throws OAuth2AuthenticationException {
+	public OAuth2User loadUser(AuthorizedClient authorizedClient) throws OAuth2AuthenticationException {
 		OAuth2User oauth2User = this.userServices.stream()
-			.map(userService -> userService.loadUser(clientAuthentication))
+			.map(userService -> userService.loadUser(authorizedClient))
 			.filter(Objects::nonNull)
 			.findFirst()
 			.orElse(null);

+ 4 - 5
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/NimbusUserInfoRetriever.java

@@ -28,7 +28,7 @@ import org.springframework.http.converter.HttpMessageConverter;
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
 import org.springframework.security.authentication.AuthenticationServiceException;
 import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
-import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
+import org.springframework.security.oauth2.client.authentication.AuthorizedClient;
 import org.springframework.security.oauth2.core.OAuth2Error;
 import org.springframework.util.Assert;
 
@@ -37,7 +37,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
 import java.nio.charset.Charset;
-import java.util.Map;
 
 /**
  * An implementation of a {@link UserInfoRetriever} that uses the <b>Nimbus OAuth 2.0 SDK</b> internally.
@@ -52,9 +51,9 @@ public class NimbusUserInfoRetriever implements UserInfoRetriever {
 	private final HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
 
 	@Override
-	public <T> T retrieve(OAuth2ClientAuthenticationToken clientAuthentication, Class<T> returnType) throws OAuth2AuthenticationException {
-		URI userInfoUri = URI.create(clientAuthentication.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri());
-		BearerAccessToken accessToken = new BearerAccessToken(clientAuthentication.getAccessToken().getTokenValue());
+	public <T> T retrieve(AuthorizedClient authorizedClient, Class<T> returnType) throws OAuth2AuthenticationException {
+		URI userInfoUri = URI.create(authorizedClient.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri());
+		BearerAccessToken accessToken = new BearerAccessToken(authorizedClient.getAccessToken().getTokenValue());
 
 		UserInfoRequest userInfoRequest = new UserInfoRequest(userInfoUri, accessToken);
 		HTTPRequest httpRequest = userInfoRequest.toHTTPRequest();

+ 12 - 12
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/OAuth2AuthenticationToken.java

@@ -19,7 +19,7 @@ import org.springframework.security.authentication.AbstractAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.SpringSecurityCoreVersion;
-import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
+import org.springframework.security.oauth2.client.authentication.AuthorizedClient;
 import org.springframework.security.oauth2.core.user.OAuth2User;
 import org.springframework.util.Assert;
 
@@ -28,28 +28,28 @@ import java.util.Collection;
 /**
  * An implementation of an {@link AbstractAuthenticationToken}
  * that represents an <i>OAuth 2.0</i> {@link Authentication}.
- *
  * <p>
- * This {@link Authentication} associates an {@link OAuth2User} principal to an
- * {@link OAuth2ClientAuthenticationToken} which represents the <i>&quot;Authorized Client&quot;</i>.
+ * This {@link Authentication} associates an {@link OAuth2User} principal
+ * to an {@link AuthorizedClient}.
  *
  * @author Joe Grandja
  * @since 5.0
  * @see OAuth2User
- * @see OAuth2ClientAuthenticationToken
+ * @see AuthorizedClient
  */
 public class OAuth2AuthenticationToken extends AbstractAuthenticationToken {
 	private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
 	private final OAuth2User principal;
-	private final OAuth2ClientAuthenticationToken clientAuthentication;
+	private final AuthorizedClient authorizedClient;
 
 	public OAuth2AuthenticationToken(OAuth2User principal, Collection<? extends GrantedAuthority> authorities,
-										OAuth2ClientAuthenticationToken clientAuthentication) {
+										AuthorizedClient authorizedClient) {
 		super(authorities);
-		Assert.notNull(clientAuthentication, "clientAuthentication cannot be null");
+		Assert.notNull(principal, "principal cannot be null");
+		Assert.notNull(authorizedClient, "authorizedClient cannot be null");
 		this.principal = principal;
-		this.clientAuthentication = clientAuthentication;
-		this.setAuthenticated(principal != null);
+		this.authorizedClient = authorizedClient;
+		this.setAuthenticated(true);
 	}
 
 	@Override
@@ -63,7 +63,7 @@ public class OAuth2AuthenticationToken extends AbstractAuthenticationToken {
 		return "";
 	}
 
-	public OAuth2ClientAuthenticationToken getClientAuthentication() {
-		return this.clientAuthentication;
+	public AuthorizedClient getAuthorizedClient() {
+		return this.authorizedClient;
 	}
 }

+ 4 - 4
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/OAuth2UserService.java

@@ -16,24 +16,24 @@
 package org.springframework.security.oauth2.client.authentication.userinfo;
 
 import org.springframework.security.core.AuthenticatedPrincipal;
+import org.springframework.security.oauth2.client.authentication.AuthorizedClient;
 import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
-import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
 import org.springframework.security.oauth2.core.user.OAuth2User;
 
 /**
  * Implementations of this interface are responsible for obtaining the user attributes
  * of the <i>End-User</i> (resource owner) from the <i>UserInfo Endpoint</i>
- * using the provided {@link OAuth2ClientAuthenticationToken#getAccessToken()}
+ * using the provided {@link AuthorizedClient#getAccessToken()}
  * and returning an {@link AuthenticatedPrincipal} in the form of an {@link OAuth2User}.
  *
  * @author Joe Grandja
  * @since 5.0
- * @see OAuth2ClientAuthenticationToken
+ * @see AuthorizedClient
  * @see AuthenticatedPrincipal
  * @see OAuth2User
  */
 public interface OAuth2UserService {
 
-	OAuth2User loadUser(OAuth2ClientAuthenticationToken clientAuthentication) throws OAuth2AuthenticationException;
+	OAuth2User loadUser(AuthorizedClient authorizedClient) throws OAuth2AuthenticationException;
 
 }

+ 4 - 5
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/UserInfoRetriever.java

@@ -15,23 +15,22 @@
  */
 package org.springframework.security.oauth2.client.authentication.userinfo;
 
-import org.springframework.core.ParameterizedTypeReference;
 import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
-import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
+import org.springframework.security.oauth2.client.authentication.AuthorizedClient;
 
 /**
  * A strategy for retrieving the user attributes
  * of the <i>End-User</i> (resource owner) from the <i>UserInfo Endpoint</i>
- * using the provided {@link OAuth2ClientAuthenticationToken#getAccessToken()}.
+ * using the provided {@link AuthorizedClient#getAccessToken()}.
  *
  * @author Joe Grandja
  * @author Rob Winch
  * @since 5.0
- * @see OAuth2ClientAuthenticationToken
+ * @see AuthorizedClient
  * @see OAuth2UserService
  */
 public interface UserInfoRetriever {
 
-	<T> T retrieve(OAuth2ClientAuthenticationToken clientAuthentication, Class<T> responseType) throws OAuth2AuthenticationException;
+	<T> T retrieve(AuthorizedClient clientAuthentication, Class<T> responseType) throws OAuth2AuthenticationException;
 
 }

+ 15 - 11
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcAuthorizationCodeAuthenticationProvider.java

@@ -62,7 +62,7 @@ import java.util.Collection;
  * @since 5.0
  * @see AuthorizationCodeAuthenticationToken
  * @see SecurityTokenRepository
- * @see OidcClientAuthenticationToken
+ * @see OidcAuthorizedClient
  * @see OidcUserService
  * @see OidcUser
  * @see <a target="_blank" href="http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth">Section 3.1 Authorization Code Grant Flow</a>
@@ -142,28 +142,32 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati
 
 		JwtDecoder jwtDecoder = this.jwtDecoderRegistry.getJwtDecoder(clientRegistration);
 		if (jwtDecoder == null) {
-			throw new IllegalArgumentException("Failed to find a registered JwtDecoder for Client Registration: '" + clientRegistration.getRegistrationId() +
-				"'. Check to ensure you have configured the JwkSet URI.");
+			throw new IllegalArgumentException("Failed to find a registered JwtDecoder for Client Registration: '" +
+				clientRegistration.getRegistrationId() + "'. Check to ensure you have configured the JwkSet URI.");
 		}
 		Jwt jwt = jwtDecoder.decode((String)tokenResponse.getAdditionalParameters().get(OidcParameter.ID_TOKEN));
 		IdToken idToken = new IdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims());
 
-		OidcClientAuthenticationToken clientAuthentication =
-			new OidcClientAuthenticationToken(clientRegistration, accessToken, idToken);
-		clientAuthentication.setDetails(authorizationCodeAuthentication.getDetails());
+		OidcAuthorizedClient authorizedClient = new OidcAuthorizedClient(
+			clientRegistration, idToken.getSubject(), accessToken, idToken);
 
 		this.accessTokenRepository.saveSecurityToken(
-			clientAuthentication.getAccessToken(),
-			clientAuthentication.getClientRegistration());
+			authorizedClient.getAccessToken(),
+			authorizedClient.getClientRegistration());
 
-		OAuth2User oauth2User = this.userService.loadUser(clientAuthentication);
+		OAuth2User oauth2User = this.userService.loadUser(authorizedClient);
+
+		// Update AuthorizedClient as the 'principalName' may have changed
+		// (the default IdToken.subject) from the result of userService.loadUser()
+		authorizedClient = new OidcAuthorizedClient(
+			clientRegistration, oauth2User.getName(), accessToken, idToken);
 
 		Collection<? extends GrantedAuthority> mappedAuthorities =
 			this.authoritiesMapper.mapAuthorities(oauth2User.getAuthorities());
 
 		OAuth2AuthenticationToken authenticationResult = new OAuth2AuthenticationToken(
-			oauth2User, mappedAuthorities, clientAuthentication);
-		authenticationResult.setDetails(clientAuthentication.getDetails());
+			oauth2User, mappedAuthorities, authorizedClient);
+		authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
 
 		return authenticationResult;
 	}

+ 14 - 15
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcClientAuthenticationToken.java → oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcAuthorizedClient.java

@@ -15,37 +15,36 @@
  */
 package org.springframework.security.oauth2.oidc.client.authentication;
 
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
+import org.springframework.security.oauth2.client.authentication.AuthorizedClient;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.core.AccessToken;
 import org.springframework.security.oauth2.oidc.core.IdToken;
 import org.springframework.util.Assert;
 
 /**
- * An {@link OAuth2ClientAuthenticationToken} that represents an
- * <i>OpenID Connect 1.0 Client</i> {@link Authentication}.
- *
+ * A representation of an OpenID Connect 1.0 <i>&quot;Authorized Client&quot;</i>.
+ * <p>
+ * A client is considered <i>&quot;authorized&quot;</i>
+ * when it receives a successful response from the <i>Token Endpoint</i>.
  * <p>
- * A client is considered <i>&quot;authenticated&quot;</i>,
- * if it receives a successful response from the <i>Token Endpoint</i>.
- * This {@link Authentication} associates the client identified in {@link #getClientRegistration()}
- * to the {@link #getAccessToken()} granted by the resource owner along with the {@link #getIdToken()}
- * containing Claims about the authentication of the End-User.
+ * This class associates the {@link #getClientRegistration() Client}
+ * to the {@link #getAccessToken() Access Token}
+ * granted/authorized by the {@link #getPrincipalName() Resource Owner}, along with
+ * the {@link #getIdToken() ID Token} which contains Claims about the authentication of the End-User.
  *
  * @author Joe Grandja
  * @since 5.0
  * @see IdToken
- * @see OAuth2ClientAuthenticationToken
+ * @see AuthorizedClient
  * @see <a target="_blank" href="http://openid.net/specs/openid-connect-core-1_0.html#TokenResponse">3.1.3.3 Successful Token Response</a>
  */
-public class OidcClientAuthenticationToken extends OAuth2ClientAuthenticationToken {
+public class OidcAuthorizedClient extends AuthorizedClient {
 	private final IdToken idToken;
 
-	public OidcClientAuthenticationToken(ClientRegistration clientRegistration,
-											AccessToken accessToken, IdToken idToken) {
+	public OidcAuthorizedClient(ClientRegistration clientRegistration, String principalName,
+								AccessToken accessToken, IdToken idToken) {
 
-		super(clientRegistration, accessToken);
+		super(clientRegistration, principalName, accessToken);
 		Assert.notNull(idToken, "idToken cannot be null");
 		this.idToken = idToken;
 	}

+ 14 - 14
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/userinfo/OidcUserService.java

@@ -16,15 +16,15 @@
 package org.springframework.security.oauth2.oidc.client.authentication.userinfo;
 
 import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.oauth2.client.authentication.AuthorizedClient;
 import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
-import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
 import org.springframework.security.oauth2.client.authentication.userinfo.NimbusUserInfoRetriever;
 import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2UserService;
 import org.springframework.security.oauth2.client.authentication.userinfo.UserInfoRetriever;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.security.oauth2.core.OAuth2Error;
 import org.springframework.security.oauth2.core.user.OAuth2User;
-import org.springframework.security.oauth2.oidc.client.authentication.OidcClientAuthenticationToken;
+import org.springframework.security.oauth2.oidc.client.authentication.OidcAuthorizedClient;
 import org.springframework.security.oauth2.oidc.core.OidcScope;
 import org.springframework.security.oauth2.oidc.core.UserInfo;
 import org.springframework.security.oauth2.oidc.core.user.DefaultOidcUser;
@@ -47,7 +47,7 @@ import java.util.Set;
  * @author Joe Grandja
  * @since 5.0
  * @see OAuth2UserService
- * @see OidcClientAuthenticationToken
+ * @see OidcAuthorizedClient
  * @see DefaultOidcUser
  * @see UserInfo
  * @see UserInfoRetriever
@@ -59,12 +59,12 @@ public class OidcUserService implements OAuth2UserService {
 		Arrays.asList(OidcScope.PROFILE, OidcScope.EMAIL, OidcScope.ADDRESS, OidcScope.PHONE));
 
 	@Override
-	public OAuth2User loadUser(OAuth2ClientAuthenticationToken clientAuthentication) throws OAuth2AuthenticationException {
-		OidcClientAuthenticationToken oidcClientAuthentication = (OidcClientAuthenticationToken)clientAuthentication;
+	public OAuth2User loadUser(AuthorizedClient authorizedClient) throws OAuth2AuthenticationException {
+		OidcAuthorizedClient oidcAuthorizedClient = (OidcAuthorizedClient)authorizedClient;
 
 		UserInfo userInfo = null;
-		if (this.shouldRetrieveUserInfo(oidcClientAuthentication)) {
-			Map<String, Object> userAttributes = this.userInfoRetriever.retrieve(oidcClientAuthentication, Map.class);
+		if (this.shouldRetrieveUserInfo(oidcAuthorizedClient)) {
+			Map<String, Object> userAttributes = this.userInfoRetriever.retrieve(oidcAuthorizedClient, Map.class);
 			userInfo = new UserInfo(userAttributes);
 
 			// http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
@@ -74,17 +74,17 @@ public class OidcUserService implements OAuth2UserService {
 			// The sub Claim in the UserInfo Response MUST be verified to exactly match
 			// the sub Claim in the ID Token; if they do not match,
 			// the UserInfo Response values MUST NOT be used.
-			if (!userInfo.getSubject().equals(oidcClientAuthentication.getIdToken().getSubject())) {
+			if (!userInfo.getSubject().equals(oidcAuthorizedClient.getIdToken().getSubject())) {
 				OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE);
 				throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
 			}
 		}
 
-		GrantedAuthority authority = new OidcUserAuthority(oidcClientAuthentication.getIdToken(), userInfo);
+		GrantedAuthority authority = new OidcUserAuthority(oidcAuthorizedClient.getIdToken(), userInfo);
 		Set<GrantedAuthority> authorities = new HashSet<>();
 		authorities.add(authority);
 
-		return new DefaultOidcUser(authorities, oidcClientAuthentication.getIdToken(), userInfo);
+		return new DefaultOidcUser(authorities, oidcAuthorizedClient.getIdToken(), userInfo);
 	}
 
 	public final void setUserInfoRetriever(UserInfoRetriever userInfoRetriever) {
@@ -92,9 +92,9 @@ public class OidcUserService implements OAuth2UserService {
 		this.userInfoRetriever = userInfoRetriever;
 	}
 
-	private boolean shouldRetrieveUserInfo(OidcClientAuthenticationToken oidcClientAuthentication) {
+	private boolean shouldRetrieveUserInfo(OidcAuthorizedClient oidcAuthorizedClient) {
 		// Auto-disabled if UserInfo Endpoint URI is not provided
-		if (StringUtils.isEmpty(oidcClientAuthentication.getClientRegistration().getProviderDetails()
+		if (StringUtils.isEmpty(oidcAuthorizedClient.getClientRegistration().getProviderDetails()
 			.getUserInfoEndpoint().getUri())) {
 
 			return false;
@@ -107,10 +107,10 @@ public class OidcUserService implements OAuth2UserService {
 		// the resulting Claims are returned in the ID Token.
 		// The Authorization Code Grant Flow, which is response_type=code, results in an Access Token being issued.
 		if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(
-			oidcClientAuthentication.getClientRegistration().getAuthorizationGrantType())) {
+			oidcAuthorizedClient.getClientRegistration().getAuthorizationGrantType())) {
 
 			// Return true if there is at least one match between the authorized scope(s) and UserInfo scope(s)
-			return oidcClientAuthentication.getAuthorizedScopes().stream().anyMatch(userInfoScopes::contains);
+			return oidcAuthorizedClient.getAuthorizedScopes().stream().anyMatch(userInfoScopes::contains);
 		}
 
 		return false;

+ 6 - 6
oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilterTests.java

@@ -28,7 +28,7 @@ import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.authority.AuthorityUtils;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
-import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
+import org.springframework.security.oauth2.client.authentication.AuthorizedClient;
 import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2AuthenticationToken;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
@@ -98,13 +98,13 @@ public class OAuth2LoginAuthenticationFilterTests {
 	@Test
 	public void doFilterWhenAuthorizationCodeSuccessResponseThenAuthenticationSuccessHandlerIsCalled() throws Exception {
 		ClientRegistration clientRegistration = TestUtil.githubClientRegistration();
-		OAuth2ClientAuthenticationToken clientAuthentication = new OAuth2ClientAuthenticationToken(
-			clientRegistration, mock(AccessToken.class));
+		AuthorizedClient authorizedClient = new AuthorizedClient(
+			clientRegistration, "principal", mock(AccessToken.class));
 		OAuth2AuthenticationToken userAuthentication = new OAuth2AuthenticationToken(
-			mock(OAuth2User.class), AuthorityUtils.createAuthorityList("ROLE_USER"), clientAuthentication);
+			mock(OAuth2User.class), AuthorityUtils.createAuthorityList("ROLE_USER"), authorizedClient);
 		SecurityContextHolder.getContext().setAuthentication(userAuthentication);
 		AuthenticationManager authenticationManager = mock(AuthenticationManager.class);
-		Mockito.when(authenticationManager.authenticate(Matchers.any(Authentication.class))).thenReturn(clientAuthentication);
+		Mockito.when(authenticationManager.authenticate(Matchers.any(Authentication.class))).thenReturn(userAuthentication);
 
 		OAuth2LoginAuthenticationFilter filter = Mockito.spy(setupFilter(authenticationManager, clientRegistration));
 		AuthenticationSuccessHandler successHandler = mock(AuthenticationSuccessHandler.class);
@@ -128,7 +128,7 @@ public class OAuth2LoginAuthenticationFilterTests {
 		ArgumentCaptor<Authentication> authenticationArgCaptor = ArgumentCaptor.forClass(Authentication.class);
 		Mockito.verify(successHandler).onAuthenticationSuccess(Matchers.any(HttpServletRequest.class), Matchers.any(HttpServletResponse.class),
 				authenticationArgCaptor.capture());
-		Assertions.assertThat(authenticationArgCaptor.getValue()).isEqualTo(clientAuthentication);
+		Assertions.assertThat(authenticationArgCaptor.getValue()).isEqualTo(userAuthentication);
 	}
 
 	@Test

+ 3 - 3
samples/boot/oauth2login/src/main/java/sample/web/MainController.java

@@ -40,14 +40,14 @@ public class MainController {
 	@RequestMapping("/")
 	public String index(Model model, @AuthenticationPrincipal OAuth2User user, OAuth2AuthenticationToken authentication) {
 		model.addAttribute("userName", user.getName());
-		model.addAttribute("clientName", authentication.getClientAuthentication().getClientRegistration().getClientName());
+		model.addAttribute("clientName", authentication.getAuthorizedClient().getClientRegistration().getClientName());
 		return "index";
 	}
 
 	@RequestMapping("/userinfo")
 	public String userinfo(Model model, OAuth2AuthenticationToken authentication) {
 		Map userAttributes = Collections.emptyMap();
-		String userInfoEndpointUri = authentication.getClientAuthentication().getClientRegistration()
+		String userInfoEndpointUri = authentication.getAuthorizedClient().getClientRegistration()
 			.getProviderDetails().getUserInfoEndpoint().getUri();
 		if (!StringUtils.isEmpty(userInfoEndpointUri)) {	// userInfoEndpointUri is optional for OIDC Clients
 			userAttributes = WebClient.builder()
@@ -67,7 +67,7 @@ public class MainController {
 		return ExchangeFilterFunction.ofRequestProcessor(
 			clientRequest -> {
 				ClientRequest authorizedRequest = ClientRequest.from(clientRequest)
-					.header(HttpHeaders.AUTHORIZATION, "Bearer " + authentication.getClientAuthentication().getAccessToken().getTokenValue())
+					.header(HttpHeaders.AUTHORIZATION, "Bearer " + authentication.getAuthorizedClient().getAccessToken().getTokenValue())
 					.build();
 				return Mono.just(authorizedRequest);
 			});