mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-27 22:32:43 +00:00
Re-structure OAuth2AuthenticationToken
Fixes gh-4553
This commit is contained in:
parent
8854414101
commit
c54c622124
@ -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>"authenticated"</i>.
|
* at which point the {@link OAuth2UserAuthenticationToken} is considered <i>"authenticated"</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) {
|
||||||
|
@ -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
|
||||||
|
@ -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>"authenticated"</i>,
|
||||||
* This <code>Authentication</code> is considered <i>"authenticated"</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() {
|
@ -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>"Authorized Client"</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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
@ -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>"authenticated"</i>.
|
* and then back to this <code>Filter</code> at which point the session is considered <i>"authenticated"</i>.
|
||||||
* </li>
|
* </li>
|
||||||
* </ol>
|
* </ol>
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user