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