Re-structure OAuth2AuthenticationToken

Fixes gh-4553
This commit is contained in:
Joe Grandja 2017-09-19 12:36:06 -04:00
parent 8854414101
commit c54c622124
10 changed files with 143 additions and 80 deletions

View File

@ -45,7 +45,7 @@ import java.util.Collection;
* <i>id token</i> credential (for OpenID Connect Authorization Code Flow). * <i>id token</i> credential (for OpenID Connect Authorization Code Flow).
* Additionally, it will also obtain the end-user's (resource owner) attributes from the <i>UserInfo Endpoint</i> * Additionally, it will also obtain the end-user's (resource owner) attributes from the <i>UserInfo Endpoint</i>
* (using the <i>access token</i>) and create a <code>Principal</code> in the form of an {@link OAuth2User} * (using the <i>access token</i>) and create a <code>Principal</code> in the form of an {@link OAuth2User}
* associating it with the returned {@link OAuth2AuthenticationToken}. * associating it with the returned {@link OAuth2UserAuthenticationToken}.
* *
* <p> * <p>
* The {@link AuthorizationCodeAuthenticationProvider} uses an {@link AuthorizationGrantTokenExchanger} * The {@link AuthorizationCodeAuthenticationProvider} uses an {@link AuthorizationGrantTokenExchanger}
@ -54,19 +54,21 @@ import java.util.Collection;
* If the request is valid, the authorization server will respond back with a {@link TokenResponseAttributes}. * If the request is valid, the authorization server will respond back with a {@link TokenResponseAttributes}.
* *
* <p> * <p>
* It will then create an {@link OAuth2AuthenticationToken} associating the {@link AccessToken} and optionally * It will then create an {@link OAuth2ClientAuthenticationToken} associating the {@link AccessToken} and optionally
* the {@link IdToken} from the {@link TokenResponseAttributes} and pass it to * the {@link IdToken} from the {@link TokenResponseAttributes} and pass it to
* {@link OAuth2UserService#loadUser(OAuth2AuthenticationToken)} to obtain the end-user's (resource owner) attributes * {@link OAuth2UserService#loadUser(OAuth2ClientAuthenticationToken)} to obtain the end-user's (resource owner) attributes
* in the form of an {@link OAuth2User}. * in the form of an {@link OAuth2User}.
* *
* <p> * <p>
* Finally, it will create another {@link OAuth2AuthenticationToken}, this time associating * Finally, it will create an {@link OAuth2UserAuthenticationToken}, associating the {@link OAuth2User}
* the {@link AccessToken}, {@link IdToken} and {@link OAuth2User} and return it to the {@link AuthenticationManager}, * and {@link OAuth2ClientAuthenticationToken} and return it to the {@link AuthenticationManager},
* at which point the {@link OAuth2AuthenticationToken} is considered <i>&quot;authenticated&quot;</i>. * at which point the {@link OAuth2UserAuthenticationToken} is considered <i>&quot;authenticated&quot;</i>.
* *
* @author Joe Grandja * @author Joe Grandja
* @since 5.0 * @since 5.0
* @see AuthorizationCodeAuthenticationToken * @see AuthorizationCodeAuthenticationToken
* @see OAuth2ClientAuthenticationToken
* @see OAuth2UserAuthenticationToken
* @see AuthorizationGrantTokenExchanger * @see AuthorizationGrantTokenExchanger
* @see TokenResponseAttributes * @see TokenResponseAttributes
* @see AccessToken * @see AccessToken
@ -126,23 +128,22 @@ public class AuthorizationCodeAuthenticationProvider implements AuthenticationPr
idToken = new IdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims()); idToken = new IdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims());
} }
OAuth2AuthenticationToken accessTokenAuthentication = OAuth2ClientAuthenticationToken oauth2ClientAuthentication =
new OAuth2AuthenticationToken(clientRegistration, accessToken, idToken); new OAuth2ClientAuthenticationToken(clientRegistration, accessToken, idToken);
accessTokenAuthentication.setDetails(authorizationCodeAuthentication.getDetails()); oauth2ClientAuthentication.setDetails(authorizationCodeAuthentication.getDetails());
OAuth2User user = this.userInfoService.loadUser(accessTokenAuthentication); OAuth2User user = this.userInfoService.loadUser(oauth2ClientAuthentication);
Collection<? extends GrantedAuthority> authorities = Collection<? extends GrantedAuthority> authorities =
this.authoritiesMapper.mapAuthorities(user.getAuthorities()); this.authoritiesMapper.mapAuthorities(user.getAuthorities());
OAuth2AuthenticationToken authenticationResult = new OAuth2AuthenticationToken( OAuth2UserAuthenticationToken oauth2UserAuthentication =
user, authorities, accessTokenAuthentication.getClientRegistration(), new OAuth2UserAuthenticationToken(user, authorities, oauth2ClientAuthentication);
accessTokenAuthentication.getAccessToken(), accessTokenAuthentication.getIdToken()); oauth2UserAuthentication.setDetails(oauth2ClientAuthentication.getDetails());
authenticationResult.setDetails(accessTokenAuthentication.getDetails());
this.accessTokenRepository.saveSecurityToken(accessToken, authenticationResult); this.accessTokenRepository.saveSecurityToken(accessToken, oauth2UserAuthentication);
return authenticationResult; return oauth2UserAuthentication;
} }
public final void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) { public final void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {

View File

@ -45,7 +45,7 @@ public class AuthorizationCodeAuthenticationToken extends AuthorizationGrantAuth
@Override @Override
public Object getPrincipal() { public Object getPrincipal() {
return null; return this.getClientRegistration().getClientId();
} }
@Override @Override

View File

@ -17,68 +17,56 @@ package org.springframework.security.oauth2.client.authentication;
import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion; import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.user.OAuth2UserService;
import org.springframework.security.oauth2.core.AccessToken; import org.springframework.security.oauth2.core.AccessToken;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.oidc.core.IdToken; import org.springframework.security.oauth2.oidc.core.IdToken;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import java.util.Collection;
/** /**
* An implementation of an {@link AbstractAuthenticationToken} * An implementation of an {@link AbstractAuthenticationToken}
* that represents an <i>OAuth 2.0</i> {@link Authentication}. * that represents an <i>OAuth 2.0 Client</i> {@link Authentication}.
* *
* <p> * <p>
* It associates an {@link OAuth2User}, {@link ClientRegistration}, {@link AccessToken} and optionally an {@link IdToken}. * A client is considered <i>&quot;authenticated&quot;</i>,
* This <code>Authentication</code> is considered <i>&quot;authenticated&quot;</i> if the {@link OAuth2User} * if it receives a successful response from the <i>Token Endpoint</i>.
* is provided in the respective constructor. This typically happens after the {@link OAuth2UserService} * This {@link Authentication} associates the client identified in {@link #getClientRegistration()}
* retrieves the end-user's (resource owner) attributes from the <i>UserInfo Endpoint</i>. * to the {@link #getAccessToken()} granted by the resource owner.
* *
* @author Joe Grandja * @author Joe Grandja
* @since 5.0 * @since 5.0
* @see OAuth2User
* @see ClientRegistration * @see ClientRegistration
* @see AccessToken * @see AccessToken
* @see IdToken * @see IdToken
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-5.1">Section 5.1 Access Token Response</a>
*/ */
public class OAuth2AuthenticationToken extends AbstractAuthenticationToken { public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private final OAuth2User principal;
private final ClientRegistration clientRegistration; private final ClientRegistration clientRegistration;
private final AccessToken accessToken; private final AccessToken accessToken;
private final IdToken idToken; private final IdToken idToken;
public OAuth2AuthenticationToken(ClientRegistration clientRegistration, AccessToken accessToken, IdToken idToken) { public OAuth2ClientAuthenticationToken(ClientRegistration clientRegistration,
this(null, AuthorityUtils.NO_AUTHORITIES, clientRegistration, accessToken, idToken); AccessToken accessToken, IdToken idToken) {
}
public OAuth2AuthenticationToken(OAuth2User principal, Collection<? extends GrantedAuthority> authorities, super(AuthorityUtils.NO_AUTHORITIES);
ClientRegistration clientRegistration, AccessToken accessToken, IdToken idToken) {
super(authorities);
Assert.notNull(clientRegistration, "clientRegistration cannot be null"); Assert.notNull(clientRegistration, "clientRegistration cannot be null");
Assert.notNull(accessToken, "accessToken cannot be null"); Assert.notNull(accessToken, "accessToken cannot be null");
this.principal = principal;
this.clientRegistration = clientRegistration; this.clientRegistration = clientRegistration;
this.accessToken = accessToken; this.accessToken = accessToken;
this.idToken = idToken; this.idToken = idToken;
this.setAuthenticated(principal != null); this.setAuthenticated(true); // The Client is authenticated by the Authorization Server
} }
@Override @Override
public Object getPrincipal() { public Object getPrincipal() {
return this.principal; return this.getClientRegistration().getClientId();
} }
@Override @Override
public Object getCredentials() { public Object getCredentials() {
// Credentials are never exposed (by the Provider) for an OAuth2 User return this.getAccessToken();
return "";
} }
public ClientRegistration getClientRegistration() { public ClientRegistration getClientRegistration() {

View File

@ -0,0 +1,69 @@
/*
* Copyright 2012-2017 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
*
* http://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.
*/
package org.springframework.security.oauth2.client.authentication;
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.core.user.OAuth2User;
import org.springframework.util.Assert;
import java.util.Collection;
/**
* An implementation of an {@link AbstractAuthenticationToken}
* that represents an <i>OAuth 2.0 User</i> {@link Authentication}.
*
* <p>
* This {@link Authentication} associates an {@link OAuth2User} principal
* to an <i>&quot;Authorized Client&quot;</i> identified in {@link #getClientAuthentication()}.
*
* @author Joe Grandja
* @since 5.0
* @see OAuth2User
* @see OAuth2ClientAuthenticationToken
*/
public class OAuth2UserAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private final OAuth2User principal;
private final OAuth2ClientAuthenticationToken clientAuthentication;
public OAuth2UserAuthenticationToken(OAuth2User principal, Collection<? extends GrantedAuthority> authorities,
OAuth2ClientAuthenticationToken clientAuthentication) {
super(authorities);
Assert.notNull(principal, "principal cannot be null");
Assert.notNull(clientAuthentication, "clientAuthentication cannot be null");
this.principal = principal;
this.clientAuthentication = clientAuthentication;
this.setAuthenticated(true);
}
@Override
public Object getPrincipal() {
return this.principal;
}
@Override
public Object getCredentials() {
// Credentials are never exposed (by the Provider) for an OAuth2 User
return "";
}
public OAuth2ClientAuthenticationToken getClientAuthentication() {
return this.clientAuthentication;
}
}

View File

@ -15,7 +15,7 @@
*/ */
package org.springframework.security.oauth2.client.token; package org.springframework.security.oauth2.client.token;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.client.authentication.OAuth2UserAuthenticationToken;
import org.springframework.security.oauth2.core.AccessToken; import org.springframework.security.oauth2.core.AccessToken;
import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.oidc.core.user.OidcUser; import org.springframework.security.oauth2.oidc.core.user.OidcUser;
@ -37,25 +37,25 @@ public final class InMemoryAccessTokenRepository implements SecurityTokenReposit
private final Map<String, AccessToken> accessTokens = new HashMap<>(); private final Map<String, AccessToken> accessTokens = new HashMap<>();
@Override @Override
public AccessToken loadSecurityToken(OAuth2AuthenticationToken authentication) { public AccessToken loadSecurityToken(OAuth2UserAuthenticationToken authentication) {
Assert.notNull(authentication, "authentication cannot be null"); Assert.notNull(authentication, "authentication cannot be null");
return this.accessTokens.get(this.resolveAuthenticationKey(authentication)); return this.accessTokens.get(this.resolveAuthenticationKey(authentication));
} }
@Override @Override
public void saveSecurityToken(AccessToken accessToken, OAuth2AuthenticationToken authentication) { public void saveSecurityToken(AccessToken accessToken, OAuth2UserAuthenticationToken authentication) {
Assert.notNull(accessToken, "accessToken cannot be null"); Assert.notNull(accessToken, "accessToken cannot be null");
Assert.notNull(authentication, "authentication cannot be null"); Assert.notNull(authentication, "authentication cannot be null");
this.accessTokens.put(this.resolveAuthenticationKey(authentication), accessToken); this.accessTokens.put(this.resolveAuthenticationKey(authentication), accessToken);
} }
@Override @Override
public void removeSecurityToken(OAuth2AuthenticationToken authentication) { public void removeSecurityToken(OAuth2UserAuthenticationToken authentication) {
Assert.notNull(authentication, "authentication cannot be null"); Assert.notNull(authentication, "authentication cannot be null");
this.accessTokens.remove(this.resolveAuthenticationKey(authentication)); this.accessTokens.remove(this.resolveAuthenticationKey(authentication));
} }
private String resolveAuthenticationKey(OAuth2AuthenticationToken authentication) { private String resolveAuthenticationKey(OAuth2UserAuthenticationToken authentication) {
String authenticationKey; String authenticationKey;
OAuth2User oauth2User = (OAuth2User) authentication.getPrincipal(); OAuth2User oauth2User = (OAuth2User) authentication.getPrincipal();
@ -63,8 +63,8 @@ public final class InMemoryAccessTokenRepository implements SecurityTokenReposit
OidcUser oidcUser = (OidcUser)oauth2User; OidcUser oidcUser = (OidcUser)oauth2User;
authenticationKey = oidcUser.getIssuer().toString() + "-" + oidcUser.getSubject(); authenticationKey = oidcUser.getIssuer().toString() + "-" + oidcUser.getSubject();
} else { } else {
authenticationKey = authentication.getClientRegistration().getProviderDetails().getUserInfoUri() + authenticationKey = authentication.getClientAuthentication().getClientRegistration()
"-" + oauth2User.getName(); .getProviderDetails().getUserInfoUri() + "-" + oauth2User.getName();
} }
return authenticationKey; return authenticationKey;

View File

@ -15,22 +15,22 @@
*/ */
package org.springframework.security.oauth2.client.token; package org.springframework.security.oauth2.client.token;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.client.authentication.OAuth2UserAuthenticationToken;
import org.springframework.security.oauth2.core.SecurityToken; import org.springframework.security.oauth2.core.SecurityToken;
/** /**
* Implementations of this interface are responsible for the persistence * Implementations of this interface are responsible for the persistence
* of {@link SecurityToken}(s) that are associated to an {@link OAuth2AuthenticationToken}. * of {@link SecurityToken}(s) that are associated to an {@link OAuth2UserAuthenticationToken}.
* *
* @author Joe Grandja * @author Joe Grandja
* @since 5.0 * @since 5.0
*/ */
public interface SecurityTokenRepository<T extends SecurityToken> { public interface SecurityTokenRepository<T extends SecurityToken> {
T loadSecurityToken(OAuth2AuthenticationToken authentication); T loadSecurityToken(OAuth2UserAuthenticationToken authentication);
void saveSecurityToken(T securityToken, OAuth2AuthenticationToken authentication); void saveSecurityToken(T securityToken, OAuth2UserAuthenticationToken authentication);
void removeSecurityToken(OAuth2AuthenticationToken authentication); void removeSecurityToken(OAuth2UserAuthenticationToken authentication);
} }

View File

@ -17,7 +17,7 @@ package org.springframework.security.oauth2.client.user;
import org.springframework.security.core.AuthenticatedPrincipal; import org.springframework.security.core.AuthenticatedPrincipal;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.oidc.core.UserInfo; import org.springframework.security.oauth2.oidc.core.UserInfo;
import org.springframework.security.oauth2.oidc.core.user.OidcUser; import org.springframework.security.oauth2.oidc.core.user.OidcUser;
@ -25,12 +25,12 @@ import org.springframework.security.oauth2.oidc.core.user.OidcUser;
/** /**
* Implementations of this interface are responsible for obtaining * Implementations of this interface are responsible for obtaining
* the end-user's (resource owner) attributes from the <i>UserInfo Endpoint</i> * the end-user's (resource owner) attributes from the <i>UserInfo Endpoint</i>
* using the provided {@link OAuth2AuthenticationToken#getAccessToken()} * using the provided {@link OAuth2ClientAuthenticationToken#getAccessToken()}
* and returning an {@link AuthenticatedPrincipal} in the form of an {@link OAuth2User}. * and returning an {@link AuthenticatedPrincipal} in the form of an {@link OAuth2User}.
* *
* @author Joe Grandja * @author Joe Grandja
* @since 5.0 * @since 5.0
* @see OAuth2AuthenticationToken * @see OAuth2ClientAuthenticationToken
* @see AuthenticatedPrincipal * @see AuthenticatedPrincipal
* @see OAuth2User * @see OAuth2User
* @see OidcUser * @see OidcUser
@ -38,6 +38,6 @@ import org.springframework.security.oauth2.oidc.core.user.OidcUser;
*/ */
public interface OAuth2UserService { public interface OAuth2UserService {
OAuth2User loadUser(OAuth2AuthenticationToken token) throws OAuth2AuthenticationException; OAuth2User loadUser(OAuth2ClientAuthenticationToken token) throws OAuth2AuthenticationException;
} }

View File

@ -29,7 +29,7 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.user.OAuth2UserService; import org.springframework.security.oauth2.client.user.OAuth2UserService;
import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2Error;
@ -64,7 +64,7 @@ import java.util.Set;
* *
* @author Joe Grandja * @author Joe Grandja
* @since 5.0 * @since 5.0
* @see OAuth2AuthenticationToken * @see OAuth2ClientAuthenticationToken
* @see OAuth2User * @see OAuth2User
* @see OidcUser * @see OidcUser
* @see UserInfo * @see UserInfo
@ -80,7 +80,7 @@ public class NimbusOAuth2UserService implements OAuth2UserService {
} }
@Override @Override
public final OAuth2User loadUser(OAuth2AuthenticationToken token) throws OAuth2AuthenticationException { public final OAuth2User loadUser(OAuth2ClientAuthenticationToken token) throws OAuth2AuthenticationException {
URI userInfoUri = this.getUserInfoUri(token); URI userInfoUri = this.getUserInfoUri(token);
if (this.getCustomUserTypes().containsKey(userInfoUri)) { if (this.getCustomUserTypes().containsKey(userInfoUri)) {
@ -93,7 +93,7 @@ public class NimbusOAuth2UserService implements OAuth2UserService {
return this.loadOAuth2User(token); return this.loadOAuth2User(token);
} }
protected OAuth2User loadOidcUser(OAuth2AuthenticationToken token) throws OAuth2AuthenticationException { protected OAuth2User loadOidcUser(OAuth2ClientAuthenticationToken token) throws OAuth2AuthenticationException {
// TODO Retrieving the UserInfo should be optional. Need to add the capability for opting in/out // TODO Retrieving the UserInfo should be optional. Need to add the capability for opting in/out
Map<String, Object> userAttributes = this.getUserInfo(token); Map<String, Object> userAttributes = this.getUserInfo(token);
UserInfo userInfo = new UserInfo(userAttributes); UserInfo userInfo = new UserInfo(userAttributes);
@ -105,7 +105,7 @@ public class NimbusOAuth2UserService implements OAuth2UserService {
return new DefaultOidcUser(authorities, token.getIdToken(), userInfo); return new DefaultOidcUser(authorities, token.getIdToken(), userInfo);
} }
protected OAuth2User loadOAuth2User(OAuth2AuthenticationToken token) throws OAuth2AuthenticationException { protected OAuth2User loadOAuth2User(OAuth2ClientAuthenticationToken token) throws OAuth2AuthenticationException {
URI userInfoUri = this.getUserInfoUri(token); URI userInfoUri = this.getUserInfoUri(token);
if (!this.getUserNameAttributeNames().containsKey(userInfoUri)) { if (!this.getUserNameAttributeNames().containsKey(userInfoUri)) {
throw new IllegalArgumentException("The attribute name for the \"user's name\" is required for the OAuth2User " + throw new IllegalArgumentException("The attribute name for the \"user's name\" is required for the OAuth2User " +
@ -122,7 +122,7 @@ public class NimbusOAuth2UserService implements OAuth2UserService {
return new DefaultOAuth2User(authorities, userAttributes, userNameAttributeName); return new DefaultOAuth2User(authorities, userAttributes, userNameAttributeName);
} }
protected OAuth2User loadCustomUser(OAuth2AuthenticationToken token) throws OAuth2AuthenticationException { protected OAuth2User loadCustomUser(OAuth2ClientAuthenticationToken token) throws OAuth2AuthenticationException {
URI userInfoUri = this.getUserInfoUri(token); URI userInfoUri = this.getUserInfoUri(token);
Class<? extends OAuth2User> customUserType = this.getCustomUserTypes().get(userInfoUri); Class<? extends OAuth2User> customUserType = this.getCustomUserTypes().get(userInfoUri);
@ -146,7 +146,7 @@ public class NimbusOAuth2UserService implements OAuth2UserService {
return user; return user;
} }
protected Map<String, Object> getUserInfo(OAuth2AuthenticationToken token) throws OAuth2AuthenticationException { protected Map<String, Object> getUserInfo(OAuth2ClientAuthenticationToken token) throws OAuth2AuthenticationException {
URI userInfoUri = this.getUserInfoUri(token); URI userInfoUri = this.getUserInfoUri(token);
BearerAccessToken accessToken = new BearerAccessToken(token.getAccessToken().getTokenValue()); BearerAccessToken accessToken = new BearerAccessToken(token.getAccessToken().getTokenValue());
@ -219,7 +219,7 @@ public class NimbusOAuth2UserService implements OAuth2UserService {
this.customUserTypes = Collections.unmodifiableMap(new HashMap<>(customUserTypes)); this.customUserTypes = Collections.unmodifiableMap(new HashMap<>(customUserTypes));
} }
private URI getUserInfoUri(OAuth2AuthenticationToken token) { private URI getUserInfoUri(OAuth2ClientAuthenticationToken token) {
ClientRegistration clientRegistration = token.getClientRegistration(); ClientRegistration clientRegistration = token.getClientRegistration();
try { try {
return new URI(clientRegistration.getProviderDetails().getUserInfoUri()); return new URI(clientRegistration.getProviderDetails().getUserInfoUri());

View File

@ -21,7 +21,8 @@ import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationProvider; import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationProvider;
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken; import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.client.authentication.OAuth2UserAuthenticationToken;
import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.user.OAuth2UserService; import org.springframework.security.oauth2.client.user.OAuth2UserService;
@ -29,7 +30,11 @@ import org.springframework.security.oauth2.client.web.converter.AuthorizationCod
import org.springframework.security.oauth2.client.web.converter.ErrorResponseAttributesConverter; import org.springframework.security.oauth2.client.web.converter.ErrorResponseAttributesConverter;
import org.springframework.security.oauth2.core.AccessToken; import org.springframework.security.oauth2.core.AccessToken;
import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.endpoint.*; import org.springframework.security.oauth2.core.endpoint.AuthorizationCodeAuthorizationResponseAttributes;
import org.springframework.security.oauth2.core.endpoint.AuthorizationRequestAttributes;
import org.springframework.security.oauth2.core.endpoint.ErrorResponseAttributes;
import org.springframework.security.oauth2.core.endpoint.OAuth2Parameter;
import org.springframework.security.oauth2.core.endpoint.TokenResponseAttributes;
import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@ -70,16 +75,16 @@ import java.io.IOException;
* If the request is valid, the authorization server will respond back with a {@link TokenResponseAttributes}. * If the request is valid, the authorization server will respond back with a {@link TokenResponseAttributes}.
* </li> * </li>
* <li> * <li>
* The {@link AuthorizationCodeAuthenticationProvider} will then create a new {@link OAuth2AuthenticationToken} * The {@link AuthorizationCodeAuthenticationProvider} will then create a new {@link OAuth2ClientAuthenticationToken}
* associating the {@link AccessToken} from the {@link TokenResponseAttributes} and pass it to * associating the {@link AccessToken} from the {@link TokenResponseAttributes} and pass it to
* {@link OAuth2UserService#loadUser(OAuth2AuthenticationToken)}. The {@link OAuth2UserService} will make a request * {@link OAuth2UserService#loadUser(OAuth2ClientAuthenticationToken)}. The {@link OAuth2UserService} will make a request
* to the authorization server's <i>UserInfo Endpoint</i> (using the {@link AccessToken}) * to the authorization server's <i>UserInfo Endpoint</i> (using the {@link AccessToken})
* to obtain the end-user's (resource owner) attributes and return it in the form of an {@link OAuth2User}. * to obtain the end-user's (resource owner) attributes and return it in the form of an {@link OAuth2User}.
* </li> * </li>
* <li> * <li>
* The {@link AuthorizationCodeAuthenticationProvider} will create another new {@link OAuth2AuthenticationToken} * The {@link AuthorizationCodeAuthenticationProvider} will then create a {@link OAuth2UserAuthenticationToken}
* but this time associating the {@link AccessToken} and {@link OAuth2User} returned from the {@link OAuth2UserService}. * associating the {@link OAuth2ClientAuthenticationToken} and {@link OAuth2User} returned from the {@link OAuth2UserService}.
* Finally, the {@link OAuth2AuthenticationToken} is returned to the {@link AuthenticationManager} * Finally, the {@link OAuth2UserAuthenticationToken} is returned to the {@link AuthenticationManager}
* and then back to this <code>Filter</code> at which point the session is considered <i>&quot;authenticated&quot;</i>. * and then back to this <code>Filter</code> at which point the session is considered <i>&quot;authenticated&quot;</i>.
* </li> * </li>
* </ol> * </ol>

View File

@ -17,7 +17,7 @@ package sample.web;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.client.authentication.OAuth2UserAuthenticationToken;
import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@ -38,18 +38,18 @@ public class MainController {
@RequestMapping("/") @RequestMapping("/")
public String index(Model model, @AuthenticationPrincipal OAuth2User user, OAuth2AuthenticationToken authentication) { public String index(Model model, @AuthenticationPrincipal OAuth2User user, OAuth2UserAuthenticationToken authentication) {
model.addAttribute("userName", user.getName()); model.addAttribute("userName", user.getName());
model.addAttribute("clientName", authentication.getClientRegistration().getClientName()); model.addAttribute("clientName", authentication.getClientAuthentication().getClientRegistration().getClientName());
return "index"; return "index";
} }
@RequestMapping("/userinfo") @RequestMapping("/userinfo")
public String userinfo(Model model, OAuth2AuthenticationToken authentication) { public String userinfo(Model model, OAuth2UserAuthenticationToken authentication) {
Map userAttributes = this.webClient Map userAttributes = this.webClient
.filter(oauth2Credentials(authentication)) .filter(oauth2Credentials(authentication))
.get() .get()
.uri(authentication.getClientRegistration().getProviderDetails().getUserInfoUri()) .uri(authentication.getClientAuthentication().getClientRegistration().getProviderDetails().getUserInfoUri())
.retrieve() .retrieve()
.bodyToMono(Map.class) .bodyToMono(Map.class)
.block(); .block();
@ -57,11 +57,11 @@ public class MainController {
return "userinfo"; return "userinfo";
} }
private ExchangeFilterFunction oauth2Credentials(OAuth2AuthenticationToken authentication) { private ExchangeFilterFunction oauth2Credentials(OAuth2UserAuthenticationToken authentication) {
return ExchangeFilterFunction.ofRequestProcessor( return ExchangeFilterFunction.ofRequestProcessor(
clientRequest -> { clientRequest -> {
ClientRequest authorizedRequest = ClientRequest.from(clientRequest) ClientRequest authorizedRequest = ClientRequest.from(clientRequest)
.header(HttpHeaders.AUTHORIZATION, "Bearer " + authentication.getAccessToken().getTokenValue()) .header(HttpHeaders.AUTHORIZATION, "Bearer " + authentication.getClientAuthentication().getAccessToken().getTokenValue())
.build(); .build();
return Mono.just(authorizedRequest); return Mono.just(authorizedRequest);
}); });