mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-31 09:12:14 +00:00
Polish oauth2-client
This commit is contained in:
parent
d4d7199a6d
commit
c441f99567
@ -991,7 +991,7 @@ public final class HttpSecurity extends
|
|||||||
* .and()
|
* .and()
|
||||||
* .oauth2Login()
|
* .oauth2Login()
|
||||||
* .clients(this.clientRegistrationRepository())
|
* .clients(this.clientRegistrationRepository())
|
||||||
* .authorizationRequestBuilder(this.authorizationRequestBuilder())
|
* .authorizationRequestUriBuilder(this.authorizationRequestUriBuilder())
|
||||||
* .authorizationCodeTokenExchanger(this.authorizationCodeTokenExchanger())
|
* .authorizationCodeTokenExchanger(this.authorizationCodeTokenExchanger())
|
||||||
* .userInfoEndpoint()
|
* .userInfoEndpoint()
|
||||||
* .userInfoService(this.userInfoService())
|
* .userInfoService(this.userInfoService())
|
||||||
@ -1008,7 +1008,7 @@ public final class HttpSecurity extends
|
|||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @Bean
|
* @Bean
|
||||||
* public AuthorizationRequestUriBuilder authorizationRequestBuilder() {
|
* public AuthorizationRequestUriBuilder authorizationRequestUriBuilder() {
|
||||||
* // Custom URI builder for the "Authorization Request"
|
* // Custom URI builder for the "Authorization Request"
|
||||||
* return new AuthorizationRequestUriBuilderImpl();
|
* return new AuthorizationRequestUriBuilderImpl();
|
||||||
* }
|
* }
|
||||||
|
@ -54,7 +54,7 @@ public class AuthorizationCodeGrantConfigurer<B extends HttpSecurityBuilder<B>>
|
|||||||
// ***** Authorization Request members
|
// ***** Authorization Request members
|
||||||
private AuthorizationRequestRedirectFilter authorizationRequestFilter;
|
private AuthorizationRequestRedirectFilter authorizationRequestFilter;
|
||||||
private String authorizationRequestBaseUri;
|
private String authorizationRequestBaseUri;
|
||||||
private AuthorizationRequestUriBuilder authorizationRequestBuilder;
|
private AuthorizationRequestUriBuilder authorizationRequestUriBuilder;
|
||||||
private AuthorizationRequestRepository authorizationRequestRepository;
|
private AuthorizationRequestRepository authorizationRequestRepository;
|
||||||
|
|
||||||
// ***** Authorization Response members
|
// ***** Authorization Response members
|
||||||
@ -71,9 +71,9 @@ public class AuthorizationCodeGrantConfigurer<B extends HttpSecurityBuilder<B>>
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuthorizationCodeGrantConfigurer<B> authorizationRequestBuilder(AuthorizationRequestUriBuilder authorizationRequestBuilder) {
|
public AuthorizationCodeGrantConfigurer<B> authorizationRequestUriBuilder(AuthorizationRequestUriBuilder authorizationRequestUriBuilder) {
|
||||||
Assert.notNull(authorizationRequestBuilder, "authorizationRequestBuilder cannot be null");
|
Assert.notNull(authorizationRequestUriBuilder, "authorizationRequestUriBuilder cannot be null");
|
||||||
this.authorizationRequestBuilder = authorizationRequestBuilder;
|
this.authorizationRequestUriBuilder = authorizationRequestUriBuilder;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,8 +134,8 @@ public class AuthorizationCodeGrantConfigurer<B extends HttpSecurityBuilder<B>>
|
|||||||
|
|
||||||
this.authorizationRequestFilter = new AuthorizationRequestRedirectFilter(
|
this.authorizationRequestFilter = new AuthorizationRequestRedirectFilter(
|
||||||
this.getAuthorizationRequestBaseUri(), this.getClientRegistrationRepository());
|
this.getAuthorizationRequestBaseUri(), this.getClientRegistrationRepository());
|
||||||
if (this.authorizationRequestBuilder != null) {
|
if (this.authorizationRequestUriBuilder != null) {
|
||||||
this.authorizationRequestFilter.setAuthorizationUriBuilder(this.authorizationRequestBuilder);
|
this.authorizationRequestFilter.setAuthorizationRequestUriBuilder(this.authorizationRequestUriBuilder);
|
||||||
}
|
}
|
||||||
if (this.authorizationRequestRepository != null) {
|
if (this.authorizationRequestRepository != null) {
|
||||||
this.authorizationRequestFilter.setAuthorizationRequestRepository(this.authorizationRequestRepository);
|
this.authorizationRequestFilter.setAuthorizationRequestRepository(this.authorizationRequestRepository);
|
||||||
|
@ -33,7 +33,7 @@ public final class ImplicitGrantConfigurer<B extends HttpSecurityBuilder<B>> ext
|
|||||||
AbstractHttpConfigurer<ImplicitGrantConfigurer<B>, B> {
|
AbstractHttpConfigurer<ImplicitGrantConfigurer<B>, B> {
|
||||||
|
|
||||||
private String authorizationRequestBaseUri;
|
private String authorizationRequestBaseUri;
|
||||||
private AuthorizationRequestUriBuilder authorizationRequestBuilder;
|
private AuthorizationRequestUriBuilder authorizationRequestUriBuilder;
|
||||||
|
|
||||||
public ImplicitGrantConfigurer<B> authorizationRequestBaseUri(String authorizationRequestBaseUri) {
|
public ImplicitGrantConfigurer<B> authorizationRequestBaseUri(String authorizationRequestBaseUri) {
|
||||||
Assert.hasText(authorizationRequestBaseUri, "authorizationRequestBaseUri cannot be empty");
|
Assert.hasText(authorizationRequestBaseUri, "authorizationRequestBaseUri cannot be empty");
|
||||||
@ -41,9 +41,9 @@ public final class ImplicitGrantConfigurer<B extends HttpSecurityBuilder<B>> ext
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImplicitGrantConfigurer<B> authorizationRequestBuilder(AuthorizationRequestUriBuilder authorizationRequestBuilder) {
|
public ImplicitGrantConfigurer<B> authorizationRequestUriBuilder(AuthorizationRequestUriBuilder authorizationRequestUriBuilder) {
|
||||||
Assert.notNull(authorizationRequestBuilder, "authorizationRequestBuilder cannot be null");
|
Assert.notNull(authorizationRequestUriBuilder, "authorizationRequestUriBuilder cannot be null");
|
||||||
this.authorizationRequestBuilder = authorizationRequestBuilder;
|
this.authorizationRequestUriBuilder = authorizationRequestUriBuilder;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,8 +57,8 @@ public final class ImplicitGrantConfigurer<B extends HttpSecurityBuilder<B>> ext
|
|||||||
public void configure(B http) throws Exception {
|
public void configure(B http) throws Exception {
|
||||||
AuthorizationRequestRedirectFilter authorizationRequestFilter = new AuthorizationRequestRedirectFilter(
|
AuthorizationRequestRedirectFilter authorizationRequestFilter = new AuthorizationRequestRedirectFilter(
|
||||||
this.getAuthorizationRequestBaseUri(), this.getClientRegistrationRepository());
|
this.getAuthorizationRequestBaseUri(), this.getClientRegistrationRepository());
|
||||||
if (this.authorizationRequestBuilder != null) {
|
if (this.authorizationRequestUriBuilder != null) {
|
||||||
authorizationRequestFilter.setAuthorizationUriBuilder(this.authorizationRequestBuilder);
|
authorizationRequestFilter.setAuthorizationRequestUriBuilder(this.authorizationRequestUriBuilder);
|
||||||
}
|
}
|
||||||
http.addFilter(this.postProcess(authorizationRequestFilter));
|
http.addFilter(this.postProcess(authorizationRequestFilter));
|
||||||
}
|
}
|
||||||
|
@ -100,9 +100,9 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> exten
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuthorizationEndpointConfig authorizationRequestBuilder(AuthorizationRequestUriBuilder authorizationRequestBuilder) {
|
public AuthorizationEndpointConfig authorizationRequestUriBuilder(AuthorizationRequestUriBuilder authorizationRequestUriBuilder) {
|
||||||
Assert.notNull(authorizationRequestBuilder, "authorizationRequestBuilder cannot be null");
|
Assert.notNull(authorizationRequestUriBuilder, "authorizationRequestUriBuilder cannot be null");
|
||||||
authorizationCodeGrantConfigurer.authorizationRequestBuilder(authorizationRequestBuilder);
|
authorizationCodeGrantConfigurer.authorizationRequestUriBuilder(authorizationRequestUriBuilder);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,14 +87,14 @@ public class AuthorizationCodeAuthenticationProvider implements AuthenticationPr
|
|||||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
OAuth2ClientAuthenticationToken oauth2ClientAuthentication =
|
OAuth2ClientAuthenticationToken clientAuthentication =
|
||||||
this.authorizationCodeAuthenticator.authenticate(authorizationCodeAuthentication);
|
this.authorizationCodeAuthenticator.authenticate(authorizationCodeAuthentication);
|
||||||
|
|
||||||
this.accessTokenRepository.saveSecurityToken(
|
this.accessTokenRepository.saveSecurityToken(
|
||||||
oauth2ClientAuthentication.getAccessToken(),
|
clientAuthentication.getAccessToken(),
|
||||||
oauth2ClientAuthentication.getClientRegistration());
|
clientAuthentication.getClientRegistration());
|
||||||
|
|
||||||
return oauth2ClientAuthentication;
|
return clientAuthentication;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setAccessTokenRepository(SecurityTokenRepository<AccessToken> accessTokenRepository) {
|
public final void setAccessTokenRepository(SecurityTokenRepository<AccessToken> accessTokenRepository) {
|
||||||
|
@ -27,6 +27,8 @@ import org.springframework.util.Assert;
|
|||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
|
* @see AuthorizationCodeAuthenticationToken
|
||||||
|
* @see AuthorizationGrantTokenExchanger
|
||||||
*/
|
*/
|
||||||
public class AuthorizationCodeAuthenticator implements AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken> {
|
public class AuthorizationCodeAuthenticator implements AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken> {
|
||||||
private final AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
|
private final AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
|
||||||
@ -46,7 +48,7 @@ public class AuthorizationCodeAuthenticator implements AuthorizationGrantAuthent
|
|||||||
// If the openid scope value is not present, the behavior is entirely unspecified.
|
// If the openid scope value is not present, the behavior is entirely unspecified.
|
||||||
if (authorizationCodeAuthentication.getAuthorizationRequest().getScope().contains("openid")) {
|
if (authorizationCodeAuthentication.getAuthorizationRequest().getScope().contains("openid")) {
|
||||||
// The OpenID Connect implementation of AuthorizationGrantAuthenticator
|
// The OpenID Connect implementation of AuthorizationGrantAuthenticator
|
||||||
// must handle OpenID Connect Authentication Requests
|
// should handle OpenID Connect Authentication Requests
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,10 +59,10 @@ public class AuthorizationCodeAuthenticator implements AuthorizationGrantAuthent
|
|||||||
tokenResponse.getTokenValue(), tokenResponse.getIssuedAt(),
|
tokenResponse.getTokenValue(), tokenResponse.getIssuedAt(),
|
||||||
tokenResponse.getExpiresAt(), tokenResponse.getScope());
|
tokenResponse.getExpiresAt(), tokenResponse.getScope());
|
||||||
|
|
||||||
OAuth2ClientAuthenticationToken oauth2ClientAuthentication =
|
OAuth2ClientAuthenticationToken clientAuthentication =
|
||||||
new OAuth2ClientAuthenticationToken(authorizationCodeAuthentication.getClientRegistration(), accessToken);
|
new OAuth2ClientAuthenticationToken(authorizationCodeAuthentication.getClientRegistration(), accessToken);
|
||||||
oauth2ClientAuthentication.setDetails(authorizationCodeAuthentication.getDetails());
|
clientAuthentication.setDetails(authorizationCodeAuthentication.getDetails());
|
||||||
|
|
||||||
return oauth2ClientAuthentication;
|
return clientAuthentication;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,28 +39,28 @@ import org.springframework.util.Assert;
|
|||||||
* @since 5.0
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
public class OAuth2AuthenticationException extends AuthenticationException {
|
public class OAuth2AuthenticationException extends AuthenticationException {
|
||||||
private OAuth2Error errorObject;
|
private OAuth2Error error;
|
||||||
|
|
||||||
public OAuth2AuthenticationException(OAuth2Error errorObject, Throwable cause) {
|
public OAuth2AuthenticationException(OAuth2Error error, Throwable cause) {
|
||||||
this(errorObject, cause.getMessage(), cause);
|
this(error, cause.getMessage(), cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OAuth2AuthenticationException(OAuth2Error errorObject, String message) {
|
public OAuth2AuthenticationException(OAuth2Error error, String message) {
|
||||||
super(message);
|
super(message);
|
||||||
this.setErrorObject(errorObject);
|
this.setError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OAuth2AuthenticationException(OAuth2Error errorObject, String message, Throwable cause) {
|
public OAuth2AuthenticationException(OAuth2Error error, String message, Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
this.setErrorObject(errorObject);
|
this.setError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OAuth2Error getErrorObject() {
|
public OAuth2Error getError() {
|
||||||
return errorObject;
|
return this.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setErrorObject(OAuth2Error errorObject) {
|
private void setError(OAuth2Error error) {
|
||||||
Assert.notNull(errorObject, "OAuth2 Error object cannot be null");
|
Assert.notNull(error, "error cannot be null");
|
||||||
this.errorObject = errorObject;
|
this.error = error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,12 @@ 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.SpringSecurityCoreVersion;
|
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||||
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.core.AccessToken;
|
import org.springframework.security.oauth2.core.AccessToken;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,7 +48,7 @@ public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken
|
|||||||
private final AccessToken accessToken;
|
private final AccessToken accessToken;
|
||||||
|
|
||||||
public OAuth2ClientAuthenticationToken(ClientRegistration clientRegistration, AccessToken accessToken) {
|
public OAuth2ClientAuthenticationToken(ClientRegistration clientRegistration, AccessToken accessToken) {
|
||||||
super(AuthorityUtils.NO_AUTHORITIES);
|
super(Collections.emptyList());
|
||||||
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.clientRegistration = clientRegistration;
|
this.clientRegistration = clientRegistration;
|
||||||
@ -63,7 +63,7 @@ public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getCredentials() {
|
public Object getCredentials() {
|
||||||
return this.getAccessToken();
|
return ""; // No need to expose this.getClientRegistration().getClientSecret()
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientRegistration getClientRegistration() {
|
public ClientRegistration getClientRegistration() {
|
||||||
@ -74,13 +74,13 @@ public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken
|
|||||||
return this.accessToken;
|
return this.accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getAuthorizedScope() {
|
public final Set<String> getAuthorizedScope() {
|
||||||
// As per spec, in section 5.1 Successful Access Token Response
|
// As per spec, in section 5.1 Successful Access Token Response
|
||||||
// https://tools.ietf.org/html/rfc6749#section-5.1
|
// https://tools.ietf.org/html/rfc6749#section-5.1
|
||||||
// If AccessToken.scope is empty, then default to the scope
|
// If AccessToken.scope is empty, then default to the scope
|
||||||
// originally requested by the client in the Authorization Request
|
// originally requested by the client in the Authorization Request
|
||||||
return (!CollectionUtils.isEmpty(this.getAccessToken().getScope()) ?
|
return (CollectionUtils.isEmpty(this.getAccessToken().getScope()) ?
|
||||||
this.getAccessToken().getScope() :
|
this.getClientRegistration().getScope() :
|
||||||
this.getClientRegistration().getScope());
|
this.getAccessToken().getScope());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,11 @@ 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.GrantedAuthority;
|
||||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
|
||||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of an {@link AbstractAuthenticationToken}
|
* An implementation of an {@link AbstractAuthenticationToken}
|
||||||
@ -44,7 +44,7 @@ public class OAuth2UserAuthenticationToken extends AbstractAuthenticationToken {
|
|||||||
private final OAuth2ClientAuthenticationToken clientAuthentication;
|
private final OAuth2ClientAuthenticationToken clientAuthentication;
|
||||||
|
|
||||||
public OAuth2UserAuthenticationToken(OAuth2ClientAuthenticationToken clientAuthentication) {
|
public OAuth2UserAuthenticationToken(OAuth2ClientAuthenticationToken clientAuthentication) {
|
||||||
this(null, AuthorityUtils.NO_AUTHORITIES, clientAuthentication);
|
this(null, Collections.emptyList(), clientAuthentication);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OAuth2UserAuthenticationToken(OAuth2User principal, Collection<? extends GrantedAuthority> authorities,
|
public OAuth2UserAuthenticationToken(OAuth2User principal, Collection<? extends GrantedAuthority> authorities,
|
||||||
|
@ -19,7 +19,7 @@ import org.springframework.security.jwt.JwtDecoder;
|
|||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A registry for {@link JwtDecoder}'s that are associated to a {@link ClientRegistration}.
|
* A registry of {@link JwtDecoder}'s that are associated to a {@link ClientRegistration}.
|
||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
|
@ -26,8 +26,8 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link JwtDecoderRegistry} that uses the <b>Nimbus JOSE + JWT SDK</b>
|
* A {@link JwtDecoderRegistry} that creates/manages instances of
|
||||||
* to create/manage instances of {@link NimbusJwtDecoderJwkSupport} internally.
|
* {@link NimbusJwtDecoderJwkSupport}, which uses the <b>Nimbus JOSE + JWT SDK</b> internally.
|
||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
|
@ -186,19 +186,19 @@ public class ClientRegistration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
protected String registrationId;
|
private String registrationId;
|
||||||
protected String clientId;
|
private String clientId;
|
||||||
protected String clientSecret;
|
private String clientSecret;
|
||||||
protected ClientAuthenticationMethod clientAuthenticationMethod = ClientAuthenticationMethod.BASIC;
|
private ClientAuthenticationMethod clientAuthenticationMethod = ClientAuthenticationMethod.BASIC;
|
||||||
protected AuthorizationGrantType authorizationGrantType;
|
private AuthorizationGrantType authorizationGrantType;
|
||||||
protected String redirectUri;
|
private String redirectUri;
|
||||||
protected Set<String> scope;
|
private Set<String> scope;
|
||||||
protected String authorizationUri;
|
private String authorizationUri;
|
||||||
protected String tokenUri;
|
private String tokenUri;
|
||||||
protected String userInfoUri;
|
private String userInfoUri;
|
||||||
protected String userNameAttributeName;
|
private String userNameAttributeName;
|
||||||
protected String jwkSetUri;
|
private String jwkSetUri;
|
||||||
protected String clientName;
|
private String clientName;
|
||||||
|
|
||||||
public Builder(String registrationId) {
|
public Builder(String registrationId) {
|
||||||
this.registrationId = registrationId;
|
this.registrationId = registrationId;
|
||||||
@ -212,7 +212,7 @@ public class ClientRegistration {
|
|||||||
this.authorizationGrantType(clientRegistrationProperties.getAuthorizationGrantType());
|
this.authorizationGrantType(clientRegistrationProperties.getAuthorizationGrantType());
|
||||||
this.redirectUri(clientRegistrationProperties.getRedirectUri());
|
this.redirectUri(clientRegistrationProperties.getRedirectUri());
|
||||||
if (!CollectionUtils.isEmpty(clientRegistrationProperties.getScope())) {
|
if (!CollectionUtils.isEmpty(clientRegistrationProperties.getScope())) {
|
||||||
this.scope(clientRegistrationProperties.getScope().stream().toArray(String[]::new));
|
this.scope(clientRegistrationProperties.getScope().toArray(new String[0]));
|
||||||
}
|
}
|
||||||
this.authorizationUri(clientRegistrationProperties.getAuthorizationUri());
|
this.authorizationUri(clientRegistrationProperties.getAuthorizationUri());
|
||||||
this.tokenUri(clientRegistrationProperties.getTokenUri());
|
this.tokenUri(clientRegistrationProperties.getTokenUri());
|
||||||
@ -230,7 +230,7 @@ public class ClientRegistration {
|
|||||||
this.authorizationGrantType(clientRegistration.getAuthorizationGrantType());
|
this.authorizationGrantType(clientRegistration.getAuthorizationGrantType());
|
||||||
this.redirectUri(clientRegistration.getRedirectUri());
|
this.redirectUri(clientRegistration.getRedirectUri());
|
||||||
if (!CollectionUtils.isEmpty(clientRegistration.getScope())) {
|
if (!CollectionUtils.isEmpty(clientRegistration.getScope())) {
|
||||||
this.scope(clientRegistration.getScope().stream().toArray(String[]::new));
|
this.scope(clientRegistration.getScope().toArray(new String[0]));
|
||||||
}
|
}
|
||||||
this.authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri());
|
this.authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri());
|
||||||
this.tokenUri(clientRegistration.getProviderDetails().getTokenUri());
|
this.tokenUri(clientRegistration.getProviderDetails().getTokenUri());
|
||||||
|
@ -28,21 +28,21 @@ import java.util.Map;
|
|||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
|
* @see ClientRegistrationRepository
|
||||||
* @see ClientRegistration
|
* @see ClientRegistration
|
||||||
*/
|
*/
|
||||||
public final class InMemoryClientRegistrationRepository implements ClientRegistrationRepository, Iterable<ClientRegistration> {
|
public final class InMemoryClientRegistrationRepository implements ClientRegistrationRepository, Iterable<ClientRegistration> {
|
||||||
private final ClientRegistrationIdentifierStrategy<String> identifierStrategy = new RegistrationIdIdentifierStrategy();
|
|
||||||
private final Map<String, ClientRegistration> registrations;
|
private final Map<String, ClientRegistration> registrations;
|
||||||
|
|
||||||
public InMemoryClientRegistrationRepository(List<ClientRegistration> registrations) {
|
public InMemoryClientRegistrationRepository(List<ClientRegistration> registrations) {
|
||||||
Assert.notEmpty(registrations, "registrations cannot be empty");
|
Assert.notEmpty(registrations, "registrations cannot be empty");
|
||||||
Map<String, ClientRegistration> registrationsMap = new HashMap<>();
|
Map<String, ClientRegistration> registrationsMap = new HashMap<>();
|
||||||
registrations.forEach(registration -> {
|
registrations.forEach(registration -> {
|
||||||
String identifier = this.identifierStrategy.getIdentifier(registration);
|
if (registrationsMap.containsKey(registration.getRegistrationId())) {
|
||||||
if (registrationsMap.containsKey(identifier)) {
|
throw new IllegalArgumentException("ClientRegistration must be unique. Found duplicate registrationId: " +
|
||||||
throw new IllegalArgumentException("ClientRegistration must be unique. Found duplicate identifier: " + identifier);
|
registration.getRegistrationId());
|
||||||
}
|
}
|
||||||
registrationsMap.put(identifier, registration);
|
registrationsMap.put(registration.getRegistrationId(), registration);
|
||||||
});
|
});
|
||||||
this.registrations = Collections.unmodifiableMap(registrationsMap);
|
this.registrations = Collections.unmodifiableMap(registrationsMap);
|
||||||
}
|
}
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.registration;
|
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link ClientRegistrationIdentifierStrategy} that identifies a {@link ClientRegistration}
|
|
||||||
* using the {@link ClientRegistration#getRegistrationId()}.
|
|
||||||
*
|
|
||||||
* @author Joe Grandja
|
|
||||||
* @since 5.0
|
|
||||||
* @see ClientRegistration
|
|
||||||
*/
|
|
||||||
public class RegistrationIdIdentifierStrategy implements ClientRegistrationIdentifierStrategy<String> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getIdentifier(ClientRegistration clientRegistration) {
|
|
||||||
Assert.notNull(clientRegistration, "clientRegistration cannot be null");
|
|
||||||
return clientRegistration.getRegistrationId();
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,8 +20,7 @@ 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
|
||||||
* and association of an OAuth 2.0 / OpenID Connect 1.0
|
* and association of a {@link SecurityToken} to a {@link ClientRegistration Client}.
|
||||||
* {@link SecurityToken} to a {@link ClientRegistration Client}.
|
|
||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
|
@ -58,7 +58,7 @@ public class CustomUserTypesOAuth2UserService implements OAuth2UserService {
|
|||||||
public OAuth2User loadUser(OAuth2ClientAuthenticationToken clientAuthentication) throws OAuth2AuthenticationException {
|
public OAuth2User loadUser(OAuth2ClientAuthenticationToken clientAuthentication) throws OAuth2AuthenticationException {
|
||||||
URI userInfoUri = URI.create(clientAuthentication.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri());
|
URI userInfoUri = URI.create(clientAuthentication.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri());
|
||||||
Class<? extends OAuth2User> customUserType;
|
Class<? extends OAuth2User> customUserType;
|
||||||
if ((customUserType = this.getCustomUserTypes().get(userInfoUri)) == null) {
|
if ((customUserType = this.customUserTypes.get(userInfoUri)) == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,14 +82,6 @@ public class CustomUserTypesOAuth2UserService implements OAuth2UserService {
|
|||||||
return customUser;
|
return customUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<URI, Class<? extends OAuth2User>> getCustomUserTypes() {
|
|
||||||
return this.customUserTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UserInfoRetriever getUserInfoRetriever() {
|
|
||||||
return this.userInfoRetriever;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void setUserInfoRetriever(UserInfoRetriever userInfoRetriever) {
|
public final void setUserInfoRetriever(UserInfoRetriever userInfoRetriever) {
|
||||||
Assert.notNull(userInfoRetriever, "userInfoRetriever cannot be null");
|
Assert.notNull(userInfoRetriever, "userInfoRetriever cannot be null");
|
||||||
this.userInfoRetriever = userInfoRetriever;
|
this.userInfoRetriever = userInfoRetriever;
|
||||||
|
@ -53,9 +53,6 @@ import java.util.Set;
|
|||||||
public class DefaultOAuth2UserService implements OAuth2UserService {
|
public class DefaultOAuth2UserService implements OAuth2UserService {
|
||||||
private UserInfoRetriever userInfoRetriever = new NimbusUserInfoRetriever();
|
private UserInfoRetriever userInfoRetriever = new NimbusUserInfoRetriever();
|
||||||
|
|
||||||
public DefaultOAuth2UserService() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2User loadUser(OAuth2ClientAuthenticationToken clientAuthentication) throws OAuth2AuthenticationException {
|
public OAuth2User loadUser(OAuth2ClientAuthenticationToken clientAuthentication) throws OAuth2AuthenticationException {
|
||||||
if (OidcClientAuthenticationToken.class.isAssignableFrom(clientAuthentication.getClass())) {
|
if (OidcClientAuthenticationToken.class.isAssignableFrom(clientAuthentication.getClass())) {
|
||||||
@ -69,7 +66,7 @@ public class DefaultOAuth2UserService implements OAuth2UserService {
|
|||||||
clientAuthentication.getClientRegistration().getRegistrationId());
|
clientAuthentication.getClientRegistration().getRegistrationId());
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> userAttributes = this.getUserInfoRetriever().retrieve(clientAuthentication);
|
Map<String, Object> userAttributes = this.userInfoRetriever.retrieve(clientAuthentication);
|
||||||
GrantedAuthority authority = new OAuth2UserAuthority(userAttributes);
|
GrantedAuthority authority = new OAuth2UserAuthority(userAttributes);
|
||||||
Set<GrantedAuthority> authorities = new HashSet<>();
|
Set<GrantedAuthority> authorities = new HashSet<>();
|
||||||
authorities.add(authority);
|
authorities.add(authority);
|
||||||
@ -77,10 +74,6 @@ public class DefaultOAuth2UserService implements OAuth2UserService {
|
|||||||
return new DefaultOAuth2User(authorities, userAttributes, userNameAttributeName);
|
return new DefaultOAuth2User(authorities, userAttributes, userNameAttributeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected UserInfoRetriever getUserInfoRetriever() {
|
|
||||||
return this.userInfoRetriever;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void setUserInfoRetriever(UserInfoRetriever userInfoRetriever) {
|
public final void setUserInfoRetriever(UserInfoRetriever userInfoRetriever) {
|
||||||
Assert.notNull(userInfoRetriever, "userInfoRetriever cannot be null");
|
Assert.notNull(userInfoRetriever, "userInfoRetriever cannot be null");
|
||||||
this.userInfoRetriever = userInfoRetriever;
|
this.userInfoRetriever = userInfoRetriever;
|
||||||
|
@ -37,17 +37,17 @@ import java.util.Objects;
|
|||||||
* @see OAuth2User
|
* @see OAuth2User
|
||||||
*/
|
*/
|
||||||
public class DelegatingOAuth2UserService implements OAuth2UserService {
|
public class DelegatingOAuth2UserService implements OAuth2UserService {
|
||||||
private final List<OAuth2UserService> oauth2UserServices;
|
private final List<OAuth2UserService> userServices;
|
||||||
|
|
||||||
public DelegatingOAuth2UserService(List<OAuth2UserService> oauth2UserServices) {
|
public DelegatingOAuth2UserService(List<OAuth2UserService> userServices) {
|
||||||
Assert.notEmpty(oauth2UserServices, "oauth2UserServices cannot be empty");
|
Assert.notEmpty(userServices, "userServices cannot be empty");
|
||||||
this.oauth2UserServices = oauth2UserServices;
|
this.userServices = userServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2User loadUser(OAuth2ClientAuthenticationToken clientAuthentication) throws OAuth2AuthenticationException {
|
public OAuth2User loadUser(OAuth2ClientAuthenticationToken clientAuthentication) throws OAuth2AuthenticationException {
|
||||||
OAuth2User oauth2User = this.oauth2UserServices.stream()
|
OAuth2User oauth2User = this.userServices.stream()
|
||||||
.map(oauth2UserService -> oauth2UserService.loadUser(clientAuthentication))
|
.map(userService -> userService.loadUser(clientAuthentication))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.user.nimbus;
|
|
||||||
|
|
||||||
import com.nimbusds.oauth2.sdk.http.HTTPResponse;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.client.AbstractClientHttpResponse;
|
|
||||||
import org.springframework.http.client.ClientHttpResponse;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An implementation of a {@link ClientHttpResponse} which is used by {@link NimbusUserInfoRetriever}.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* <b>NOTE:</b> This class is intended for internal use only.
|
|
||||||
*
|
|
||||||
* @author Joe Grandja
|
|
||||||
* @since 5.0
|
|
||||||
*/
|
|
||||||
final class NimbusClientHttpResponse extends AbstractClientHttpResponse {
|
|
||||||
private final HTTPResponse httpResponse;
|
|
||||||
private final HttpHeaders headers;
|
|
||||||
|
|
||||||
NimbusClientHttpResponse(HTTPResponse httpResponse) {
|
|
||||||
Assert.notNull(httpResponse, "httpResponse cannot be null");
|
|
||||||
this.httpResponse = httpResponse;
|
|
||||||
this.headers = new HttpHeaders();
|
|
||||||
this.headers.setAll(httpResponse.getHeaders());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getRawStatusCode() throws IOException {
|
|
||||||
return this.httpResponse.getStatusCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getStatusText() throws IOException {
|
|
||||||
return String.valueOf(this.getRawStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getBody() throws IOException {
|
|
||||||
InputStream inputStream = new ByteArrayInputStream(
|
|
||||||
this.httpResponse.getContent().getBytes(Charset.forName("UTF-8")));
|
|
||||||
return inputStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HttpHeaders getHeaders() {
|
|
||||||
return this.headers;
|
|
||||||
}
|
|
||||||
}
|
|
@ -22,6 +22,8 @@ import com.nimbusds.oauth2.sdk.http.HTTPResponse;
|
|||||||
import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
|
import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
|
||||||
import com.nimbusds.openid.connect.sdk.UserInfoErrorResponse;
|
import com.nimbusds.openid.connect.sdk.UserInfoErrorResponse;
|
||||||
import com.nimbusds.openid.connect.sdk.UserInfoRequest;
|
import com.nimbusds.openid.connect.sdk.UserInfoRequest;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.client.AbstractClientHttpResponse;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
@ -29,9 +31,13 @@ import org.springframework.security.oauth2.client.authentication.OAuth2Authentic
|
|||||||
import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
|
import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
|
||||||
import org.springframework.security.oauth2.client.user.UserInfoRetriever;
|
import org.springframework.security.oauth2.client.user.UserInfoRetriever;
|
||||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,4 +106,42 @@ public class NimbusUserInfoRetriever implements UserInfoRetriever {
|
|||||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex);
|
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class NimbusClientHttpResponse extends AbstractClientHttpResponse {
|
||||||
|
private final HTTPResponse httpResponse;
|
||||||
|
private final HttpHeaders headers;
|
||||||
|
|
||||||
|
private NimbusClientHttpResponse(HTTPResponse httpResponse) {
|
||||||
|
Assert.notNull(httpResponse, "httpResponse cannot be null");
|
||||||
|
this.httpResponse = httpResponse;
|
||||||
|
this.headers = new HttpHeaders();
|
||||||
|
this.headers.setAll(httpResponse.getHeaders());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRawStatusCode() throws IOException {
|
||||||
|
return this.httpResponse.getStatusCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStatusText() throws IOException {
|
||||||
|
return String.valueOf(this.getRawStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getBody() throws IOException {
|
||||||
|
InputStream inputStream = new ByteArrayInputStream(
|
||||||
|
this.httpResponse.getContent().getBytes(Charset.forName("UTF-8")));
|
||||||
|
return inputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpHeaders getHeaders() {
|
||||||
|
return this.headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,9 +65,10 @@ import java.io.IOException;
|
|||||||
* @see AbstractAuthenticationProcessingFilter
|
* @see AbstractAuthenticationProcessingFilter
|
||||||
* @see AuthorizationCodeAuthenticationToken
|
* @see AuthorizationCodeAuthenticationToken
|
||||||
* @see AuthorizationCodeAuthenticationProvider
|
* @see AuthorizationCodeAuthenticationProvider
|
||||||
* @see AuthorizationRequestRedirectFilter
|
* @see AuthorizationResponse
|
||||||
* @see AuthorizationRequest
|
* @see AuthorizationRequest
|
||||||
* @see AuthorizationRequestRepository
|
* @see AuthorizationRequestRepository
|
||||||
|
* @see AuthorizationRequestRedirectFilter
|
||||||
* @see ClientRegistrationRepository
|
* @see ClientRegistrationRepository
|
||||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">Section 4.1 Authorization Code Grant</a>
|
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">Section 4.1 Authorization Code Grant</a>
|
||||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.2">Section 4.1.2 Authorization Response</a>
|
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.2">Section 4.1.2 Authorization Response</a>
|
||||||
@ -125,11 +126,11 @@ public class AuthorizationCodeAuthenticationFilter extends AbstractAuthenticatio
|
|||||||
clientRegistration, authorizationRequest, authorizationResponse);
|
clientRegistration, authorizationRequest, authorizationResponse);
|
||||||
authorizationCodeAuthentication.setDetails(this.authenticationDetailsSource.buildDetails(request));
|
authorizationCodeAuthentication.setDetails(this.authenticationDetailsSource.buildDetails(request));
|
||||||
|
|
||||||
OAuth2ClientAuthenticationToken oauth2ClientAuthentication =
|
OAuth2ClientAuthenticationToken clientAuthentication =
|
||||||
(OAuth2ClientAuthenticationToken)this.getAuthenticationManager().authenticate(authorizationCodeAuthentication);
|
(OAuth2ClientAuthenticationToken)this.getAuthenticationManager().authenticate(authorizationCodeAuthentication);
|
||||||
|
|
||||||
return this.getAuthenticationManager().authenticate(
|
return this.getAuthenticationManager().authenticate(
|
||||||
new OAuth2UserAuthenticationToken(oauth2ClientAuthentication));
|
new OAuth2UserAuthenticationToken(clientAuthentication));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final RequestMatcher getAuthorizationResponseMatcher() {
|
public final RequestMatcher getAuthorizationResponseMatcher() {
|
||||||
@ -192,12 +193,12 @@ public class AuthorizationCodeAuthenticationFilter extends AbstractAuthenticatio
|
|||||||
.state(state)
|
.state(state)
|
||||||
.build();
|
.build();
|
||||||
} else {
|
} else {
|
||||||
String description = request.getParameter(OAuth2Parameter.ERROR_DESCRIPTION);
|
String errorDescription = request.getParameter(OAuth2Parameter.ERROR_DESCRIPTION);
|
||||||
String uri = request.getParameter(OAuth2Parameter.ERROR_URI);
|
String errorUri = request.getParameter(OAuth2Parameter.ERROR_URI);
|
||||||
return AuthorizationResponse.error(errorCode)
|
return AuthorizationResponse.error(errorCode)
|
||||||
.redirectUri(redirectUri)
|
.redirectUri(redirectUri)
|
||||||
.errorDescription(description)
|
.errorDescription(errorDescription)
|
||||||
.errorUri(uri)
|
.errorUri(errorUri)
|
||||||
.state(state)
|
.state(state)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
@ -64,10 +64,10 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class AuthorizationRequestRedirectFilter extends OncePerRequestFilter {
|
public class AuthorizationRequestRedirectFilter extends OncePerRequestFilter {
|
||||||
public static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization";
|
public static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization";
|
||||||
public static final String REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId";
|
private static final String REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId";
|
||||||
private final AntPathRequestMatcher authorizationRequestMatcher;
|
private final AntPathRequestMatcher authorizationRequestMatcher;
|
||||||
private final ClientRegistrationRepository clientRegistrationRepository;
|
private final ClientRegistrationRepository clientRegistrationRepository;
|
||||||
private AuthorizationRequestUriBuilder authorizationUriBuilder = new DefaultAuthorizationRequestUriBuilder();
|
private AuthorizationRequestUriBuilder authorizationRequestUriBuilder = new DefaultAuthorizationRequestUriBuilder();
|
||||||
private final RedirectStrategy authorizationRedirectStrategy = new DefaultRedirectStrategy();
|
private final RedirectStrategy authorizationRedirectStrategy = new DefaultRedirectStrategy();
|
||||||
private final StringKeyGenerator stateGenerator = new DefaultStateGenerator();
|
private final StringKeyGenerator stateGenerator = new DefaultStateGenerator();
|
||||||
private AuthorizationRequestRepository authorizationRequestRepository = new HttpSessionAuthorizationRequestRepository();
|
private AuthorizationRequestRepository authorizationRequestRepository = new HttpSessionAuthorizationRequestRepository();
|
||||||
@ -86,9 +86,9 @@ public class AuthorizationRequestRedirectFilter extends OncePerRequestFilter {
|
|||||||
this.clientRegistrationRepository = clientRegistrationRepository;
|
this.clientRegistrationRepository = clientRegistrationRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setAuthorizationUriBuilder(AuthorizationRequestUriBuilder authorizationUriBuilder) {
|
public final void setAuthorizationRequestUriBuilder(AuthorizationRequestUriBuilder authorizationRequestUriBuilder) {
|
||||||
Assert.notNull(authorizationUriBuilder, "authorizationUriBuilder cannot be null");
|
Assert.notNull(authorizationRequestUriBuilder, "authorizationRequestUriBuilder cannot be null");
|
||||||
this.authorizationUriBuilder = authorizationUriBuilder;
|
this.authorizationRequestUriBuilder = authorizationRequestUriBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setAuthorizationRequestRepository(AuthorizationRequestRepository authorizationRequestRepository) {
|
public final void setAuthorizationRequestRepository(AuthorizationRequestRepository authorizationRequestRepository) {
|
||||||
@ -112,18 +112,18 @@ public class AuthorizationRequestRedirectFilter extends OncePerRequestFilter {
|
|||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean shouldRequestAuthorization(HttpServletRequest request, HttpServletResponse response) {
|
private boolean shouldRequestAuthorization(HttpServletRequest request, HttpServletResponse response) {
|
||||||
return this.authorizationRequestMatcher.matches(request);
|
return this.authorizationRequestMatcher.matches(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void sendRedirectForAuthorization(HttpServletRequest request, HttpServletResponse response)
|
private void sendRedirectForAuthorization(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
|
|
||||||
String registrationId = this.authorizationRequestMatcher
|
String registrationId = this.authorizationRequestMatcher
|
||||||
.extractUriTemplateVariables(request).get(REGISTRATION_ID_URI_VARIABLE_NAME);
|
.extractUriTemplateVariables(request).get(REGISTRATION_ID_URI_VARIABLE_NAME);
|
||||||
ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
|
ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
|
||||||
if (clientRegistration == null) {
|
if (clientRegistration == null) {
|
||||||
throw new IllegalArgumentException("Invalid Client Identifier (Registration Id): " + registrationId);
|
throw new IllegalArgumentException("Invalid Client Registration with Id: " + registrationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
String redirectUriStr = this.expandRedirectUri(request, clientRegistration);
|
String redirectUriStr = this.expandRedirectUri(request, clientRegistration);
|
||||||
@ -153,11 +153,11 @@ public class AuthorizationRequestRedirectFilter extends OncePerRequestFilter {
|
|||||||
this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, request, response);
|
this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
URI redirectUri = this.authorizationUriBuilder.build(authorizationRequest);
|
URI redirectUri = this.authorizationRequestUriBuilder.build(authorizationRequest);
|
||||||
this.authorizationRedirectStrategy.sendRedirect(request, response, redirectUri.toString());
|
this.authorizationRedirectStrategy.sendRedirect(request, response, redirectUri.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void unsuccessfulRedirectForAuthorization(HttpServletRequest request, HttpServletResponse response,
|
private void unsuccessfulRedirectForAuthorization(HttpServletRequest request, HttpServletResponse response,
|
||||||
Exception failed) throws IOException, ServletException {
|
Exception failed) throws IOException, ServletException {
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
|
@ -27,8 +27,8 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
* <p>
|
* <p>
|
||||||
* Used by the {@link AuthorizationRequestRedirectFilter} for persisting the <i>Authorization Request</i>
|
* Used by the {@link AuthorizationRequestRedirectFilter} for persisting the <i>Authorization Request</i>
|
||||||
* before it initiates the authorization code grant flow.
|
* before it initiates the authorization code grant flow.
|
||||||
* As well, used by the {@link AuthorizationCodeAuthenticationFilter} when resolving
|
* As well, used by the {@link AuthorizationCodeAuthenticationFilter} for resolving
|
||||||
* the associated <i>Authorization Request</i> during the handling of the <i>Authorization Response</i>.
|
* the associated <i>Authorization Request</i> when handling the <i>Authorization Response</i>.
|
||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
@ -42,6 +42,6 @@ public interface AuthorizationRequestRepository {
|
|||||||
void saveAuthorizationRequest(AuthorizationRequest authorizationRequest, HttpServletRequest request,
|
void saveAuthorizationRequest(AuthorizationRequest authorizationRequest, HttpServletRequest request,
|
||||||
HttpServletResponse response);
|
HttpServletResponse response);
|
||||||
|
|
||||||
AuthorizationRequest removeAuthorizationRequest(HttpServletRequest request);
|
void removeAuthorizationRequest(HttpServletRequest request);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The default implementation of an {@link AuthorizationRequestUriBuilder},
|
* The default implementation of an {@link AuthorizationRequestUriBuilder},
|
||||||
* which internally uses an {@link UriComponentsBuilder} to construct the <i>OAuth 2.0 Authorization Request</i>.
|
* which internally uses a {@link UriComponentsBuilder} to construct the <i>OAuth 2.0 Authorization Request</i>.
|
||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
|
@ -15,16 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.security.oauth2.client.web;
|
package org.springframework.security.oauth2.client.web;
|
||||||
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
import org.springframework.security.crypto.keygen.BytesKeyGenerator;
|
import org.springframework.security.crypto.keygen.BytesKeyGenerator;
|
||||||
import org.springframework.security.crypto.keygen.KeyGenerators;
|
import org.springframework.security.crypto.keygen.KeyGenerators;
|
||||||
import org.springframework.security.crypto.keygen.StringKeyGenerator;
|
import org.springframework.security.crypto.keygen.StringKeyGenerator;
|
||||||
|
import org.springframework.security.oauth2.core.endpoint.OAuth2Parameter;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default implementation for generating the
|
* The default implementation for generating the {@link OAuth2Parameter#STATE} parameter
|
||||||
* {@link org.springframework.security.oauth2.core.endpoint.OAuth2Parameter#STATE} parameter
|
|
||||||
* used in the <i>Authorization Request</i> and correlated in the <i>Authorization Response</i> (or <i>Error Response</i>).
|
* used in the <i>Authorization Request</i> and correlated in the <i>Authorization Response</i> (or <i>Error Response</i>).
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
@ -36,16 +36,16 @@ import org.springframework.util.Assert;
|
|||||||
* @since 5.0
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
public class DefaultStateGenerator implements StringKeyGenerator {
|
public class DefaultStateGenerator implements StringKeyGenerator {
|
||||||
private static final int DEFAULT_BYTE_LENGTH = 32;
|
private static final int DEFAULT_KEY_LENGTH = 32;
|
||||||
private final BytesKeyGenerator keyGenerator;
|
private final BytesKeyGenerator keyGenerator;
|
||||||
|
|
||||||
public DefaultStateGenerator() {
|
public DefaultStateGenerator() {
|
||||||
this(DEFAULT_BYTE_LENGTH);
|
this(DEFAULT_KEY_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultStateGenerator(int byteLength) {
|
public DefaultStateGenerator(int keyLength) {
|
||||||
Assert.isTrue(byteLength > 0, "byteLength must be greater than 0");
|
Assert.isTrue(keyLength >= DEFAULT_KEY_LENGTH, "keyLength must be greater than " + DEFAULT_KEY_LENGTH);
|
||||||
this.keyGenerator = KeyGenerators.secureRandom(byteLength);
|
this.keyGenerator = KeyGenerators.secureRandom(keyLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -32,16 +32,15 @@ import javax.servlet.http.HttpSession;
|
|||||||
public final class HttpSessionAuthorizationRequestRepository implements AuthorizationRequestRepository {
|
public final class HttpSessionAuthorizationRequestRepository implements AuthorizationRequestRepository {
|
||||||
private static final String DEFAULT_AUTHORIZATION_REQUEST_ATTR_NAME =
|
private static final String DEFAULT_AUTHORIZATION_REQUEST_ATTR_NAME =
|
||||||
HttpSessionAuthorizationRequestRepository.class.getName() + ".AUTHORIZATION_REQUEST";
|
HttpSessionAuthorizationRequestRepository.class.getName() + ".AUTHORIZATION_REQUEST";
|
||||||
private String sessionAttributeName = DEFAULT_AUTHORIZATION_REQUEST_ATTR_NAME;
|
private final String sessionAttributeName = DEFAULT_AUTHORIZATION_REQUEST_ATTR_NAME;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthorizationRequest loadAuthorizationRequest(HttpServletRequest request) {
|
public AuthorizationRequest loadAuthorizationRequest(HttpServletRequest request) {
|
||||||
AuthorizationRequest authorizationRequest = null;
|
|
||||||
HttpSession session = request.getSession(false);
|
HttpSession session = request.getSession(false);
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
authorizationRequest = (AuthorizationRequest) session.getAttribute(this.sessionAttributeName);
|
return (AuthorizationRequest) session.getAttribute(this.sessionAttributeName);
|
||||||
}
|
}
|
||||||
return authorizationRequest;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -55,11 +54,7 @@ public final class HttpSessionAuthorizationRequestRepository implements Authoriz
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthorizationRequest removeAuthorizationRequest(HttpServletRequest request) {
|
public void removeAuthorizationRequest(HttpServletRequest request) {
|
||||||
AuthorizationRequest authorizationRequest = this.loadAuthorizationRequest(request);
|
request.getSession().removeAttribute(this.sessionAttributeName);
|
||||||
if (authorizationRequest != null) {
|
|
||||||
request.getSession().removeAttribute(this.sessionAttributeName);
|
|
||||||
}
|
|
||||||
return authorizationRequest;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,9 @@ import com.nimbusds.oauth2.sdk.id.ClientID;
|
|||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken;
|
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken;
|
||||||
import org.springframework.security.oauth2.client.web.AuthorizationGrantTokenExchanger;
|
|
||||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
|
import org.springframework.security.oauth2.client.web.AuthorizationGrantTokenExchanger;
|
||||||
import org.springframework.security.oauth2.core.AccessToken;
|
import org.springframework.security.oauth2.core.AccessToken;
|
||||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
@ -45,10 +45,10 @@ import org.springframework.util.CollectionUtils;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of an {@link AuthorizationGrantTokenExchanger} that <i>"exchanges"</i>
|
* An implementation of an {@link AuthorizationGrantTokenExchanger} that <i>"exchanges"</i>
|
||||||
@ -60,6 +60,7 @@ import java.util.stream.Collectors;
|
|||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
|
* @see AuthorizationGrantTokenExchanger
|
||||||
* @see AuthorizationCodeAuthenticationToken
|
* @see AuthorizationCodeAuthenticationToken
|
||||||
* @see TokenResponse
|
* @see TokenResponse
|
||||||
* @see <a target="_blank" href="https://connect2id.com/products/nimbus-oauth-openid-connect-sdk">Nimbus OAuth 2.0 SDK</a>
|
* @see <a target="_blank" href="https://connect2id.com/products/nimbus-oauth-openid-connect-sdk">Nimbus OAuth 2.0 SDK</a>
|
||||||
@ -70,17 +71,17 @@ public class NimbusAuthorizationCodeTokenExchanger implements AuthorizationGrant
|
|||||||
private static final String INVALID_TOKEN_RESPONSE_ERROR_CODE = "invalid_token_response";
|
private static final String INVALID_TOKEN_RESPONSE_ERROR_CODE = "invalid_token_response";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TokenResponse exchange(AuthorizationCodeAuthenticationToken authorizationCodeAuthenticationToken)
|
public TokenResponse exchange(AuthorizationCodeAuthenticationToken authorizationCodeAuthentication)
|
||||||
throws OAuth2AuthenticationException {
|
throws OAuth2AuthenticationException {
|
||||||
|
|
||||||
ClientRegistration clientRegistration = authorizationCodeAuthenticationToken.getClientRegistration();
|
ClientRegistration clientRegistration = authorizationCodeAuthentication.getClientRegistration();
|
||||||
|
|
||||||
// Build the authorization code grant request for the token endpoint
|
// Build the authorization code grant request for the token endpoint
|
||||||
AuthorizationCode authorizationCode = new AuthorizationCode(
|
AuthorizationCode authorizationCode = new AuthorizationCode(
|
||||||
authorizationCodeAuthenticationToken.getAuthorizationResponse().getCode());
|
authorizationCodeAuthentication.getAuthorizationResponse().getCode());
|
||||||
URI redirectUri = this.toURI(clientRegistration.getRedirectUri());
|
URI redirectUri = toURI(clientRegistration.getRedirectUri());
|
||||||
AuthorizationGrant authorizationCodeGrant = new AuthorizationCodeGrant(authorizationCode, redirectUri);
|
AuthorizationGrant authorizationCodeGrant = new AuthorizationCodeGrant(authorizationCode, redirectUri);
|
||||||
URI tokenUri = this.toURI(clientRegistration.getProviderDetails().getTokenUri());
|
URI tokenUri = toURI(clientRegistration.getProviderDetails().getTokenUri());
|
||||||
|
|
||||||
// Set the credentials to authenticate the client at the token endpoint
|
// Set the credentials to authenticate the client at the token endpoint
|
||||||
ClientID clientId = new ClientID(clientRegistration.getClientId());
|
ClientID clientId = new ClientID(clientRegistration.getClientId());
|
||||||
@ -102,11 +103,8 @@ public class NimbusAuthorizationCodeTokenExchanger implements AuthorizationGrant
|
|||||||
httpRequest.setReadTimeout(30000);
|
httpRequest.setReadTimeout(30000);
|
||||||
tokenResponse = com.nimbusds.oauth2.sdk.TokenResponse.parse(httpRequest.send());
|
tokenResponse = com.nimbusds.oauth2.sdk.TokenResponse.parse(httpRequest.send());
|
||||||
} catch (ParseException pe) {
|
} catch (ParseException pe) {
|
||||||
// This error occurs if the Access Token Response is not well-formed,
|
|
||||||
// for example, a required attribute is missing
|
|
||||||
throw new OAuth2AuthenticationException(new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE), pe);
|
throw new OAuth2AuthenticationException(new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE), pe);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
// This error occurs when there is a network-related issue
|
|
||||||
throw new AuthenticationServiceException("An error occurred while sending the Access Token Request: " +
|
throw new AuthenticationServiceException("An error occurred while sending the Access Token Request: " +
|
||||||
ioe.getMessage(), ioe);
|
ioe.getMessage(), ioe);
|
||||||
}
|
}
|
||||||
@ -129,10 +127,9 @@ public class NimbusAuthorizationCodeTokenExchanger implements AuthorizationGrant
|
|||||||
long expiresIn = accessTokenResponse.getTokens().getAccessToken().getLifetime();
|
long expiresIn = accessTokenResponse.getTokens().getAccessToken().getLifetime();
|
||||||
Set<String> scope = Collections.emptySet();
|
Set<String> scope = Collections.emptySet();
|
||||||
if (!CollectionUtils.isEmpty(accessTokenResponse.getTokens().getAccessToken().getScope())) {
|
if (!CollectionUtils.isEmpty(accessTokenResponse.getTokens().getAccessToken().getScope())) {
|
||||||
scope = new HashSet<>(accessTokenResponse.getTokens().getAccessToken().getScope().toStringList());
|
scope = new LinkedHashSet<>(accessTokenResponse.getTokens().getAccessToken().getScope().toStringList());
|
||||||
}
|
}
|
||||||
Map<String, Object> additionalParameters = accessTokenResponse.getCustomParameters().entrySet().stream()
|
Map<String, Object> additionalParameters = new LinkedHashMap<>(accessTokenResponse.getCustomParameters());
|
||||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
|
||||||
|
|
||||||
return TokenResponse.withToken(accessToken)
|
return TokenResponse.withToken(accessToken)
|
||||||
.tokenType(accessTokenType)
|
.tokenType(accessTokenType)
|
||||||
@ -142,7 +139,7 @@ public class NimbusAuthorizationCodeTokenExchanger implements AuthorizationGrant
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private URI toURI(String uriStr) {
|
private static URI toURI(String uriStr) {
|
||||||
try {
|
try {
|
||||||
return new URI(uriStr);
|
return new URI(uriStr);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
@ -27,6 +27,7 @@ import org.springframework.security.oauth2.client.web.AuthorizationGrantTokenExc
|
|||||||
import org.springframework.security.oauth2.core.AccessToken;
|
import org.springframework.security.oauth2.core.AccessToken;
|
||||||
import org.springframework.security.oauth2.core.endpoint.TokenResponse;
|
import org.springframework.security.oauth2.core.endpoint.TokenResponse;
|
||||||
import org.springframework.security.oauth2.oidc.core.IdToken;
|
import org.springframework.security.oauth2.oidc.core.IdToken;
|
||||||
|
import org.springframework.security.oauth2.oidc.core.OidcScope;
|
||||||
import org.springframework.security.oauth2.oidc.core.endpoint.OidcParameter;
|
import org.springframework.security.oauth2.oidc.core.endpoint.OidcParameter;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@ -37,6 +38,10 @@ import org.springframework.util.Assert;
|
|||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
|
* @see AuthorizationGrantAuthenticator
|
||||||
|
* @see AuthorizationCodeAuthenticationToken
|
||||||
|
* @see AuthorizationGrantTokenExchanger
|
||||||
|
* @see JwtDecoderRegistry
|
||||||
*/
|
*/
|
||||||
public class OidcAuthorizationCodeAuthenticator implements AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken> {
|
public class OidcAuthorizationCodeAuthenticator implements AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken> {
|
||||||
private final AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
|
private final AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
|
||||||
@ -60,7 +65,7 @@ public class OidcAuthorizationCodeAuthenticator implements AuthorizationGrantAut
|
|||||||
// scope
|
// scope
|
||||||
// REQUIRED. OpenID Connect requests MUST contain the "openid" scope value.
|
// REQUIRED. OpenID Connect requests MUST contain the "openid" scope value.
|
||||||
// If the openid scope value is not present, the behavior is entirely unspecified.
|
// If the openid scope value is not present, the behavior is entirely unspecified.
|
||||||
if (!authorizationCodeAuthentication.getAuthorizationRequest().getScope().contains("openid")) {
|
if (!authorizationCodeAuthentication.getAuthorizationRequest().getScope().contains(OidcScope.OPENID)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,21 +80,21 @@ public class OidcAuthorizationCodeAuthenticator implements AuthorizationGrantAut
|
|||||||
|
|
||||||
if (!tokenResponse.getAdditionalParameters().containsKey(OidcParameter.ID_TOKEN)) {
|
if (!tokenResponse.getAdditionalParameters().containsKey(OidcParameter.ID_TOKEN)) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Missing (required) ID Token in Token Response for Client Registration: '" + clientRegistration.getRegistrationId() + "'");
|
"Missing (required) ID Token in Token Response for Client Registration: " + clientRegistration.getRegistrationId());
|
||||||
}
|
}
|
||||||
|
|
||||||
JwtDecoder jwtDecoder = this.jwtDecoderRegistry.getJwtDecoder(clientRegistration);
|
JwtDecoder jwtDecoder = this.jwtDecoderRegistry.getJwtDecoder(clientRegistration);
|
||||||
if (jwtDecoder == null) {
|
if (jwtDecoder == null) {
|
||||||
throw new IllegalArgumentException("Unable to find a registered JwtDecoder for Client Registration: '" + clientRegistration.getRegistrationId() +
|
throw new IllegalArgumentException("Failed to find a registered JwtDecoder for Client Registration: '" + clientRegistration.getRegistrationId() +
|
||||||
"'. Check to ensure you have configured the JwkSet URI.");
|
"'. Check to ensure you have configured the JwkSet URI.");
|
||||||
}
|
}
|
||||||
Jwt jwt = jwtDecoder.decode((String)tokenResponse.getAdditionalParameters().get(OidcParameter.ID_TOKEN));
|
Jwt jwt = jwtDecoder.decode((String)tokenResponse.getAdditionalParameters().get(OidcParameter.ID_TOKEN));
|
||||||
IdToken idToken = new IdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims());
|
IdToken idToken = new IdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims());
|
||||||
|
|
||||||
OidcClientAuthenticationToken oidcClientAuthentication =
|
OidcClientAuthenticationToken clientAuthentication =
|
||||||
new OidcClientAuthenticationToken(clientRegistration, accessToken, idToken);
|
new OidcClientAuthenticationToken(clientRegistration, accessToken, idToken);
|
||||||
oidcClientAuthentication.setDetails(authorizationCodeAuthentication.getDetails());
|
clientAuthentication.setDetails(authorizationCodeAuthentication.getDetails());
|
||||||
|
|
||||||
return oidcClientAuthentication;
|
return clientAuthentication;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import org.springframework.util.Assert;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link OAuth2ClientAuthenticationToken} that represents an
|
* A {@link OAuth2ClientAuthenticationToken} that represents an
|
||||||
* <i>OpenID Connect 1.0 Client</i> {@link Authentication} (also known as <i>Relying Party</i>).
|
* <i>OpenID Connect 1.0 Client</i> {@link Authentication}.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* A client is considered <i>"authenticated"</i>,
|
* A client is considered <i>"authenticated"</i>,
|
||||||
|
@ -17,12 +17,12 @@ package org.springframework.security.oauth2.oidc.client.authentication;
|
|||||||
|
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
|
||||||
import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
|
import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
|
||||||
import org.springframework.security.oauth2.client.authentication.OAuth2UserAuthenticationToken;
|
import org.springframework.security.oauth2.client.authentication.OAuth2UserAuthenticationToken;
|
||||||
import org.springframework.security.oauth2.oidc.core.user.OidcUser;
|
import org.springframework.security.oauth2.oidc.core.user.OidcUser;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link OAuth2UserAuthenticationToken} that represents an
|
* A {@link OAuth2UserAuthenticationToken} that represents an
|
||||||
@ -41,7 +41,7 @@ import java.util.Collection;
|
|||||||
public class OidcUserAuthenticationToken extends OAuth2UserAuthenticationToken {
|
public class OidcUserAuthenticationToken extends OAuth2UserAuthenticationToken {
|
||||||
|
|
||||||
public OidcUserAuthenticationToken(OidcClientAuthenticationToken clientAuthentication) {
|
public OidcUserAuthenticationToken(OidcClientAuthenticationToken clientAuthentication) {
|
||||||
this(null, AuthorityUtils.NO_AUTHORITIES, clientAuthentication);
|
this(null, Collections.emptyList(), clientAuthentication);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OidcUserAuthenticationToken(OidcUser principal, Collection<? extends GrantedAuthority> authorities,
|
public OidcUserAuthenticationToken(OidcUser principal, Collection<? extends GrantedAuthority> authorities,
|
||||||
|
@ -65,7 +65,7 @@ public class OidcUserService implements OAuth2UserService {
|
|||||||
|
|
||||||
UserInfo userInfo = null;
|
UserInfo userInfo = null;
|
||||||
if (this.shouldRetrieveUserInfo(oidcClientAuthentication)) {
|
if (this.shouldRetrieveUserInfo(oidcClientAuthentication)) {
|
||||||
Map<String, Object> userAttributes = this.getUserInfoRetriever().retrieve(oidcClientAuthentication);
|
Map<String, Object> userAttributes = this.userInfoRetriever.retrieve(oidcClientAuthentication);
|
||||||
userInfo = new UserInfo(userAttributes);
|
userInfo = new UserInfo(userAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,10 +76,6 @@ public class OidcUserService implements OAuth2UserService {
|
|||||||
return new DefaultOidcUser(authorities, oidcClientAuthentication.getIdToken(), userInfo);
|
return new DefaultOidcUser(authorities, oidcClientAuthentication.getIdToken(), userInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected UserInfoRetriever getUserInfoRetriever() {
|
|
||||||
return this.userInfoRetriever;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void setUserInfoRetriever(UserInfoRetriever userInfoRetriever) {
|
public final void setUserInfoRetriever(UserInfoRetriever userInfoRetriever) {
|
||||||
Assert.notNull(userInfoRetriever, "userInfoRetriever cannot be null");
|
Assert.notNull(userInfoRetriever, "userInfoRetriever cannot be null");
|
||||||
this.userInfoRetriever = userInfoRetriever;
|
this.userInfoRetriever = userInfoRetriever;
|
||||||
|
@ -165,8 +165,8 @@ public class AuthorizationCodeAuthenticationFilterTests {
|
|||||||
Assertions.assertThat(authenticationExceptionArgCaptor.getValue()).isInstanceOf(OAuth2AuthenticationException.class);
|
Assertions.assertThat(authenticationExceptionArgCaptor.getValue()).isInstanceOf(OAuth2AuthenticationException.class);
|
||||||
OAuth2AuthenticationException oauth2AuthenticationException =
|
OAuth2AuthenticationException oauth2AuthenticationException =
|
||||||
(OAuth2AuthenticationException)authenticationExceptionArgCaptor.getValue();
|
(OAuth2AuthenticationException)authenticationExceptionArgCaptor.getValue();
|
||||||
Assertions.assertThat(oauth2AuthenticationException.getErrorObject()).isNotNull();
|
Assertions.assertThat(oauth2AuthenticationException.getError()).isNotNull();
|
||||||
Assertions.assertThat(oauth2AuthenticationException.getErrorObject().getErrorCode()).isEqualTo(errorCode);
|
Assertions.assertThat(oauth2AuthenticationException.getError().getErrorCode()).isEqualTo(errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuthorizationCodeAuthenticationFilter setupFilter(ClientRegistration... clientRegistrations) throws Exception {
|
private AuthorizationCodeAuthenticationFilter setupFilter(ClientRegistration... clientRegistrations) throws Exception {
|
||||||
|
@ -128,7 +128,7 @@ public class AuthorizationRequestRedirectFilterTests {
|
|||||||
|
|
||||||
ClientRegistrationRepository clientRegistrationRepository = TestUtil.clientRegistrationRepository(clientRegistrations);
|
ClientRegistrationRepository clientRegistrationRepository = TestUtil.clientRegistrationRepository(clientRegistrations);
|
||||||
AuthorizationRequestRedirectFilter filter = new AuthorizationRequestRedirectFilter(clientRegistrationRepository);
|
AuthorizationRequestRedirectFilter filter = new AuthorizationRequestRedirectFilter(clientRegistrationRepository);
|
||||||
filter.setAuthorizationUriBuilder(authorizationUriBuilder);
|
filter.setAuthorizationRequestUriBuilder(authorizationUriBuilder);
|
||||||
|
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ public class DefaultOAuth2UserTests {
|
|||||||
@Test
|
@Test
|
||||||
public void constructorWhenNameAttributeKeyIsInvalidThenThrowsException() {
|
public void constructorWhenNameAttributeKeyIsInvalidThenThrowsException() {
|
||||||
this.thrown.expect(IllegalArgumentException.class);
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
this.thrown.expectMessage("Invalid nameAttributeKey: invalid");
|
this.thrown.expectMessage("Missing attribute 'invalid' in attributes");
|
||||||
|
|
||||||
new DefaultOAuth2User(TEST_AUTHORITIES, TEST_ATTRIBUTES, "invalid");
|
new DefaultOAuth2User(TEST_AUTHORITIES, TEST_ATTRIBUTES, "invalid");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user