parent
38aae7f015
commit
dc47a7575e
|
@ -163,14 +163,16 @@ public final class AuthorizedClientServiceOAuth2AuthorizedClientManager implemen
|
|||
|
||||
private OAuth2AuthorizationContext buildAuthorizationContext(OAuth2AuthorizeRequest authorizeRequest,
|
||||
Authentication principal, OAuth2AuthorizationContext.Builder contextBuilder) {
|
||||
OAuth2AuthorizationContext authorizationContext = contextBuilder.principal(principal)
|
||||
// @formatter:off
|
||||
return contextBuilder.principal(principal)
|
||||
.attributes((attributes) -> {
|
||||
Map<String, Object> contextAttributes = this.contextAttributesMapper.apply(authorizeRequest);
|
||||
if (!CollectionUtils.isEmpty(contextAttributes)) {
|
||||
attributes.putAll(contextAttributes);
|
||||
}
|
||||
}).build();
|
||||
return authorizationContext;
|
||||
})
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -81,9 +81,12 @@ public final class InMemoryReactiveOAuth2AuthorizedClientService implements Reac
|
|||
public Mono<Void> removeAuthorizedClient(String clientRegistrationId, String principalName) {
|
||||
Assert.hasText(clientRegistrationId, "clientRegistrationId cannot be empty");
|
||||
Assert.hasText(principalName, "principalName cannot be empty");
|
||||
// @formatter:off
|
||||
return this.clientRegistrationRepository.findByRegistrationId(clientRegistrationId)
|
||||
.map((clientRegistration) -> new OAuth2AuthorizedClientId(clientRegistrationId, principalName))
|
||||
.doOnNext(this.authorizedClients::remove).then(Mono.empty());
|
||||
.doOnNext(this.authorizedClients::remove)
|
||||
.then(Mono.empty());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -64,26 +64,42 @@ import org.springframework.util.StringUtils;
|
|||
*/
|
||||
public class JdbcOAuth2AuthorizedClientService implements OAuth2AuthorizedClientService {
|
||||
|
||||
private static final String COLUMN_NAMES = "client_registration_id, " + "principal_name, " + "access_token_type, "
|
||||
+ "access_token_value, " + "access_token_issued_at, " + "access_token_expires_at, "
|
||||
+ "access_token_scopes, " + "refresh_token_value, " + "refresh_token_issued_at";
|
||||
// @formatter:off
|
||||
private static final String COLUMN_NAMES = "client_registration_id, "
|
||||
+ "principal_name, "
|
||||
+ "access_token_type, "
|
||||
+ "access_token_value, "
|
||||
+ "access_token_issued_at, "
|
||||
+ "access_token_expires_at, "
|
||||
+ "access_token_scopes, "
|
||||
+ "refresh_token_value, "
|
||||
+ "refresh_token_issued_at";
|
||||
// @formatter:on
|
||||
|
||||
private static final String TABLE_NAME = "oauth2_authorized_client";
|
||||
|
||||
private static final String PK_FILTER = "client_registration_id = ? AND principal_name = ?";
|
||||
|
||||
private static final String LOAD_AUTHORIZED_CLIENT_SQL = "SELECT " + COLUMN_NAMES + " FROM " + TABLE_NAME
|
||||
// @formatter:off
|
||||
private static final String LOAD_AUTHORIZED_CLIENT_SQL = "SELECT " + COLUMN_NAMES
|
||||
+ " FROM " + TABLE_NAME
|
||||
+ " WHERE " + PK_FILTER;
|
||||
// @formatter:on
|
||||
|
||||
private static final String SAVE_AUTHORIZED_CLIENT_SQL = "INSERT INTO " + TABLE_NAME + " (" + COLUMN_NAMES
|
||||
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
// @formatter:off
|
||||
private static final String SAVE_AUTHORIZED_CLIENT_SQL = "INSERT INTO " + TABLE_NAME
|
||||
+ " (" + COLUMN_NAMES + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
// @formatter:on
|
||||
|
||||
private static final String REMOVE_AUTHORIZED_CLIENT_SQL = "DELETE FROM " + TABLE_NAME + " WHERE " + PK_FILTER;
|
||||
|
||||
// @formatter:off
|
||||
private static final String UPDATE_AUTHORIZED_CLIENT_SQL = "UPDATE " + TABLE_NAME
|
||||
+ " SET access_token_type = ?, access_token_value = ?, access_token_issued_at = ?,"
|
||||
+ " access_token_expires_at = ?, access_token_scopes = ?,"
|
||||
+ " refresh_token_value = ?, refresh_token_issued_at = ?" + " WHERE " + PK_FILTER;
|
||||
+ " refresh_token_value = ?, refresh_token_issued_at = ?"
|
||||
+ " WHERE " + PK_FILTER;
|
||||
// @formatter:on
|
||||
|
||||
protected final JdbcOperations jdbcOperations;
|
||||
|
||||
|
|
|
@ -68,11 +68,15 @@ public abstract class AbstractWebClientReactiveOAuth2AccessTokenResponseClient<T
|
|||
@Override
|
||||
public Mono<OAuth2AccessTokenResponse> getTokenResponse(T grantRequest) {
|
||||
Assert.notNull(grantRequest, "grantRequest cannot be null");
|
||||
return Mono.defer(
|
||||
() -> this.webClient.post().uri(clientRegistration(grantRequest).getProviderDetails().getTokenUri())
|
||||
.headers((headers) -> populateTokenRequestHeaders(grantRequest, headers))
|
||||
.body(createTokenRequestBody(grantRequest)).exchange()
|
||||
.flatMap((response) -> readTokenResponse(grantRequest, response)));
|
||||
// @formatter:off
|
||||
return Mono.defer(() -> this.webClient.post()
|
||||
.uri(clientRegistration(grantRequest).getProviderDetails().getTokenUri())
|
||||
.headers((headers) -> populateTokenRequestHeaders(grantRequest, headers))
|
||||
.body(createTokenRequestBody(grantRequest))
|
||||
.exchange()
|
||||
.flatMap((response) -> readTokenResponse(grantRequest, response))
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -187,7 +191,12 @@ public abstract class AbstractWebClientReactiveOAuth2AccessTokenResponseClient<T
|
|||
OAuth2AccessTokenResponse populateTokenResponse(T grantRequest, OAuth2AccessTokenResponse tokenResponse) {
|
||||
if (CollectionUtils.isEmpty(tokenResponse.getAccessToken().getScopes())) {
|
||||
Set<String> defaultScopes = defaultScopes(grantRequest);
|
||||
tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse).scopes(defaultScopes).build();
|
||||
// @formatter:off
|
||||
tokenResponse = OAuth2AccessTokenResponse
|
||||
.withResponse(tokenResponse)
|
||||
.scopes(defaultScopes)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
return tokenResponse;
|
||||
}
|
||||
|
|
|
@ -82,8 +82,11 @@ public final class DefaultAuthorizationCodeTokenResponseClient
|
|||
// https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
// If AccessTokenResponse.scope is empty, then default to the scope
|
||||
// originally requested by the client in the Token Request
|
||||
// @formatter:off
|
||||
tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse)
|
||||
.scopes(authorizationCodeGrantRequest.getClientRegistration().getScopes()).build();
|
||||
.scopes(authorizationCodeGrantRequest.getClientRegistration().getScopes())
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
return tokenResponse;
|
||||
}
|
||||
|
|
|
@ -82,8 +82,11 @@ public final class DefaultClientCredentialsTokenResponseClient
|
|||
// https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
// If AccessTokenResponse.scope is empty, then default to the scope
|
||||
// originally requested by the client in the Token Request
|
||||
// @formatter:off
|
||||
tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse)
|
||||
.scopes(clientCredentialsGrantRequest.getClientRegistration().getScopes()).build();
|
||||
.scopes(clientCredentialsGrantRequest.getClientRegistration().getScopes())
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
return tokenResponse;
|
||||
}
|
||||
|
|
|
@ -119,8 +119,15 @@ public class NimbusAuthorizationCodeTokenResponseClient
|
|||
refreshToken = accessTokenResponse.getTokens().getRefreshToken().getValue();
|
||||
}
|
||||
Map<String, Object> additionalParameters = new LinkedHashMap<>(accessTokenResponse.getCustomParameters());
|
||||
return OAuth2AccessTokenResponse.withToken(accessToken).tokenType(accessTokenType).expiresIn(expiresIn)
|
||||
.scopes(scopes).refreshToken(refreshToken).additionalParameters(additionalParameters).build();
|
||||
// @formatter:off
|
||||
return OAuth2AccessTokenResponse.withToken(accessToken)
|
||||
.tokenType(accessTokenType)
|
||||
.expiresIn(expiresIn)
|
||||
.scopes(scopes)
|
||||
.refreshToken(refreshToken)
|
||||
.additionalParameters(additionalParameters)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private com.nimbusds.oauth2.sdk.TokenResponse getTokenResponse(AuthorizationGrant authorizationCodeGrant,
|
||||
|
|
|
@ -191,24 +191,31 @@ public class OidcAuthorizationCodeReactiveAuthenticationManager implements React
|
|||
null);
|
||||
return Mono.error(new OAuth2AuthenticationException(invalidIdTokenError, invalidIdTokenError.toString()));
|
||||
}
|
||||
// @formatter:off
|
||||
return createOidcToken(clientRegistration, accessTokenResponse)
|
||||
.doOnNext((idToken) -> validateNonce(authorizationCodeAuthentication, idToken))
|
||||
.map((idToken) -> new OidcUserRequest(clientRegistration, accessToken, idToken, additionalParameters))
|
||||
.flatMap(this.userService::loadUser).map((oauth2User) -> {
|
||||
.flatMap(this.userService::loadUser)
|
||||
.map((oauth2User) -> {
|
||||
Collection<? extends GrantedAuthority> mappedAuthorities = this.authoritiesMapper
|
||||
.mapAuthorities(oauth2User.getAuthorities());
|
||||
return new OAuth2LoginAuthenticationToken(authorizationCodeAuthentication.getClientRegistration(),
|
||||
authorizationCodeAuthentication.getAuthorizationExchange(), oauth2User, mappedAuthorities,
|
||||
accessToken, accessTokenResponse.getRefreshToken());
|
||||
});
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<OidcIdToken> createOidcToken(ClientRegistration clientRegistration,
|
||||
OAuth2AccessTokenResponse accessTokenResponse) {
|
||||
ReactiveJwtDecoder jwtDecoder = this.jwtDecoderFactory.createDecoder(clientRegistration);
|
||||
String rawIdToken = (String) accessTokenResponse.getAdditionalParameters().get(OidcParameterNames.ID_TOKEN);
|
||||
return jwtDecoder.decode(rawIdToken).map(
|
||||
(jwt) -> new OidcIdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims()));
|
||||
// @formatter:off
|
||||
return jwtDecoder.decode(rawIdToken)
|
||||
.map((jwt) ->
|
||||
new OidcIdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims())
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private static Mono<OidcIdToken> validateNonce(
|
||||
|
|
|
@ -97,8 +97,13 @@ public class OidcReactiveOAuth2UserService implements ReactiveOAuth2UserService<
|
|||
@Override
|
||||
public Mono<OidcUser> loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
|
||||
Assert.notNull(userRequest, "userRequest cannot be null");
|
||||
return getUserInfo(userRequest).map((userInfo) -> new OidcUserAuthority(userRequest.getIdToken(), userInfo))
|
||||
.defaultIfEmpty(new OidcUserAuthority(userRequest.getIdToken(), null)).map((authority) -> {
|
||||
// @formatter:off
|
||||
return getUserInfo(userRequest)
|
||||
.map((userInfo) ->
|
||||
new OidcUserAuthority(userRequest.getIdToken(), userInfo)
|
||||
)
|
||||
.defaultIfEmpty(new OidcUserAuthority(userRequest.getIdToken(), null))
|
||||
.map((authority) -> {
|
||||
OidcUserInfo userInfo = authority.getUserInfo();
|
||||
Set<GrantedAuthority> authorities = new HashSet<>();
|
||||
authorities.add(authority);
|
||||
|
@ -114,14 +119,19 @@ public class OidcReactiveOAuth2UserService implements ReactiveOAuth2UserService<
|
|||
}
|
||||
return new DefaultOidcUser(authorities, userRequest.getIdToken(), userInfo);
|
||||
});
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<OidcUserInfo> getUserInfo(OidcUserRequest userRequest) {
|
||||
if (!OidcUserRequestUtils.shouldRetrieveUserInfo(userRequest)) {
|
||||
return Mono.empty();
|
||||
}
|
||||
return this.oauth2UserService.loadUser(userRequest).map(OAuth2User::getAttributes)
|
||||
.map((claims) -> convertClaims(claims, userRequest.getClientRegistration())).map(OidcUserInfo::new)
|
||||
// @formatter:off
|
||||
return this.oauth2UserService
|
||||
.loadUser(userRequest)
|
||||
.map(OAuth2User::getAttributes)
|
||||
.map((claims) -> convertClaims(claims, userRequest.getClientRegistration()))
|
||||
.map(OidcUserInfo::new)
|
||||
.doOnNext((userInfo) -> {
|
||||
String subject = userInfo.getSubject();
|
||||
if (subject == null || !subject.equals(userRequest.getIdToken().getSubject())) {
|
||||
|
@ -129,6 +139,7 @@ public class OidcReactiveOAuth2UserService implements ReactiveOAuth2UserService<
|
|||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
||||
}
|
||||
});
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Map<String, Object> convertClaims(Map<String, Object> claims, ClientRegistration clientRegistration) {
|
||||
|
|
|
@ -93,10 +93,17 @@ public final class OidcClientInitiatedLogoutSuccessHandler extends SimpleUrlLogo
|
|||
if (this.postLogoutRedirectUri == null) {
|
||||
return null;
|
||||
}
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
|
||||
.replacePath(request.getContextPath()).replaceQuery(null).fragment(null).build();
|
||||
// @formatter:off
|
||||
UriComponents uriComponents = UriComponentsBuilder
|
||||
.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
|
||||
.replacePath(request.getContextPath())
|
||||
.replaceQuery(null)
|
||||
.fragment(null)
|
||||
.build();
|
||||
return UriComponentsBuilder.fromUriString(this.postLogoutRedirectUri)
|
||||
.buildAndExpand(Collections.singletonMap("baseUrl", uriComponents.toUriString())).toUri();
|
||||
.buildAndExpand(Collections.singletonMap("baseUrl", uriComponents.toUriString()))
|
||||
.toUri();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private String endpointUri(URI endSessionEndpoint, String idToken, URI postLogoutRedirectUri) {
|
||||
|
@ -105,7 +112,11 @@ public final class OidcClientInitiatedLogoutSuccessHandler extends SimpleUrlLogo
|
|||
if (postLogoutRedirectUri != null) {
|
||||
builder.queryParam("post_logout_redirect_uri", postLogoutRedirectUri);
|
||||
}
|
||||
return builder.encode(StandardCharsets.UTF_8).build().toUriString();
|
||||
// @formatter:off
|
||||
return builder.encode(StandardCharsets.UTF_8)
|
||||
.build()
|
||||
.toUriString();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -72,11 +72,14 @@ public class OidcClientInitiatedServerLogoutSuccessHandler implements ServerLogo
|
|||
|
||||
@Override
|
||||
public Mono<Void> onLogoutSuccess(WebFilterExchange exchange, Authentication authentication) {
|
||||
return Mono.just(authentication).filter(OAuth2AuthenticationToken.class::isInstance)
|
||||
// @formatter:off
|
||||
return Mono.just(authentication)
|
||||
.filter(OAuth2AuthenticationToken.class::isInstance)
|
||||
.filter((token) -> authentication.getPrincipal() instanceof OidcUser)
|
||||
.map(OAuth2AuthenticationToken.class::cast)
|
||||
.map(OAuth2AuthenticationToken::getAuthorizedClientRegistrationId)
|
||||
.flatMap(this.clientRegistrationRepository::findByRegistrationId).flatMap((clientRegistration) -> {
|
||||
.flatMap(this.clientRegistrationRepository::findByRegistrationId)
|
||||
.flatMap((clientRegistration) -> {
|
||||
URI endSessionEndpoint = endSessionEndpoint(clientRegistration);
|
||||
if (endSessionEndpoint == null) {
|
||||
return Mono.empty();
|
||||
|
@ -86,8 +89,10 @@ public class OidcClientInitiatedServerLogoutSuccessHandler implements ServerLogo
|
|||
return Mono.just(endpointUri(endSessionEndpoint, idToken, postLogoutRedirectUri));
|
||||
})
|
||||
.switchIfEmpty(
|
||||
this.serverLogoutSuccessHandler.onLogoutSuccess(exchange, authentication).then(Mono.empty()))
|
||||
this.serverLogoutSuccessHandler.onLogoutSuccess(exchange, authentication).then(Mono.empty())
|
||||
)
|
||||
.flatMap((endpointUri) -> this.redirectStrategy.sendRedirect(exchange.getExchange(), endpointUri));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private URI endSessionEndpoint(ClientRegistration clientRegistration) {
|
||||
|
@ -118,10 +123,16 @@ public class OidcClientInitiatedServerLogoutSuccessHandler implements ServerLogo
|
|||
if (this.postLogoutRedirectUri == null) {
|
||||
return null;
|
||||
}
|
||||
// @formatter:off
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromUri(request.getURI())
|
||||
.replacePath(request.getPath().contextPath().value()).replaceQuery(null).fragment(null).build();
|
||||
.replacePath(request.getPath().contextPath().value())
|
||||
.replaceQuery(null)
|
||||
.fragment(null)
|
||||
.build();
|
||||
return UriComponentsBuilder.fromUriString(this.postLogoutRedirectUri)
|
||||
.buildAndExpand(Collections.singletonMap("baseUrl", uriComponents.toUriString())).toUri();
|
||||
.buildAndExpand(Collections.singletonMap("baseUrl", uriComponents.toUriString()))
|
||||
.toUri();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -168,11 +168,19 @@ public final class ClientRegistration implements Serializable {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClientRegistration{" + "registrationId='" + this.registrationId + '\'' + ", clientId='" + this.clientId
|
||||
+ '\'' + ", clientSecret='" + this.clientSecret + '\'' + ", clientAuthenticationMethod="
|
||||
+ this.clientAuthenticationMethod + ", authorizationGrantType=" + this.authorizationGrantType
|
||||
+ ", redirectUri='" + this.redirectUri + '\'' + ", scopes=" + this.scopes + ", providerDetails="
|
||||
+ this.providerDetails + ", clientName='" + this.clientName + '\'' + '}';
|
||||
// @formatter:off
|
||||
return "ClientRegistration{"
|
||||
+ "registrationId='" + this.registrationId + '\''
|
||||
+ ", clientId='" + this.clientId + '\''
|
||||
+ ", clientSecret='" + this.clientSecret + '\''
|
||||
+ ", clientAuthenticationMethod=" + this.clientAuthenticationMethod
|
||||
+ ", authorizationGrantType=" + this.authorizationGrantType
|
||||
+ ", redirectUri='" + this.redirectUri
|
||||
+ '\'' + ", scopes=" + this.scopes
|
||||
+ ", providerDetails=" + this.providerDetails
|
||||
+ ", clientName='" + this.clientName + '\''
|
||||
+ '}';
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -148,8 +148,11 @@ public final class ClientRegistrations {
|
|||
}
|
||||
|
||||
private static Supplier<ClientRegistration.Builder> oidc(URI issuer) {
|
||||
URI uri = UriComponentsBuilder.fromUri(issuer).replacePath(issuer.getPath() + OIDC_METADATA_PATH)
|
||||
// @formatter:off
|
||||
URI uri = UriComponentsBuilder.fromUri(issuer)
|
||||
.replacePath(issuer.getPath() + OIDC_METADATA_PATH)
|
||||
.build(Collections.emptyMap());
|
||||
// @formatter:on
|
||||
return () -> {
|
||||
RequestEntity<Void> request = RequestEntity.get(uri).build();
|
||||
Map<String, Object> configuration = rest.exchange(request, typeReference).getBody();
|
||||
|
@ -164,14 +167,20 @@ public final class ClientRegistrations {
|
|||
}
|
||||
|
||||
private static Supplier<ClientRegistration.Builder> oidcRfc8414(URI issuer) {
|
||||
URI uri = UriComponentsBuilder.fromUri(issuer).replacePath(OIDC_METADATA_PATH + issuer.getPath())
|
||||
// @formatter:off
|
||||
URI uri = UriComponentsBuilder.fromUri(issuer)
|
||||
.replacePath(OIDC_METADATA_PATH + issuer.getPath())
|
||||
.build(Collections.emptyMap());
|
||||
// @formatter:on
|
||||
return getRfc8414Builder(issuer, uri);
|
||||
}
|
||||
|
||||
private static Supplier<ClientRegistration.Builder> oauth(URI issuer) {
|
||||
URI uri = UriComponentsBuilder.fromUri(issuer).replacePath(OAUTH_METADATA_PATH + issuer.getPath())
|
||||
// @formatter:off
|
||||
URI uri = UriComponentsBuilder.fromUri(issuer)
|
||||
.replacePath(OAUTH_METADATA_PATH + issuer.getPath())
|
||||
.build(Collections.emptyMap());
|
||||
// @formatter:on
|
||||
return getRfc8414Builder(issuer, uri);
|
||||
}
|
||||
|
||||
|
@ -242,12 +251,19 @@ public final class ClientRegistrations {
|
|||
+ "\" returned a configuration of " + grantTypes);
|
||||
List<String> scopes = getScopes(metadata);
|
||||
Map<String, Object> configurationMetadata = new LinkedHashMap<>(metadata.toJSONObject());
|
||||
return ClientRegistration.withRegistrationId(name).userNameAttributeName(IdTokenClaimNames.SUB).scope(scopes)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).clientAuthenticationMethod(method)
|
||||
// @formatter:off
|
||||
return ClientRegistration.withRegistrationId(name)
|
||||
.userNameAttributeName(IdTokenClaimNames.SUB)
|
||||
.scope(scopes)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.clientAuthenticationMethod(method)
|
||||
.redirectUri("{baseUrl}/{action}/oauth2/code/{registrationId}")
|
||||
.authorizationUri(metadata.getAuthorizationEndpointURI().toASCIIString())
|
||||
.providerConfigurationMetadata(configurationMetadata)
|
||||
.tokenUri(metadata.getTokenEndpointURI().toASCIIString()).issuerUri(issuer).clientName(issuer);
|
||||
.tokenUri(metadata.getTokenEndpointURI().toASCIIString())
|
||||
.issuerUri(issuer)
|
||||
.clientName(issuer);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private static ClientAuthenticationMethod getClientAuthenticationMethod(String issuer,
|
||||
|
|
|
@ -108,13 +108,18 @@ public class DefaultReactiveOAuth2UserService implements ReactiveOAuth2UserServi
|
|||
.getUserInfoEndpoint().getAuthenticationMethod();
|
||||
WebClient.RequestHeadersSpec<?> requestHeadersSpec = getRequestHeaderSpec(userRequest, userInfoUri,
|
||||
authenticationMethod);
|
||||
// @formatter:off
|
||||
Mono<Map<String, Object>> userAttributes = requestHeadersSpec.retrieve()
|
||||
.onStatus((s) -> s != HttpStatus.OK, (response) -> parse(response).map((userInfoErrorResponse) -> {
|
||||
String description = userInfoErrorResponse.getErrorObject().getDescription();
|
||||
OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE, description,
|
||||
null);
|
||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
||||
})).bodyToMono(DefaultReactiveOAuth2UserService.STRING_OBJECT_MAP);
|
||||
.onStatus((s) -> s != HttpStatus.OK, (response) ->
|
||||
parse(response)
|
||||
.map((userInfoErrorResponse) -> {
|
||||
String description = userInfoErrorResponse.getErrorObject().getDescription();
|
||||
OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE, description,
|
||||
null);
|
||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
||||
})
|
||||
)
|
||||
.bodyToMono(DefaultReactiveOAuth2UserService.STRING_OBJECT_MAP);
|
||||
return userAttributes.map((attrs) -> {
|
||||
GrantedAuthority authority = new OAuth2UserAuthority(attrs);
|
||||
Set<GrantedAuthority> authorities = new HashSet<>();
|
||||
|
@ -125,40 +130,54 @@ public class DefaultReactiveOAuth2UserService implements ReactiveOAuth2UserServi
|
|||
}
|
||||
|
||||
return new DefaultOAuth2User(authorities, attrs, userNameAttributeName);
|
||||
}).onErrorMap(IOException.class,
|
||||
})
|
||||
.onErrorMap(IOException.class,
|
||||
(ex) -> new AuthenticationServiceException("Unable to access the userInfoEndpoint " + userInfoUri,
|
||||
ex))
|
||||
.onErrorMap(UnsupportedMediaTypeException.class, (ex) -> {
|
||||
String errorMessage = "An error occurred while attempting to retrieve the UserInfo Resource from '"
|
||||
+ userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint()
|
||||
.getUri()
|
||||
+ "': response contains invalid content type '" + ex.getContentType().toString() + "'. "
|
||||
+ "The UserInfo Response should return a JSON object (content type 'application/json') "
|
||||
+ "that contains a collection of name and value pairs of the claims about the authenticated End-User. "
|
||||
+ "Please ensure the UserInfo Uri in UserInfoEndpoint for Client Registration '"
|
||||
+ userRequest.getClientRegistration().getRegistrationId()
|
||||
+ "' conforms to the UserInfo Endpoint, "
|
||||
+ "as defined in OpenID Connect 1.0: 'https://openid.net/specs/openid-connect-core-1_0.html#UserInfo'";
|
||||
OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE, errorMessage,
|
||||
null);
|
||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex);
|
||||
}).onErrorMap((t) -> !(t instanceof AuthenticationServiceException), (t) -> {
|
||||
OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE,
|
||||
"An error occurred reading the UserInfo Success response: " + t.getMessage(), null);
|
||||
return new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), t);
|
||||
});
|
||||
ex)
|
||||
)
|
||||
.onErrorMap(UnsupportedMediaTypeException.class, (ex) -> {
|
||||
String errorMessage = "An error occurred while attempting to retrieve the UserInfo Resource from '"
|
||||
+ userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint()
|
||||
.getUri()
|
||||
+ "': response contains invalid content type '" + ex.getContentType().toString() + "'. "
|
||||
+ "The UserInfo Response should return a JSON object (content type 'application/json') "
|
||||
+ "that contains a collection of name and value pairs of the claims about the authenticated End-User. "
|
||||
+ "Please ensure the UserInfo Uri in UserInfoEndpoint for Client Registration '"
|
||||
+ userRequest.getClientRegistration().getRegistrationId()
|
||||
+ "' conforms to the UserInfo Endpoint, "
|
||||
+ "as defined in OpenID Connect 1.0: 'https://openid.net/specs/openid-connect-core-1_0.html#UserInfo'";
|
||||
OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE, errorMessage,
|
||||
null);
|
||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex);
|
||||
})
|
||||
.onErrorMap((t) -> !(t instanceof AuthenticationServiceException), (t) -> {
|
||||
OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE,
|
||||
"An error occurred reading the UserInfo Success response: " + t.getMessage(), null);
|
||||
return new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), t);
|
||||
});
|
||||
});
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private WebClient.RequestHeadersSpec<?> getRequestHeaderSpec(OAuth2UserRequest userRequest, String userInfoUri,
|
||||
AuthenticationMethod authenticationMethod) {
|
||||
if (AuthenticationMethod.FORM.equals(authenticationMethod)) {
|
||||
return this.webClient.post().uri(userInfoUri).header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
// @formatter:off
|
||||
return this.webClient.post()
|
||||
.uri(userInfoUri)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
.syncBody("access_token=" + userRequest.getAccessToken().getTokenValue());
|
||||
.bodyValue("access_token=" + userRequest.getAccessToken().getTokenValue());
|
||||
// @formatter:on
|
||||
}
|
||||
return this.webClient.get().uri(userInfoUri).header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
.headers((headers) -> headers.setBearerAuth(userRequest.getAccessToken().getTokenValue()));
|
||||
// @formatter:off
|
||||
return this.webClient.get()
|
||||
.uri(userInfoUri)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
.headers((headers) -> headers
|
||||
.setBearerAuth(userRequest.getAccessToken().getTokenValue())
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -58,8 +58,13 @@ public class DelegatingOAuth2UserService<R extends OAuth2UserRequest, U extends
|
|||
@Override
|
||||
public U loadUser(R userRequest) throws OAuth2AuthenticationException {
|
||||
Assert.notNull(userRequest, "userRequest cannot be null");
|
||||
return this.userServices.stream().map((userService) -> userService.loadUser(userRequest))
|
||||
.filter(Objects::nonNull).findFirst().orElse(null);
|
||||
// @formatter:off
|
||||
return this.userServices.stream()
|
||||
.map((userService) -> userService.loadUser(userRequest))
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -153,10 +153,14 @@ public final class DefaultOAuth2AuthorizationRequestResolver implements OAuth2Au
|
|||
|
||||
String redirectUriStr = expandRedirectUri(request, clientRegistration, redirectUriAction);
|
||||
|
||||
// @formatter:off
|
||||
builder.clientId(clientRegistration.getClientId())
|
||||
.authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri())
|
||||
.redirectUri(redirectUriStr).scopes(clientRegistration.getScopes())
|
||||
.state(this.stateGenerator.generateKey()).attributes(attributes);
|
||||
.redirectUri(redirectUriStr)
|
||||
.scopes(clientRegistration.getScopes())
|
||||
.state(this.stateGenerator.generateKey())
|
||||
.attributes(attributes);
|
||||
// @formatter:on
|
||||
|
||||
this.authorizationRequestCustomizer.accept(builder);
|
||||
|
||||
|
@ -219,8 +223,13 @@ public final class DefaultOAuth2AuthorizationRequestResolver implements OAuth2Au
|
|||
String action) {
|
||||
Map<String, String> uriVariables = new HashMap<>();
|
||||
uriVariables.put("registrationId", clientRegistration.getRegistrationId());
|
||||
// @formatter:off
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
|
||||
.replacePath(request.getContextPath()).replaceQuery(null).fragment(null).build();
|
||||
.replacePath(request.getContextPath())
|
||||
.replaceQuery(null)
|
||||
.fragment(null)
|
||||
.build();
|
||||
// @formatter:on
|
||||
String scheme = uriComponents.getScheme();
|
||||
uriVariables.put("baseScheme", (scheme != null) ? scheme : "");
|
||||
String host = uriComponents.getHost();
|
||||
|
|
|
@ -87,8 +87,14 @@ import org.springframework.web.context.request.ServletRequestAttributes;
|
|||
*/
|
||||
public final class DefaultOAuth2AuthorizedClientManager implements OAuth2AuthorizedClientManager {
|
||||
|
||||
private static final OAuth2AuthorizedClientProvider DEFAULT_AUTHORIZED_CLIENT_PROVIDER = OAuth2AuthorizedClientProviderBuilder
|
||||
.builder().authorizationCode().refreshToken().clientCredentials().password().build();
|
||||
// @formatter:off
|
||||
private static final OAuth2AuthorizedClientProvider DEFAULT_AUTHORIZED_CLIENT_PROVIDER = OAuth2AuthorizedClientProviderBuilder.builder()
|
||||
.authorizationCode()
|
||||
.refreshToken()
|
||||
.clientCredentials()
|
||||
.password()
|
||||
.build();
|
||||
// @formatter:on
|
||||
|
||||
private final ClientRegistrationRepository clientRegistrationRepository;
|
||||
|
||||
|
@ -156,13 +162,16 @@ public final class DefaultOAuth2AuthorizedClientManager implements OAuth2Authori
|
|||
contextBuilder = OAuth2AuthorizationContext.withClientRegistration(clientRegistration);
|
||||
}
|
||||
}
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = contextBuilder.principal(principal)
|
||||
.attributes((attributes) -> {
|
||||
Map<String, Object> contextAttributes = this.contextAttributesMapper.apply(authorizeRequest);
|
||||
if (!CollectionUtils.isEmpty(contextAttributes)) {
|
||||
attributes.putAll(contextAttributes);
|
||||
}
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
// @formatter:on
|
||||
try {
|
||||
authorizedClient = this.authorizedClientProvider.authorize(authorizationContext);
|
||||
}
|
||||
|
|
|
@ -93,11 +93,20 @@ import org.springframework.web.server.ServerWebExchange;
|
|||
*/
|
||||
public final class DefaultReactiveOAuth2AuthorizedClientManager implements ReactiveOAuth2AuthorizedClientManager {
|
||||
|
||||
private static final ReactiveOAuth2AuthorizedClientProvider DEFAULT_AUTHORIZED_CLIENT_PROVIDER = ReactiveOAuth2AuthorizedClientProviderBuilder
|
||||
.builder().authorizationCode().refreshToken().clientCredentials().password().build();
|
||||
// @formatter:off
|
||||
private static final ReactiveOAuth2AuthorizedClientProvider DEFAULT_AUTHORIZED_CLIENT_PROVIDER = ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
|
||||
.authorizationCode()
|
||||
.refreshToken()
|
||||
.clientCredentials()
|
||||
.password()
|
||||
.build();
|
||||
// @formatter:on
|
||||
|
||||
// @formatter:off
|
||||
private static final Mono<ServerWebExchange> currentServerWebExchangeMono = Mono.subscriberContext()
|
||||
.filter((c) -> c.hasKey(ServerWebExchange.class)).map((c) -> c.get(ServerWebExchange.class));
|
||||
.filter((c) -> c.hasKey(ServerWebExchange.class))
|
||||
.map((c) -> c.get(ServerWebExchange.class));
|
||||
// @formatter:on
|
||||
|
||||
private final ReactiveClientRegistrationRepository clientRegistrationRepository;
|
||||
|
||||
|
@ -138,28 +147,32 @@ public final class DefaultReactiveOAuth2AuthorizedClientManager implements React
|
|||
Assert.notNull(authorizeRequest, "authorizeRequest cannot be null");
|
||||
String clientRegistrationId = authorizeRequest.getClientRegistrationId();
|
||||
Authentication principal = authorizeRequest.getPrincipal();
|
||||
// @formatter:off
|
||||
return Mono.justOrEmpty(authorizeRequest.<ServerWebExchange>getAttribute(ServerWebExchange.class.getName()))
|
||||
.switchIfEmpty(currentServerWebExchangeMono)
|
||||
.switchIfEmpty(Mono.error(() -> new IllegalArgumentException("serverWebExchange cannot be null")))
|
||||
.flatMap((serverWebExchange) -> Mono.justOrEmpty(authorizeRequest.getAuthorizedClient())
|
||||
.switchIfEmpty(Mono
|
||||
.defer(() -> loadAuthorizedClient(clientRegistrationId, principal, serverWebExchange)))
|
||||
.flatMap((serverWebExchange) -> Mono
|
||||
.justOrEmpty(authorizeRequest.getAuthorizedClient())
|
||||
.switchIfEmpty(Mono.defer(() -> loadAuthorizedClient(clientRegistrationId, principal, serverWebExchange)))
|
||||
.flatMap((authorizedClient) -> // Re-authorize
|
||||
authorizationContext(authorizeRequest, authorizedClient).flatMap(
|
||||
(authorizationContext) -> authorize(authorizationContext, principal, serverWebExchange))
|
||||
// Default to the existing authorizedClient if the
|
||||
// client was not re-authorized
|
||||
.defaultIfEmpty((authorizeRequest.getAuthorizedClient() != null)
|
||||
? authorizeRequest.getAuthorizedClient() : authorizedClient))
|
||||
authorizationContext(authorizeRequest, authorizedClient)
|
||||
.flatMap((authorizationContext) -> authorize(authorizationContext, principal, serverWebExchange))
|
||||
// Default to the existing authorizedClient if the
|
||||
// client was not re-authorized
|
||||
.defaultIfEmpty((authorizeRequest.getAuthorizedClient() != null)
|
||||
? authorizeRequest.getAuthorizedClient() : authorizedClient)
|
||||
)
|
||||
.switchIfEmpty(Mono.defer(() ->
|
||||
// Authorize
|
||||
this.clientRegistrationRepository.findByRegistrationId(clientRegistrationId)
|
||||
.switchIfEmpty(Mono.error(() -> new IllegalArgumentException(
|
||||
"Could not find ClientRegistration with id '" + clientRegistrationId + "'")))
|
||||
.flatMap((clientRegistration) -> authorizationContext(authorizeRequest,
|
||||
clientRegistration))
|
||||
.flatMap((authorizationContext) -> authorize(authorizationContext, principal,
|
||||
serverWebExchange)))));
|
||||
// Authorize
|
||||
this.clientRegistrationRepository.findByRegistrationId(clientRegistrationId)
|
||||
.switchIfEmpty(Mono.error(() -> new IllegalArgumentException(
|
||||
"Could not find ClientRegistration with id '" + clientRegistrationId + "'")))
|
||||
.flatMap((clientRegistration) -> authorizationContext(authorizeRequest,
|
||||
clientRegistration))
|
||||
.flatMap((authorizationContext) -> authorize(authorizationContext, principal,
|
||||
serverWebExchange))))
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<OAuth2AuthorizedClient> loadAuthorizedClient(String clientRegistrationId, Authentication principal,
|
||||
|
@ -181,18 +194,22 @@ public final class DefaultReactiveOAuth2AuthorizedClientManager implements React
|
|||
*/
|
||||
private Mono<OAuth2AuthorizedClient> authorize(OAuth2AuthorizationContext authorizationContext,
|
||||
Authentication principal, ServerWebExchange serverWebExchange) {
|
||||
// @formatter:off
|
||||
return this.authorizedClientProvider.authorize(authorizationContext)
|
||||
// Delegate to the authorizationSuccessHandler of the successful
|
||||
// authorization
|
||||
.flatMap((authorizedClient) -> this.authorizationSuccessHandler
|
||||
.onAuthorizationSuccess(authorizedClient, principal, createAttributes(serverWebExchange))
|
||||
.thenReturn(authorizedClient))
|
||||
.flatMap((authorizedClient) ->
|
||||
this.authorizationSuccessHandler
|
||||
.onAuthorizationSuccess(authorizedClient, principal, createAttributes(serverWebExchange))
|
||||
.thenReturn(authorizedClient)
|
||||
)
|
||||
// Delegate to the authorizationFailureHandler of the failed authorization
|
||||
.onErrorResume(OAuth2AuthorizationException.class,
|
||||
(authorizationException) -> this.authorizationFailureHandler
|
||||
.onAuthorizationFailure(authorizationException, principal,
|
||||
createAttributes(serverWebExchange))
|
||||
.then(Mono.error(authorizationException)));
|
||||
.onErrorResume(OAuth2AuthorizationException.class, (authorizationException) ->
|
||||
this.authorizationFailureHandler
|
||||
.onAuthorizationFailure(authorizationException, principal, createAttributes(serverWebExchange))
|
||||
.then(Mono.error(authorizationException))
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Map<String, Object> createAttributes(ServerWebExchange serverWebExchange) {
|
||||
|
@ -201,24 +218,36 @@ public final class DefaultReactiveOAuth2AuthorizedClientManager implements React
|
|||
|
||||
private Mono<OAuth2AuthorizationContext> authorizationContext(OAuth2AuthorizeRequest authorizeRequest,
|
||||
OAuth2AuthorizedClient authorizedClient) {
|
||||
return Mono.just(authorizeRequest).flatMap(this.contextAttributesMapper)
|
||||
.map((attrs) -> OAuth2AuthorizationContext.withAuthorizedClient(authorizedClient)
|
||||
.principal(authorizeRequest.getPrincipal()).attributes((attributes) -> {
|
||||
// @formatter:off
|
||||
return Mono.just(authorizeRequest)
|
||||
.flatMap(this.contextAttributesMapper)
|
||||
.map((attrs) -> OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(authorizeRequest.getPrincipal())
|
||||
.attributes((attributes) -> {
|
||||
if (!CollectionUtils.isEmpty(attrs)) {
|
||||
attributes.putAll(attrs);
|
||||
}
|
||||
}).build());
|
||||
})
|
||||
.build());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<OAuth2AuthorizationContext> authorizationContext(OAuth2AuthorizeRequest authorizeRequest,
|
||||
ClientRegistration clientRegistration) {
|
||||
return Mono.just(authorizeRequest).flatMap(this.contextAttributesMapper)
|
||||
// @formatter:off
|
||||
return Mono.just(authorizeRequest)
|
||||
.flatMap(this.contextAttributesMapper)
|
||||
.map((attrs) -> OAuth2AuthorizationContext.withClientRegistration(clientRegistration)
|
||||
.principal(authorizeRequest.getPrincipal()).attributes((attributes) -> {
|
||||
.principal(authorizeRequest.getPrincipal())
|
||||
.attributes((attributes) -> {
|
||||
if (!CollectionUtils.isEmpty(attrs)) {
|
||||
attributes.putAll(attrs);
|
||||
}
|
||||
}).build());
|
||||
})
|
||||
.build()
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -286,7 +315,9 @@ public final class DefaultReactiveOAuth2AuthorizedClientManager implements React
|
|||
@Override
|
||||
public Mono<Map<String, Object>> apply(OAuth2AuthorizeRequest authorizeRequest) {
|
||||
ServerWebExchange serverWebExchange = authorizeRequest.getAttribute(ServerWebExchange.class.getName());
|
||||
return Mono.justOrEmpty(serverWebExchange).switchIfEmpty(currentServerWebExchangeMono)
|
||||
// @formatter:off
|
||||
return Mono.justOrEmpty(serverWebExchange)
|
||||
.switchIfEmpty(currentServerWebExchangeMono)
|
||||
.flatMap((exchange) -> {
|
||||
Map<String, Object> contextAttributes = Collections.emptyMap();
|
||||
String scope = exchange.getRequest().getQueryParams().getFirst(OAuth2ParameterNames.SCOPE);
|
||||
|
@ -296,7 +327,9 @@ public final class DefaultReactiveOAuth2AuthorizedClientManager implements React
|
|||
StringUtils.delimitedListToStringArray(scope, " "));
|
||||
}
|
||||
return Mono.just(contextAttributes);
|
||||
}).defaultIfEmpty(Collections.emptyMap());
|
||||
})
|
||||
.defaultIfEmpty(Collections.emptyMap());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -71,8 +71,14 @@ final class OAuth2AuthorizationResponseUtils {
|
|||
}
|
||||
String errorDescription = request.getFirst(OAuth2ParameterNames.ERROR_DESCRIPTION);
|
||||
String errorUri = request.getFirst(OAuth2ParameterNames.ERROR_URI);
|
||||
return OAuth2AuthorizationResponse.error(errorCode).redirectUri(redirectUri).errorDescription(errorDescription)
|
||||
.errorUri(errorUri).state(state).build();
|
||||
// @formatter:off
|
||||
return OAuth2AuthorizationResponse.error(errorCode)
|
||||
.redirectUri(redirectUri)
|
||||
.errorDescription(errorDescription)
|
||||
.errorUri(errorUri)
|
||||
.state(state)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -176,8 +176,12 @@ public class OAuth2LoginAuthenticationFilter extends AbstractAuthenticationProce
|
|||
"Client Registration not found with Id: " + registrationId, null);
|
||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
||||
}
|
||||
String redirectUri = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request)).replaceQuery(null)
|
||||
.build().toUriString();
|
||||
// @formatter:off
|
||||
String redirectUri = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
|
||||
.replaceQuery(null)
|
||||
.build()
|
||||
.toUriString();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationResponse authorizationResponse = OAuth2AuthorizationResponseUtils.convert(params,
|
||||
redirectUri);
|
||||
Object authenticationDetails = this.authenticationDetailsSource.buildDetails(request);
|
||||
|
|
|
@ -126,9 +126,14 @@ public final class OAuth2AuthorizedClientArgumentResolver implements HandlerMeth
|
|||
}
|
||||
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
HttpServletResponse servletResponse = webRequest.getNativeResponse(HttpServletResponse.class);
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId(clientRegistrationId)
|
||||
.principal(principal).attribute(HttpServletRequest.class.getName(), servletRequest)
|
||||
.attribute(HttpServletResponse.class.getName(), servletResponse).build();
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(clientRegistrationId)
|
||||
.principal(principal)
|
||||
.attribute(HttpServletRequest.class.getName(), servletRequest)
|
||||
.attribute(HttpServletResponse.class.getName(), servletResponse)
|
||||
.build();
|
||||
// @formatter:on
|
||||
return this.authorizedClientManager.authorize(authorizeRequest);
|
||||
}
|
||||
|
||||
|
@ -176,11 +181,16 @@ public final class OAuth2AuthorizedClientArgumentResolver implements HandlerMeth
|
|||
|
||||
private void updateDefaultAuthorizedClientManager(
|
||||
OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsTokenResponseClient) {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
|
||||
.authorizationCode().refreshToken()
|
||||
.clientCredentials(
|
||||
(configurer) -> configurer.accessTokenResponseClient(clientCredentialsTokenResponseClient))
|
||||
.password().build();
|
||||
.authorizationCode()
|
||||
.refreshToken()
|
||||
.clientCredentials((configurer) ->
|
||||
configurer.accessTokenResponseClient(clientCredentialsTokenResponseClient)
|
||||
)
|
||||
.password()
|
||||
.build();
|
||||
// @formatter:on
|
||||
((DefaultOAuth2AuthorizedClientManager) this.authorizedClientManager)
|
||||
.setAuthorizedClientProvider(authorizedClientProvider);
|
||||
}
|
||||
|
|
|
@ -131,12 +131,18 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
|||
private final Mono<Authentication> currentAuthenticationMono = ReactiveSecurityContextHolder.getContext()
|
||||
.map(SecurityContext::getAuthentication).defaultIfEmpty(ANONYMOUS_USER_TOKEN);
|
||||
|
||||
// @formatter:off
|
||||
private final Mono<String> clientRegistrationIdMono = this.currentAuthenticationMono
|
||||
.filter((t) -> this.defaultOAuth2AuthorizedClient && t instanceof OAuth2AuthenticationToken)
|
||||
.cast(OAuth2AuthenticationToken.class).map(OAuth2AuthenticationToken::getAuthorizedClientRegistrationId);
|
||||
.cast(OAuth2AuthenticationToken.class)
|
||||
.map(OAuth2AuthenticationToken::getAuthorizedClientRegistrationId);
|
||||
// @formatter:on
|
||||
|
||||
// @formatter:off
|
||||
private final Mono<ServerWebExchange> currentServerWebExchangeMono = Mono.subscriberContext()
|
||||
.filter((c) -> c.hasKey(ServerWebExchange.class)).map((c) -> c.get(ServerWebExchange.class));
|
||||
.filter((c) -> c.hasKey(ServerWebExchange.class))
|
||||
.map((c) -> c.get(ServerWebExchange.class));
|
||||
// @formatter:on
|
||||
|
||||
private final ReactiveOAuth2AuthorizedClientManager authorizedClientManager;
|
||||
|
||||
|
@ -372,11 +378,14 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
|||
}
|
||||
|
||||
private void updateDefaultAuthorizedClientManager() {
|
||||
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
|
||||
.builder().authorizationCode()
|
||||
// @formatter:off
|
||||
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
|
||||
.authorizationCode()
|
||||
.refreshToken((configurer) -> configurer.clockSkew(this.accessTokenExpiresSkew))
|
||||
.clientCredentials(this::updateClientCredentialsProvider)
|
||||
.password((configurer) -> configurer.clockSkew(this.accessTokenExpiresSkew)).build();
|
||||
.password((configurer) -> configurer.clockSkew(this.accessTokenExpiresSkew))
|
||||
.build();
|
||||
// @formatter:on
|
||||
if (this.authorizedClientManager instanceof UnAuthenticatedReactiveOAuth2AuthorizedClientManager) {
|
||||
((UnAuthenticatedReactiveOAuth2AuthorizedClientManager) this.authorizedClientManager)
|
||||
.setAuthorizedClientProvider(authorizedClientProvider);
|
||||
|
@ -418,9 +427,12 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
|||
|
||||
@Override
|
||||
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
|
||||
return authorizedClient(request).map((authorizedClient) -> bearer(request, authorizedClient))
|
||||
// @formatter:off
|
||||
return authorizedClient(request)
|
||||
.map((authorizedClient) -> bearer(request, authorizedClient))
|
||||
.flatMap((requestWithBearer) -> exchangeAndHandleResponse(requestWithBearer, next))
|
||||
.switchIfEmpty(Mono.defer(() -> exchangeAndHandleResponse(request, next)));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<ClientResponse> exchangeAndHandleResponse(ClientRequest request, ExchangeFunction next) {
|
||||
|
@ -430,22 +442,30 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
|||
|
||||
private Mono<OAuth2AuthorizedClient> authorizedClient(ClientRequest request) {
|
||||
OAuth2AuthorizedClient authorizedClientFromAttrs = oauth2AuthorizedClient(request);
|
||||
// @formatter:off
|
||||
return Mono.justOrEmpty(authorizedClientFromAttrs)
|
||||
.switchIfEmpty(
|
||||
Mono.defer(() -> authorizeRequest(request).flatMap(this.authorizedClientManager::authorize)))
|
||||
.switchIfEmpty(Mono.defer(() -> authorizeRequest(request)
|
||||
.flatMap(this.authorizedClientManager::authorize))
|
||||
)
|
||||
.flatMap((authorizedClient) -> reauthorizeRequest(request, authorizedClient)
|
||||
.flatMap(this.authorizedClientManager::authorize));
|
||||
.flatMap(this.authorizedClientManager::authorize)
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<OAuth2AuthorizeRequest> authorizeRequest(ClientRequest request) {
|
||||
Mono<String> clientRegistrationId = effectiveClientRegistrationId(request);
|
||||
Mono<Optional<ServerWebExchange>> serverWebExchange = effectiveServerWebExchange(request);
|
||||
return Mono.zip(clientRegistrationId, this.currentAuthenticationMono, serverWebExchange).map((t3) -> {
|
||||
OAuth2AuthorizeRequest.Builder builder = OAuth2AuthorizeRequest.withClientRegistrationId(t3.getT1())
|
||||
.principal(t3.getT2());
|
||||
t3.getT3().ifPresent((exchange) -> builder.attribute(ServerWebExchange.class.getName(), exchange));
|
||||
return builder.build();
|
||||
});
|
||||
// @formatter:off
|
||||
return Mono.zip(clientRegistrationId, this.currentAuthenticationMono, serverWebExchange)
|
||||
.map((t3) -> {
|
||||
OAuth2AuthorizeRequest.Builder builder = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(t3.getT1())
|
||||
.principal(t3.getT2());
|
||||
t3.getT3().ifPresent((exchange) -> builder.attribute(ServerWebExchange.class.getName(), exchange));
|
||||
return builder.build();
|
||||
});
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -456,9 +476,11 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
|||
* given request.
|
||||
*/
|
||||
private Mono<String> effectiveClientRegistrationId(ClientRequest request) {
|
||||
// @formatter:off
|
||||
return Mono.justOrEmpty(clientRegistrationId(request))
|
||||
.switchIfEmpty(Mono.justOrEmpty(this.defaultClientRegistrationId))
|
||||
.switchIfEmpty(this.clientRegistrationIdMono);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -474,24 +496,34 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
|||
* {@link ServerWebExchange} that is active for the given request.
|
||||
*/
|
||||
private Mono<Optional<ServerWebExchange>> effectiveServerWebExchange(ClientRequest request) {
|
||||
return Mono.justOrEmpty(serverWebExchange(request)).switchIfEmpty(this.currentServerWebExchangeMono)
|
||||
.map(Optional::of).defaultIfEmpty(Optional.empty());
|
||||
// @formatter:off
|
||||
return Mono.justOrEmpty(serverWebExchange(request))
|
||||
.switchIfEmpty(this.currentServerWebExchangeMono)
|
||||
.map(Optional::of)
|
||||
.defaultIfEmpty(Optional.empty());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<OAuth2AuthorizeRequest> reauthorizeRequest(ClientRequest request,
|
||||
OAuth2AuthorizedClient authorizedClient) {
|
||||
Mono<Optional<ServerWebExchange>> serverWebExchange = effectiveServerWebExchange(request);
|
||||
return Mono.zip(this.currentAuthenticationMono, serverWebExchange).map((t2) -> {
|
||||
OAuth2AuthorizeRequest.Builder builder = OAuth2AuthorizeRequest.withAuthorizedClient(authorizedClient)
|
||||
.principal(t2.getT1());
|
||||
t2.getT2().ifPresent((exchange) -> builder.attribute(ServerWebExchange.class.getName(), exchange));
|
||||
return builder.build();
|
||||
});
|
||||
// @formatter:off
|
||||
return Mono.zip(this.currentAuthenticationMono, serverWebExchange)
|
||||
.map((t2) -> {
|
||||
OAuth2AuthorizeRequest.Builder builder = OAuth2AuthorizeRequest.withAuthorizedClient(authorizedClient)
|
||||
.principal(t2.getT1());
|
||||
t2.getT2().ifPresent((exchange) -> builder.attribute(ServerWebExchange.class.getName(), exchange));
|
||||
return builder.build();
|
||||
});
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private ClientRequest bearer(ClientRequest request, OAuth2AuthorizedClient authorizedClient) {
|
||||
// @formatter:off
|
||||
return ClientRequest.from(request)
|
||||
.headers((headers) -> headers.setBearerAuth(authorizedClient.getAccessToken().getTokenValue())).build();
|
||||
.headers((headers) -> headers.setBearerAuth(authorizedClient.getAccessToken().getTokenValue()))
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -555,10 +587,12 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
|||
Assert.notNull(authorizeRequest, "authorizeRequest cannot be null");
|
||||
String clientRegistrationId = authorizeRequest.getClientRegistrationId();
|
||||
Authentication principal = authorizeRequest.getPrincipal();
|
||||
// @formatter:off
|
||||
return Mono.justOrEmpty(authorizeRequest.getAuthorizedClient())
|
||||
.switchIfEmpty(loadAuthorizedClient(clientRegistrationId, principal))
|
||||
.flatMap((authorizedClient) -> reauthorize(authorizedClient, authorizeRequest, principal))
|
||||
.switchIfEmpty(findAndAuthorize(clientRegistrationId, principal));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<OAuth2AuthorizedClient> loadAuthorizedClient(String clientRegistrationId,
|
||||
|
@ -580,12 +614,18 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
|||
}
|
||||
|
||||
private Mono<OAuth2AuthorizedClient> findAndAuthorize(String clientRegistrationId, Authentication principal) {
|
||||
return Mono.defer(() -> this.clientRegistrationRepository.findByRegistrationId(clientRegistrationId)
|
||||
.switchIfEmpty(Mono.error(() -> new IllegalArgumentException(
|
||||
"Could not find ClientRegistration with id '" + clientRegistrationId + "'")))
|
||||
.flatMap((clientRegistration) -> Mono.just(OAuth2AuthorizationContext
|
||||
.withClientRegistration(clientRegistration).principal(principal).build()))
|
||||
.flatMap((authorizationContext) -> authorize(authorizationContext, principal)));
|
||||
// @formatter:off
|
||||
return Mono.defer(() ->
|
||||
this.clientRegistrationRepository.findByRegistrationId(clientRegistrationId)
|
||||
.switchIfEmpty(Mono.error(() ->
|
||||
new IllegalArgumentException("Could not find ClientRegistration with id '" + clientRegistrationId + "'"))
|
||||
)
|
||||
.flatMap((clientRegistration) -> Mono.just(OAuth2AuthorizationContext
|
||||
.withClientRegistration(clientRegistration).principal(principal).build())
|
||||
)
|
||||
.flatMap((authorizationContext) -> authorize(authorizationContext, principal))
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -601,18 +641,22 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
|||
*/
|
||||
private Mono<OAuth2AuthorizedClient> authorize(OAuth2AuthorizationContext authorizationContext,
|
||||
Authentication principal) {
|
||||
// @formatter:off
|
||||
return this.authorizedClientProvider.authorize(authorizationContext)
|
||||
// Delegates to the authorizationSuccessHandler of the successful
|
||||
// authorization
|
||||
.flatMap((authorizedClient) -> this.authorizationSuccessHandler
|
||||
.onAuthorizationSuccess(authorizedClient, principal, Collections.emptyMap())
|
||||
.thenReturn(authorizedClient))
|
||||
.thenReturn(authorizedClient)
|
||||
)
|
||||
// Delegates to the authorizationFailureHandler of the failed
|
||||
// authorization
|
||||
.onErrorResume(OAuth2AuthorizationException.class,
|
||||
(authorizationException) -> this.authorizationFailureHandler
|
||||
.onErrorResume(OAuth2AuthorizationException.class, (authorizationException) ->
|
||||
this.authorizationFailureHandler
|
||||
.onAuthorizationFailure(authorizationException, principal, Collections.emptyMap())
|
||||
.then(Mono.error(authorizationException)));
|
||||
.then(Mono.error(authorizationException))
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private void setAuthorizedClientProvider(ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider) {
|
||||
|
@ -653,23 +697,30 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
|||
|
||||
@Override
|
||||
public Mono<ClientResponse> handleResponse(ClientRequest request, Mono<ClientResponse> responseMono) {
|
||||
return responseMono.flatMap((response) -> handleResponse(request, response).thenReturn(response))
|
||||
// @formatter:off
|
||||
return responseMono
|
||||
.flatMap((response) -> handleResponse(request, response).thenReturn(response))
|
||||
.onErrorResume(WebClientResponseException.class,
|
||||
(e) -> handleWebClientResponseException(request, e).then(Mono.error(e)))
|
||||
(e) -> handleWebClientResponseException(request, e).then(Mono.error(e))
|
||||
)
|
||||
.onErrorResume(OAuth2AuthorizationException.class,
|
||||
(e) -> handleAuthorizationException(request, e).then(Mono.error(e)));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<Void> handleResponse(ClientRequest request, ClientResponse response) {
|
||||
return Mono.justOrEmpty(resolveErrorIfPossible(response)).flatMap((oauth2Error) -> {
|
||||
Mono<Optional<ServerWebExchange>> serverWebExchange = effectiveServerWebExchange(request);
|
||||
Mono<String> clientRegistrationId = effectiveClientRegistrationId(request);
|
||||
return Mono
|
||||
.zip(ServerOAuth2AuthorizedClientExchangeFilterFunction.this.currentAuthenticationMono,
|
||||
serverWebExchange, clientRegistrationId)
|
||||
.flatMap((zipped) -> handleAuthorizationFailure(zipped.getT1(), zipped.getT2(),
|
||||
new ClientAuthorizationException(oauth2Error, zipped.getT3())));
|
||||
});
|
||||
// @formatter:off
|
||||
return Mono.justOrEmpty(resolveErrorIfPossible(response))
|
||||
.flatMap((oauth2Error) -> {
|
||||
Mono<Optional<ServerWebExchange>> serverWebExchange = effectiveServerWebExchange(request);
|
||||
Mono<String> clientRegistrationId = effectiveClientRegistrationId(request);
|
||||
return Mono
|
||||
.zip(ServerOAuth2AuthorizedClientExchangeFilterFunction.this.currentAuthenticationMono,
|
||||
serverWebExchange, clientRegistrationId)
|
||||
.flatMap((zipped) -> handleAuthorizationFailure(zipped.getT1(), zipped.getT2(),
|
||||
new ClientAuthorizationException(oauth2Error, zipped.getT3())));
|
||||
});
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private OAuth2Error resolveErrorIfPossible(ClientResponse response) {
|
||||
|
@ -695,13 +746,19 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
|||
}
|
||||
|
||||
private Map<String, String> parseAuthParameters(String wwwAuthenticateHeader) {
|
||||
return Stream.of(wwwAuthenticateHeader).filter((header) -> !StringUtils.isEmpty(header))
|
||||
// @formatter:off
|
||||
return Stream.of(wwwAuthenticateHeader)
|
||||
.filter((header) -> !StringUtils.isEmpty(header))
|
||||
.filter((header) -> header.toLowerCase().startsWith("bearer"))
|
||||
.map((header) -> header.substring("bearer".length())).map((header) -> header.split(","))
|
||||
.flatMap(Stream::of).map((parameter) -> parameter.split("="))
|
||||
.map((header) -> header.substring("bearer".length()))
|
||||
.map((header) -> header.split(","))
|
||||
.flatMap(Stream::of)
|
||||
.map((parameter) -> parameter.split("="))
|
||||
.filter((parameter) -> parameter.length > 1)
|
||||
.collect(Collectors.toMap((parameters) -> parameters[0].trim(),
|
||||
(parameters) -> parameters[1].trim().replace("\"", "")));
|
||||
(parameters) -> parameters[1].trim().replace("\"", ""))
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -715,15 +772,16 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
|||
*/
|
||||
private Mono<Void> handleWebClientResponseException(ClientRequest request,
|
||||
WebClientResponseException exception) {
|
||||
return Mono.justOrEmpty(resolveErrorIfPossible(exception.getRawStatusCode())).flatMap((oauth2Error) -> {
|
||||
Mono<Optional<ServerWebExchange>> serverWebExchange = effectiveServerWebExchange(request);
|
||||
Mono<String> clientRegistrationId = effectiveClientRegistrationId(request);
|
||||
return Mono
|
||||
.zip(ServerOAuth2AuthorizedClientExchangeFilterFunction.this.currentAuthenticationMono,
|
||||
serverWebExchange, clientRegistrationId)
|
||||
.flatMap((zipped) -> handleAuthorizationFailure(zipped.getT1(), zipped.getT2(),
|
||||
new ClientAuthorizationException(oauth2Error, zipped.getT3(), exception)));
|
||||
});
|
||||
return Mono.justOrEmpty(resolveErrorIfPossible(exception.getRawStatusCode()))
|
||||
.flatMap((oauth2Error) -> {
|
||||
Mono<Optional<ServerWebExchange>> serverWebExchange = effectiveServerWebExchange(request);
|
||||
Mono<String> clientRegistrationId = effectiveClientRegistrationId(request);
|
||||
return Mono
|
||||
.zip(ServerOAuth2AuthorizedClientExchangeFilterFunction.this.currentAuthenticationMono,
|
||||
serverWebExchange, clientRegistrationId)
|
||||
.flatMap((zipped) -> handleAuthorizationFailure(zipped.getT1(), zipped.getT2(),
|
||||
new ClientAuthorizationException(oauth2Error, zipped.getT3(), exception)));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -262,10 +262,14 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement
|
|||
}
|
||||
|
||||
private void updateDefaultAuthorizedClientManager() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
|
||||
.authorizationCode().refreshToken((configurer) -> configurer.clockSkew(this.accessTokenExpiresSkew))
|
||||
.authorizationCode()
|
||||
.refreshToken((configurer) -> configurer.clockSkew(this.accessTokenExpiresSkew))
|
||||
.clientCredentials(this::updateClientCredentialsProvider)
|
||||
.password((configurer) -> configurer.clockSkew(this.accessTokenExpiresSkew)).build();
|
||||
.password((configurer) -> configurer.clockSkew(this.accessTokenExpiresSkew))
|
||||
.build();
|
||||
// @formatter:on
|
||||
((DefaultOAuth2AuthorizedClientManager) this.authorizedClientManager)
|
||||
.setAuthorizedClientProvider(authorizedClientProvider);
|
||||
}
|
||||
|
@ -435,15 +439,21 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement
|
|||
|
||||
@Override
|
||||
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
|
||||
// @formatter:off
|
||||
return mergeRequestAttributesIfNecessary(request)
|
||||
.filter((req) -> req.attribute(OAUTH2_AUTHORIZED_CLIENT_ATTR_NAME).isPresent())
|
||||
.flatMap((req) -> reauthorizeClient(getOAuth2AuthorizedClient(req.attributes()), req))
|
||||
.switchIfEmpty(Mono.defer(() -> mergeRequestAttributesIfNecessary(request)
|
||||
.filter((req) -> resolveClientRegistrationId(req) != null)
|
||||
.flatMap((req) -> authorizeClient(resolveClientRegistrationId(req), req))))
|
||||
.switchIfEmpty(
|
||||
Mono.defer(() ->
|
||||
mergeRequestAttributesIfNecessary(request)
|
||||
.filter((req) -> resolveClientRegistrationId(req) != null)
|
||||
.flatMap((req) -> authorizeClient(resolveClientRegistrationId(req), req))
|
||||
)
|
||||
)
|
||||
.map((authorizedClient) -> bearer(request, authorizedClient))
|
||||
.flatMap((requestWithBearer) -> exchangeAndHandleResponse(requestWithBearer, next))
|
||||
.switchIfEmpty(Mono.defer(() -> exchangeAndHandleResponse(request, next)));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<ClientResponse> exchangeAndHandleResponse(ClientRequest request, ExchangeFunction next) {
|
||||
|
@ -577,9 +587,12 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement
|
|||
}
|
||||
|
||||
private ClientRequest bearer(ClientRequest request, OAuth2AuthorizedClient authorizedClient) {
|
||||
// @formatter:off
|
||||
return ClientRequest.from(request)
|
||||
.headers((headers) -> headers.setBearerAuth(authorizedClient.getAccessToken().getTokenValue()))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient)).build();
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
static OAuth2AuthorizedClient getOAuth2AuthorizedClient(Map<String, Object> attrs) {
|
||||
|
@ -664,19 +677,22 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement
|
|||
}
|
||||
|
||||
private Mono<Void> handleResponse(ClientRequest request, ClientResponse response) {
|
||||
return Mono.justOrEmpty(resolveErrorIfPossible(response)).flatMap((oauth2Error) -> {
|
||||
Map<String, Object> attrs = request.attributes();
|
||||
OAuth2AuthorizedClient authorizedClient = getOAuth2AuthorizedClient(attrs);
|
||||
if (authorizedClient == null) {
|
||||
return Mono.empty();
|
||||
}
|
||||
ClientAuthorizationException authorizationException = new ClientAuthorizationException(oauth2Error,
|
||||
authorizedClient.getClientRegistration().getRegistrationId());
|
||||
Authentication principal = createAuthentication(authorizedClient.getPrincipalName());
|
||||
HttpServletRequest servletRequest = getRequest(attrs);
|
||||
HttpServletResponse servletResponse = getResponse(attrs);
|
||||
return handleAuthorizationFailure(authorizationException, principal, servletRequest, servletResponse);
|
||||
});
|
||||
// @formatter:off
|
||||
return Mono.justOrEmpty(resolveErrorIfPossible(response))
|
||||
.flatMap((oauth2Error) -> {
|
||||
Map<String, Object> attrs = request.attributes();
|
||||
OAuth2AuthorizedClient authorizedClient = getOAuth2AuthorizedClient(attrs);
|
||||
if (authorizedClient == null) {
|
||||
return Mono.empty();
|
||||
}
|
||||
ClientAuthorizationException authorizationException = new ClientAuthorizationException(oauth2Error,
|
||||
authorizedClient.getClientRegistration().getRegistrationId());
|
||||
Authentication principal = createAuthentication(authorizedClient.getPrincipalName());
|
||||
HttpServletRequest servletRequest = getRequest(attrs);
|
||||
HttpServletResponse servletResponse = getResponse(attrs);
|
||||
return handleAuthorizationFailure(authorizationException, principal, servletRequest, servletResponse);
|
||||
});
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private OAuth2Error resolveErrorIfPossible(ClientResponse response) {
|
||||
|
@ -702,13 +718,18 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement
|
|||
}
|
||||
|
||||
private Map<String, String> parseAuthParameters(String wwwAuthenticateHeader) {
|
||||
// @formatter:off
|
||||
return Stream.of(wwwAuthenticateHeader).filter((header) -> !StringUtils.isEmpty(header))
|
||||
.filter((header) -> header.toLowerCase().startsWith("bearer"))
|
||||
.map((header) -> header.substring("bearer".length())).map((header) -> header.split(","))
|
||||
.flatMap(Stream::of).map((parameter) -> parameter.split("="))
|
||||
.map((header) -> header.substring("bearer".length()))
|
||||
.map((header) -> header.split(","))
|
||||
.flatMap(Stream::of)
|
||||
.map((parameter) -> parameter.split("="))
|
||||
.filter((parameter) -> parameter.length > 1)
|
||||
.collect(Collectors.toMap((parameters) -> parameters[0].trim(),
|
||||
(parameters) -> parameters[1].trim().replace("\"", "")));
|
||||
(parameters) -> parameters[1].trim().replace("\"", ""))
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -776,7 +797,11 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement
|
|||
HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
|
||||
Runnable runnable = () -> this.authorizationFailureHandler.onAuthorizationFailure(exception, principal,
|
||||
createAttributes(servletRequest, servletResponse));
|
||||
return Mono.fromRunnable(runnable).subscribeOn(Schedulers.boundedElastic()).then();
|
||||
// @formatter:off
|
||||
return Mono.fromRunnable(runnable)
|
||||
.subscribeOn(Schedulers.boundedElastic())
|
||||
.then();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private static Map<String, Object> createAttributes(HttpServletRequest servletRequest,
|
||||
|
|
|
@ -126,8 +126,11 @@ public final class OAuth2AuthorizedClientArgumentResolver implements HandlerMeth
|
|||
}
|
||||
|
||||
private Mono<Authentication> currentAuthentication() {
|
||||
return ReactiveSecurityContextHolder.getContext().map(SecurityContext::getAuthentication)
|
||||
// @formatter:off
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.map(SecurityContext::getAuthentication)
|
||||
.defaultIfEmpty(ANONYMOUS_USER_TOKEN);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<String> clientRegistrationId(Mono<Authentication> authentication) {
|
||||
|
@ -137,8 +140,11 @@ public final class OAuth2AuthorizedClientArgumentResolver implements HandlerMeth
|
|||
}
|
||||
|
||||
private Mono<ServerWebExchange> currentServerWebExchange() {
|
||||
return Mono.subscriberContext().filter((c) -> c.hasKey(ServerWebExchange.class))
|
||||
// @formatter:off
|
||||
return Mono.subscriberContext()
|
||||
.filter((c) -> c.hasKey(ServerWebExchange.class))
|
||||
.map((c) -> c.get(ServerWebExchange.class));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -120,10 +120,15 @@ public class DefaultServerOAuth2AuthorizationRequestResolver implements ServerOA
|
|||
|
||||
@Override
|
||||
public Mono<OAuth2AuthorizationRequest> resolve(ServerWebExchange exchange) {
|
||||
return this.authorizationRequestMatcher.matches(exchange).filter((matchResult) -> matchResult.isMatch())
|
||||
// @formatter:off
|
||||
return this.authorizationRequestMatcher
|
||||
.matches(exchange)
|
||||
.filter((matchResult) -> matchResult.isMatch())
|
||||
.map(ServerWebExchangeMatcher.MatchResult::getVariables)
|
||||
.map((variables) -> variables.get(DEFAULT_REGISTRATION_ID_URI_VARIABLE_NAME)).cast(String.class)
|
||||
.map((variables) -> variables.get(DEFAULT_REGISTRATION_ID_URI_VARIABLE_NAME))
|
||||
.cast(String.class)
|
||||
.flatMap((clientRegistrationId) -> resolve(exchange, clientRegistrationId));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -146,8 +151,10 @@ public class DefaultServerOAuth2AuthorizationRequestResolver implements ServerOA
|
|||
}
|
||||
|
||||
private Mono<ClientRegistration> findByRegistrationId(ServerWebExchange exchange, String clientRegistration) {
|
||||
return this.clientRegistrationRepository.findByRegistrationId(clientRegistration).switchIfEmpty(Mono
|
||||
.error(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid client registration id")));
|
||||
// @formatter:off
|
||||
return this.clientRegistrationRepository.findByRegistrationId(clientRegistration)
|
||||
.switchIfEmpty(Mono.error(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid client registration id")));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private OAuth2AuthorizationRequest authorizationRequest(ServerWebExchange exchange,
|
||||
|
@ -156,10 +163,14 @@ public class DefaultServerOAuth2AuthorizationRequestResolver implements ServerOA
|
|||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put(OAuth2ParameterNames.REGISTRATION_ID, clientRegistration.getRegistrationId());
|
||||
OAuth2AuthorizationRequest.Builder builder = getBuilder(clientRegistration, attributes);
|
||||
// @formatter:off
|
||||
builder.clientId(clientRegistration.getClientId())
|
||||
.authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri())
|
||||
.redirectUri(redirectUriStr).scopes(clientRegistration.getScopes())
|
||||
.state(this.stateGenerator.generateKey()).attributes(attributes);
|
||||
.redirectUri(redirectUriStr)
|
||||
.scopes(clientRegistration.getScopes())
|
||||
.state(this.stateGenerator.generateKey())
|
||||
.attributes(attributes);
|
||||
// @formatter:on
|
||||
|
||||
this.authorizationRequestCustomizer.accept(builder);
|
||||
|
||||
|
@ -214,8 +225,13 @@ public class DefaultServerOAuth2AuthorizationRequestResolver implements ServerOA
|
|||
private static String expandRedirectUri(ServerHttpRequest request, ClientRegistration clientRegistration) {
|
||||
Map<String, String> uriVariables = new HashMap<>();
|
||||
uriVariables.put("registrationId", clientRegistration.getRegistrationId());
|
||||
// @formatter:off
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromUri(request.getURI())
|
||||
.replacePath(request.getPath().contextPath().value()).replaceQuery(null).fragment(null).build();
|
||||
.replacePath(request.getPath().contextPath().value())
|
||||
.replaceQuery(null)
|
||||
.fragment(null)
|
||||
.build();
|
||||
// @formatter:on
|
||||
String scheme = uriComponents.getScheme();
|
||||
uriVariables.put("baseScheme", (scheme != null) ? scheme : "");
|
||||
String host = uriComponents.getHost();
|
||||
|
@ -236,8 +252,11 @@ public class DefaultServerOAuth2AuthorizationRequestResolver implements ServerOA
|
|||
action = "login";
|
||||
}
|
||||
uriVariables.put("action", action);
|
||||
return UriComponentsBuilder.fromUriString(clientRegistration.getRedirectUri()).buildAndExpand(uriVariables)
|
||||
// @formatter:off
|
||||
return UriComponentsBuilder.fromUriString(clientRegistration.getRedirectUri())
|
||||
.buildAndExpand(uriVariables)
|
||||
.toUriString();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -202,15 +202,20 @@ public class OAuth2AuthorizationCodeGrantWebFilter implements WebFilter {
|
|||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
// @formatter:off
|
||||
return this.requiresAuthenticationMatcher.matches(exchange)
|
||||
.filter(ServerWebExchangeMatcher.MatchResult::isMatch)
|
||||
.flatMap((matchResult) -> this.authenticationConverter.convert(exchange).onErrorMap(
|
||||
OAuth2AuthorizationException.class,
|
||||
(ex) -> new OAuth2AuthenticationException(ex.getError(), ex.getError().toString())))
|
||||
.flatMap((matchResult) -> this.authenticationConverter.convert(exchange)
|
||||
.onErrorMap(OAuth2AuthorizationException.class,
|
||||
(ex) -> new OAuth2AuthenticationException(ex.getError(), ex.getError().toString())
|
||||
)
|
||||
)
|
||||
.switchIfEmpty(chain.filter(exchange).then(Mono.empty()))
|
||||
.flatMap((token) -> authenticate(exchange, chain, token))
|
||||
.onErrorResume(AuthenticationException.class, (e) -> this.authenticationFailureHandler
|
||||
.onAuthenticationFailure(new WebFilterExchange(exchange, chain), e));
|
||||
.onErrorResume(AuthenticationException.class, (e) ->
|
||||
this.authenticationFailureHandler.onAuthenticationFailure(new WebFilterExchange(exchange, chain), e)
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<Void> authenticate(ServerWebExchange exchange, WebFilterChain chain, Authentication token) {
|
||||
|
@ -230,19 +235,30 @@ public class OAuth2AuthorizationCodeGrantWebFilter implements WebFilter {
|
|||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
|
||||
authenticationResult.getClientRegistration(), authenticationResult.getName(),
|
||||
authenticationResult.getAccessToken(), authenticationResult.getRefreshToken());
|
||||
// @formatter:off
|
||||
return this.authenticationSuccessHandler.onAuthenticationSuccess(webFilterExchange, authentication)
|
||||
.then(ReactiveSecurityContextHolder.getContext().map(SecurityContext::getAuthentication)
|
||||
.defaultIfEmpty(this.anonymousToken).flatMap((principal) -> this.authorizedClientRepository
|
||||
.saveAuthorizedClient(authorizedClient, principal, webFilterExchange.getExchange())));
|
||||
.then(ReactiveSecurityContextHolder.getContext()
|
||||
.map(SecurityContext::getAuthentication)
|
||||
.defaultIfEmpty(this.anonymousToken)
|
||||
.flatMap((principal) -> this.authorizedClientRepository
|
||||
.saveAuthorizedClient(authorizedClient, principal, webFilterExchange.getExchange())
|
||||
)
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<ServerWebExchangeMatcher.MatchResult> matchesAuthorizationResponse(ServerWebExchange exchange) {
|
||||
return Mono.just(exchange).filter(
|
||||
(exch) -> OAuth2AuthorizationResponseUtils.isAuthorizationResponse(exch.getRequest().getQueryParams()))
|
||||
// @formatter:off
|
||||
return Mono.just(exchange)
|
||||
.filter((exch) ->
|
||||
OAuth2AuthorizationResponseUtils.isAuthorizationResponse(exch.getRequest().getQueryParams())
|
||||
)
|
||||
.flatMap((exch) -> this.authorizationRequestRepository.loadAuthorizationRequest(exchange)
|
||||
.flatMap((authorizationRequest) -> matchesRedirectUri(exch.getRequest().getURI(),
|
||||
authorizationRequest.getRedirectUri())))
|
||||
authorizationRequest.getRedirectUri()))
|
||||
)
|
||||
.switchIfEmpty(ServerWebExchangeMatcher.MatchResult.notMatch());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private static Mono<ServerWebExchangeMatcher.MatchResult> matchesRedirectUri(URI authorizationResponseUri,
|
||||
|
|
|
@ -127,12 +127,15 @@ public class OAuth2AuthorizationRequestRedirectWebFilter implements WebFilter {
|
|||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
// @formatter:off
|
||||
return this.authorizationRequestResolver.resolve(exchange)
|
||||
.switchIfEmpty(chain.filter(exchange).then(Mono.empty()))
|
||||
.onErrorResume(ClientAuthorizationRequiredException.class,
|
||||
(ex) -> this.requestCache.saveRequest(exchange).then(
|
||||
this.authorizationRequestResolver.resolve(exchange, ex.getClientRegistrationId())))
|
||||
this.authorizationRequestResolver.resolve(exchange, ex.getClientRegistrationId()))
|
||||
)
|
||||
.flatMap((clientRegistration) -> sendRedirectForAuthorization(exchange, clientRegistration));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<Void> sendRedirectForAuthorization(ServerWebExchange exchange,
|
||||
|
@ -143,8 +146,11 @@ public class OAuth2AuthorizationRequestRedirectWebFilter implements WebFilter {
|
|||
saveAuthorizationRequest = this.authorizationRequestRepository
|
||||
.saveAuthorizationRequest(authorizationRequest, exchange);
|
||||
}
|
||||
// @formatter:off
|
||||
URI redirectUri = UriComponentsBuilder.fromUriString(authorizationRequest.getAuthorizationRequestUri())
|
||||
.build(true).toUri();
|
||||
.build(true)
|
||||
.toUri();
|
||||
// @formatter:on
|
||||
return saveAuthorizationRequest
|
||||
.then(this.authorizationRedirectStrategy.sendRedirect(exchange, redirectUri));
|
||||
});
|
||||
|
|
|
@ -71,8 +71,14 @@ final class OAuth2AuthorizationResponseUtils {
|
|||
}
|
||||
String errorDescription = request.getFirst(OAuth2ParameterNames.ERROR_DESCRIPTION);
|
||||
String errorUri = request.getFirst(OAuth2ParameterNames.ERROR_URI);
|
||||
return OAuth2AuthorizationResponse.error(errorCode).redirectUri(redirectUri).errorDescription(errorDescription)
|
||||
.errorUri(errorUri).state(state).build();
|
||||
// @formatter:off
|
||||
return OAuth2AuthorizationResponse.error(errorCode)
|
||||
.redirectUri(redirectUri)
|
||||
.errorDescription(errorDescription)
|
||||
.errorUri(errorUri)
|
||||
.state(state)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -70,9 +70,11 @@ public class ServerOAuth2AuthorizationCodeAuthenticationTokenConverter implement
|
|||
|
||||
@Override
|
||||
public Mono<Authentication> convert(ServerWebExchange serverWebExchange) {
|
||||
// @formatter:off
|
||||
return this.authorizationRequestRepository.removeAuthorizationRequest(serverWebExchange)
|
||||
.switchIfEmpty(oauth2AuthorizationException(AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE))
|
||||
.flatMap((authorizationRequest) -> authenticationRequest(serverWebExchange, authorizationRequest));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private <T> Mono<T> oauth2AuthorizationException(String errorCode) {
|
||||
|
@ -84,13 +86,16 @@ public class ServerOAuth2AuthorizationCodeAuthenticationTokenConverter implement
|
|||
|
||||
private Mono<OAuth2AuthorizationCodeAuthenticationToken> authenticationRequest(ServerWebExchange exchange,
|
||||
OAuth2AuthorizationRequest authorizationRequest) {
|
||||
return Mono.just(authorizationRequest).map(OAuth2AuthorizationRequest::getAttributes).flatMap((attributes) -> {
|
||||
String id = (String) attributes.get(OAuth2ParameterNames.REGISTRATION_ID);
|
||||
if (id == null) {
|
||||
return oauth2AuthorizationException(CLIENT_REGISTRATION_NOT_FOUND_ERROR_CODE);
|
||||
}
|
||||
return this.clientRegistrationRepository.findByRegistrationId(id);
|
||||
}).switchIfEmpty(oauth2AuthorizationException(CLIENT_REGISTRATION_NOT_FOUND_ERROR_CODE))
|
||||
// @formatter:off
|
||||
return Mono.just(authorizationRequest)
|
||||
.map(OAuth2AuthorizationRequest::getAttributes).flatMap((attributes) -> {
|
||||
String id = (String) attributes.get(OAuth2ParameterNames.REGISTRATION_ID);
|
||||
if (id == null) {
|
||||
return oauth2AuthorizationException(CLIENT_REGISTRATION_NOT_FOUND_ERROR_CODE);
|
||||
}
|
||||
return this.clientRegistrationRepository.findByRegistrationId(id);
|
||||
})
|
||||
.switchIfEmpty(oauth2AuthorizationException(CLIENT_REGISTRATION_NOT_FOUND_ERROR_CODE))
|
||||
.map((clientRegistration) -> {
|
||||
OAuth2AuthorizationResponse authorizationResponse = convertResponse(exchange);
|
||||
OAuth2AuthorizationCodeAuthenticationToken authenticationRequest = new OAuth2AuthorizationCodeAuthenticationToken(
|
||||
|
@ -98,6 +103,7 @@ public class ServerOAuth2AuthorizationCodeAuthenticationTokenConverter implement
|
|||
new OAuth2AuthorizationExchange(authorizationRequest, authorizationResponse));
|
||||
return authenticationRequest;
|
||||
});
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private static OAuth2AuthorizationResponse convertResponse(ServerWebExchange exchange) {
|
||||
|
|
|
@ -52,19 +52,23 @@ public final class WebSessionOAuth2ServerAuthorizationRequestRepository
|
|||
if (state == null) {
|
||||
return Mono.empty();
|
||||
}
|
||||
// @formatter:off
|
||||
return getStateToAuthorizationRequest(exchange)
|
||||
.filter((stateToAuthorizationRequest) -> stateToAuthorizationRequest.containsKey(state))
|
||||
.map((stateToAuthorizationRequest) -> stateToAuthorizationRequest.get(state));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> saveAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest,
|
||||
ServerWebExchange exchange) {
|
||||
Assert.notNull(authorizationRequest, "authorizationRequest cannot be null");
|
||||
// @formatter:off
|
||||
return saveStateToAuthorizationRequest(exchange)
|
||||
.doOnNext((stateToAuthorizationRequest) -> stateToAuthorizationRequest
|
||||
.put(authorizationRequest.getState(), authorizationRequest))
|
||||
.then();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -73,29 +77,33 @@ public final class WebSessionOAuth2ServerAuthorizationRequestRepository
|
|||
if (state == null) {
|
||||
return Mono.empty();
|
||||
}
|
||||
return exchange.getSession().map(WebSession::getAttributes).handle((sessionAttrs, sink) -> {
|
||||
Map<String, OAuth2AuthorizationRequest> stateToAuthzRequest = sessionAttrsMapStateToAuthorizationRequest(
|
||||
sessionAttrs);
|
||||
if (stateToAuthzRequest == null) {
|
||||
sink.complete();
|
||||
return;
|
||||
}
|
||||
OAuth2AuthorizationRequest removedValue = stateToAuthzRequest.remove(state);
|
||||
if (stateToAuthzRequest.isEmpty()) {
|
||||
sessionAttrs.remove(this.sessionAttributeName);
|
||||
}
|
||||
else if (removedValue != null) {
|
||||
// gh-7327 Overwrite the existing Map to ensure the state is saved for
|
||||
// distributed sessions
|
||||
sessionAttrs.put(this.sessionAttributeName, stateToAuthzRequest);
|
||||
}
|
||||
if (removedValue == null) {
|
||||
sink.complete();
|
||||
}
|
||||
else {
|
||||
sink.next(removedValue);
|
||||
}
|
||||
});
|
||||
// @formatter:off
|
||||
return exchange.getSession()
|
||||
.map(WebSession::getAttributes)
|
||||
.handle((sessionAttrs, sink) -> {
|
||||
Map<String, OAuth2AuthorizationRequest> stateToAuthzRequest = sessionAttrsMapStateToAuthorizationRequest(
|
||||
sessionAttrs);
|
||||
if (stateToAuthzRequest == null) {
|
||||
sink.complete();
|
||||
return;
|
||||
}
|
||||
OAuth2AuthorizationRequest removedValue = stateToAuthzRequest.remove(state);
|
||||
if (stateToAuthzRequest.isEmpty()) {
|
||||
sessionAttrs.remove(this.sessionAttributeName);
|
||||
}
|
||||
else if (removedValue != null) {
|
||||
// gh-7327 Overwrite the existing Map to ensure the state is saved for
|
||||
// distributed sessions
|
||||
sessionAttrs.put(this.sessionAttributeName, stateToAuthzRequest);
|
||||
}
|
||||
if (removedValue == null) {
|
||||
sink.complete();
|
||||
}
|
||||
else {
|
||||
sink.next(removedValue);
|
||||
}
|
||||
});
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,22 +123,28 @@ public final class WebSessionOAuth2ServerAuthorizationRequestRepository
|
|||
private Mono<Map<String, OAuth2AuthorizationRequest>> getStateToAuthorizationRequest(ServerWebExchange exchange) {
|
||||
Assert.notNull(exchange, "exchange cannot be null");
|
||||
|
||||
return getSessionAttributes(exchange).flatMap(
|
||||
(sessionAttrs) -> Mono.justOrEmpty(this.sessionAttrsMapStateToAuthorizationRequest(sessionAttrs)));
|
||||
// @formatter:off
|
||||
return getSessionAttributes(exchange)
|
||||
.flatMap((sessionAttrs) -> Mono.justOrEmpty(this.sessionAttrsMapStateToAuthorizationRequest(sessionAttrs)));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<Map<String, OAuth2AuthorizationRequest>> saveStateToAuthorizationRequest(ServerWebExchange exchange) {
|
||||
Assert.notNull(exchange, "exchange cannot be null");
|
||||
return getSessionAttributes(exchange).doOnNext((sessionAttrs) -> {
|
||||
Object stateToAuthzRequest = sessionAttrs.get(this.sessionAttributeName);
|
||||
if (stateToAuthzRequest == null) {
|
||||
stateToAuthzRequest = new HashMap<String, OAuth2AuthorizationRequest>();
|
||||
}
|
||||
// No matter stateToAuthzRequest was in session or not, we should always put
|
||||
// it into session again
|
||||
// in case of redis or hazelcast session. #6215
|
||||
sessionAttrs.put(this.sessionAttributeName, stateToAuthzRequest);
|
||||
}).flatMap((sessionAttrs) -> Mono.justOrEmpty(this.sessionAttrsMapStateToAuthorizationRequest(sessionAttrs)));
|
||||
// @formatter:off
|
||||
return getSessionAttributes(exchange)
|
||||
.doOnNext((sessionAttrs) -> {
|
||||
Object stateToAuthzRequest = sessionAttrs.get(this.sessionAttributeName);
|
||||
if (stateToAuthzRequest == null) {
|
||||
stateToAuthzRequest = new HashMap<String, OAuth2AuthorizationRequest>();
|
||||
}
|
||||
// No matter stateToAuthzRequest was in session or not, we should always put
|
||||
// it into session again
|
||||
// in case of redis or hazelcast session. #6215
|
||||
sessionAttrs.put(this.sessionAttributeName, stateToAuthzRequest);
|
||||
})
|
||||
.flatMap((sessionAttrs) -> Mono.justOrEmpty(this.sessionAttrsMapStateToAuthorizationRequest(sessionAttrs)));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Map<String, OAuth2AuthorizationRequest> sessionAttrsMapStateToAuthorizationRequest(
|
||||
|
|
|
@ -50,8 +50,11 @@ public final class WebSessionServerOAuth2AuthorizedClientRepository implements S
|
|||
Authentication principal, ServerWebExchange exchange) {
|
||||
Assert.hasText(clientRegistrationId, "clientRegistrationId cannot be empty");
|
||||
Assert.notNull(exchange, "exchange cannot be null");
|
||||
return exchange.getSession().map(this::getAuthorizedClients)
|
||||
// @formatter:off
|
||||
return exchange.getSession()
|
||||
.map(this::getAuthorizedClients)
|
||||
.flatMap((clients) -> Mono.justOrEmpty((T) clients.get(clientRegistrationId)));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -59,11 +62,15 @@ public final class WebSessionServerOAuth2AuthorizedClientRepository implements S
|
|||
ServerWebExchange exchange) {
|
||||
Assert.notNull(authorizedClient, "authorizedClient cannot be null");
|
||||
Assert.notNull(exchange, "exchange cannot be null");
|
||||
return exchange.getSession().doOnSuccess((session) -> {
|
||||
Map<String, OAuth2AuthorizedClient> authorizedClients = getAuthorizedClients(session);
|
||||
authorizedClients.put(authorizedClient.getClientRegistration().getRegistrationId(), authorizedClient);
|
||||
session.getAttributes().put(this.sessionAttributeName, authorizedClients);
|
||||
}).then(Mono.empty());
|
||||
// @formatter:off
|
||||
return exchange.getSession()
|
||||
.doOnSuccess((session) -> {
|
||||
Map<String, OAuth2AuthorizedClient> authorizedClients = getAuthorizedClients(session);
|
||||
authorizedClients.put(authorizedClient.getClientRegistration().getRegistrationId(), authorizedClient);
|
||||
session.getAttributes().put(this.sessionAttributeName, authorizedClients);
|
||||
})
|
||||
.then(Mono.empty());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,16 +78,20 @@ public final class WebSessionServerOAuth2AuthorizedClientRepository implements S
|
|||
ServerWebExchange exchange) {
|
||||
Assert.hasText(clientRegistrationId, "clientRegistrationId cannot be empty");
|
||||
Assert.notNull(exchange, "exchange cannot be null");
|
||||
return exchange.getSession().doOnSuccess((session) -> {
|
||||
Map<String, OAuth2AuthorizedClient> authorizedClients = getAuthorizedClients(session);
|
||||
authorizedClients.remove(clientRegistrationId);
|
||||
if (authorizedClients.isEmpty()) {
|
||||
session.getAttributes().remove(this.sessionAttributeName);
|
||||
}
|
||||
else {
|
||||
session.getAttributes().put(this.sessionAttributeName, authorizedClients);
|
||||
}
|
||||
}).then(Mono.empty());
|
||||
// @formatter:off
|
||||
return exchange.getSession()
|
||||
.doOnSuccess((session) -> {
|
||||
Map<String, OAuth2AuthorizedClient> authorizedClients = getAuthorizedClients(session);
|
||||
authorizedClients.remove(clientRegistrationId);
|
||||
if (authorizedClients.isEmpty()) {
|
||||
session.getAttributes().remove(this.sessionAttributeName);
|
||||
}
|
||||
else {
|
||||
session.getAttributes().put(this.sessionAttributeName, authorizedClients);
|
||||
}
|
||||
})
|
||||
.then(Mono.empty());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -61,9 +61,11 @@ public class OAuth2LoginAuthenticationWebFilter extends AuthenticationWebFilter
|
|||
OAuth2AuthenticationToken result = new OAuth2AuthenticationToken(authenticationResult.getPrincipal(),
|
||||
authenticationResult.getAuthorities(),
|
||||
authenticationResult.getClientRegistration().getRegistrationId());
|
||||
// @formatter:off
|
||||
return this.authorizedClientRepository
|
||||
.saveAuthorizedClient(authorizedClient, authenticationResult, webFilterExchange.getExchange())
|
||||
.then(super.onAuthenticationSuccess(result, webFilterExchange));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -61,22 +61,31 @@ public class AuthorizationCodeOAuth2AuthorizedClientProviderTests {
|
|||
@Test
|
||||
public void authorizeWhenNotAuthorizationCodeThenUnableToAuthorize() {
|
||||
ClientRegistration clientCredentialsClient = TestClientRegistrations.clientCredentials().build();
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(clientCredentialsClient).principal(this.principal).build();
|
||||
.withClientRegistration(clientCredentialsClient).principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenAuthorizationCodeAndAuthorizedThenNotAuthorize() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(this.authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(this.authorizedClient).principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenAuthorizationCodeAndNotAuthorizedThenAuthorize() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistration).principal(this.principal).build();
|
||||
.withClientRegistration(this.clientRegistration).principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThatExceptionOfType(ClientAuthorizationRequiredException.class)
|
||||
.isThrownBy(() -> this.authorizedClientProvider.authorize(authorizationContext));
|
||||
}
|
||||
|
|
|
@ -61,22 +61,34 @@ public class AuthorizationCodeReactiveOAuth2AuthorizedClientProviderTests {
|
|||
@Test
|
||||
public void authorizeWhenNotAuthorizationCodeThenUnableToAuthorize() {
|
||||
ClientRegistration clientCredentialsClient = TestClientRegistrations.clientCredentials().build();
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(clientCredentialsClient).principal(this.principal).build();
|
||||
.withClientRegistration(clientCredentialsClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext).block()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenAuthorizationCodeAndAuthorizedThenNotAuthorize() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(this.authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext).block()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenAuthorizationCodeAndNotAuthorizedThenAuthorize() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistration).principal(this.principal).build();
|
||||
.withClientRegistration(this.clientRegistration)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThatExceptionOfType(ClientAuthorizationRequiredException.class)
|
||||
.isThrownBy(() -> this.authorizedClientProvider.authorize(authorizationContext).block());
|
||||
}
|
||||
|
|
|
@ -108,58 +108,78 @@ public class AuthorizedClientServiceOAuth2AuthorizedClientManagerTests {
|
|||
|
||||
@Test
|
||||
public void constructorWhenClientRegistrationRepositoryIsNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> new AuthorizedClientServiceOAuth2AuthorizedClientManager(null, this.authorizedClientService))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new AuthorizedClientServiceOAuth2AuthorizedClientManager(null, this.authorizedClientService))
|
||||
.withMessage("clientRegistrationRepository cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenOAuth2AuthorizedClientServiceIsNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> new AuthorizedClientServiceOAuth2AuthorizedClientManager(this.clientRegistrationRepository, null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new AuthorizedClientServiceOAuth2AuthorizedClientManager(this.clientRegistrationRepository, null))
|
||||
.withMessage("authorizedClientService cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthorizedClientProviderWhenNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientManager.setAuthorizedClientProvider(null))
|
||||
.withMessage("authorizedClientProvider cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setContextAttributesMapperWhenNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientManager.setContextAttributesMapper(null))
|
||||
.withMessage("contextAttributesMapper cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthorizationSuccessHandlerWhenNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientManager.setAuthorizationSuccessHandler(null))
|
||||
.withMessage("authorizationSuccessHandler cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthorizationFailureHandlerWhenNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientManager.setAuthorizationFailureHandler(null))
|
||||
.withMessage("authorizationFailureHandler cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenRequestIsNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientManager.authorize(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientManager.authorize(null))
|
||||
.withMessage("authorizeRequest cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenClientRegistrationNotFoundThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId("invalid-registration-id").principal(this.principal).build();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientManager.authorize(authorizeRequest))
|
||||
.withClientRegistrationId("invalid-registration-id")
|
||||
|
||||
.principal(this.principal).build();
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientManager.authorize(authorizeRequest))
|
||||
.withMessage("Could not find ClientRegistration with id 'invalid-registration-id'");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -189,9 +209,12 @@ public class AuthorizedClientServiceOAuth2AuthorizedClientManagerTests {
|
|||
.willReturn(this.clientRegistration);
|
||||
given(this.authorizedClientProvider.authorize(any(OAuth2AuthorizationContext.class)))
|
||||
.willReturn(this.authorizedClient);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
|
||||
verify(this.authorizedClientProvider).authorize(this.authorizationContextCaptor.capture());
|
||||
verify(this.contextAttributesMapper).apply(eq(authorizeRequest));
|
||||
|
@ -216,9 +239,12 @@ public class AuthorizedClientServiceOAuth2AuthorizedClientManagerTests {
|
|||
this.principal.getName(), TestOAuth2AccessTokens.noScopes(), TestOAuth2RefreshTokens.refreshToken());
|
||||
given(this.authorizedClientProvider.authorize(any(OAuth2AuthorizationContext.class)))
|
||||
.willReturn(reauthorizedClient);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
|
||||
verify(this.authorizedClientProvider).authorize(this.authorizationContextCaptor.capture());
|
||||
verify(this.contextAttributesMapper).apply(eq(authorizeRequest));
|
||||
|
@ -324,11 +350,15 @@ public class AuthorizedClientServiceOAuth2AuthorizedClientManagerTests {
|
|||
new OAuth2Error("non-matching-error-code", null, null), this.clientRegistration.getRegistrationId());
|
||||
given(this.authorizedClientProvider.authorize(any(OAuth2AuthorizationContext.class)))
|
||||
.willThrow(authorizationException);
|
||||
OAuth2AuthorizeRequest reauthorizeRequest = OAuth2AuthorizeRequest.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal).build();
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest reauthorizeRequest = OAuth2AuthorizeRequest
|
||||
.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
assertThatExceptionOfType(ClientAuthorizationException.class)
|
||||
.isThrownBy(() -> this.authorizedClientManager.authorize(reauthorizeRequest))
|
||||
.isEqualTo(authorizationException);
|
||||
// @formatter:on
|
||||
verify(this.authorizationFailureHandler).onAuthorizationFailure(eq(authorizationException), eq(this.principal),
|
||||
any());
|
||||
verifyNoInteractions(this.authorizedClientService);
|
||||
|
|
|
@ -170,9 +170,12 @@ public class AuthorizedClientServiceReactiveOAuth2AuthorizedClientManagerTests {
|
|||
.willReturn(Mono.just(this.clientRegistration));
|
||||
given(this.authorizedClientService.loadAuthorizedClient(any(), any())).willReturn(Mono.empty());
|
||||
given(this.authorizedClientProvider.authorize(any())).willReturn(Mono.empty());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
Mono<OAuth2AuthorizedClient> authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
|
||||
StepVerifier.create(authorizedClient).verifyComplete();
|
||||
verify(this.authorizedClientProvider).authorize(this.authorizationContextCaptor.capture());
|
||||
|
@ -217,9 +220,12 @@ public class AuthorizedClientServiceReactiveOAuth2AuthorizedClientManagerTests {
|
|||
given(this.authorizedClientService.loadAuthorizedClient(any(), any())).willReturn(Mono.empty());
|
||||
given(this.authorizedClientProvider.authorize(any(OAuth2AuthorizationContext.class)))
|
||||
.willReturn(Mono.just(this.authorizedClient));
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
PublisherProbe<Void> authorizationSuccessHandlerProbe = PublisherProbe.empty();
|
||||
this.authorizedClientManager.setAuthorizationSuccessHandler(
|
||||
(client, principal, attributes) -> authorizationSuccessHandlerProbe.mono());
|
||||
|
@ -241,9 +247,12 @@ public class AuthorizedClientServiceReactiveOAuth2AuthorizedClientManagerTests {
|
|||
given(this.clientRegistrationRepository.findByRegistrationId(eq(this.clientRegistration.getRegistrationId())))
|
||||
.willReturn(Mono.just(this.clientRegistration));
|
||||
given(this.authorizedClientService.loadAuthorizedClient(any(), any())).willReturn(Mono.empty());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
ClientAuthorizationException exception = new ClientAuthorizationException(
|
||||
new OAuth2Error(OAuth2ErrorCodes.INVALID_TOKEN, null, null),
|
||||
this.clientRegistration.getRegistrationId());
|
||||
|
@ -269,9 +278,12 @@ public class AuthorizedClientServiceReactiveOAuth2AuthorizedClientManagerTests {
|
|||
given(this.clientRegistrationRepository.findByRegistrationId(eq(this.clientRegistration.getRegistrationId())))
|
||||
.willReturn(Mono.just(this.clientRegistration));
|
||||
given(this.authorizedClientService.loadAuthorizedClient(any(), any())).willReturn(Mono.empty());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
ClientAuthorizationException exception = new ClientAuthorizationException(
|
||||
new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT, null, null),
|
||||
this.clientRegistration.getRegistrationId());
|
||||
|
@ -297,9 +309,12 @@ public class AuthorizedClientServiceReactiveOAuth2AuthorizedClientManagerTests {
|
|||
given(this.clientRegistrationRepository.findByRegistrationId(eq(this.clientRegistration.getRegistrationId())))
|
||||
.willReturn(Mono.just(this.clientRegistration));
|
||||
given(this.authorizedClientService.loadAuthorizedClient(any(), any())).willReturn(Mono.empty());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
ClientAuthorizationException exception = new ClientAuthorizationException(
|
||||
new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR, null, null),
|
||||
this.clientRegistration.getRegistrationId());
|
||||
|
@ -323,9 +338,12 @@ public class AuthorizedClientServiceReactiveOAuth2AuthorizedClientManagerTests {
|
|||
given(this.clientRegistrationRepository.findByRegistrationId(eq(this.clientRegistration.getRegistrationId())))
|
||||
.willReturn(Mono.just(this.clientRegistration));
|
||||
given(this.authorizedClientService.loadAuthorizedClient(any(), any())).willReturn(Mono.empty());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationException exception = new OAuth2AuthorizationException(
|
||||
new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT, null, null));
|
||||
given(this.authorizedClientProvider.authorize(any(OAuth2AuthorizationContext.class)))
|
||||
|
@ -348,9 +366,12 @@ public class AuthorizedClientServiceReactiveOAuth2AuthorizedClientManagerTests {
|
|||
given(this.clientRegistrationRepository.findByRegistrationId(eq(this.clientRegistration.getRegistrationId())))
|
||||
.willReturn(Mono.just(this.clientRegistration));
|
||||
given(this.authorizedClientService.loadAuthorizedClient(any(), any())).willReturn(Mono.empty());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationException exception = new OAuth2AuthorizationException(
|
||||
new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT, null, null));
|
||||
given(this.authorizedClientProvider.authorize(any(OAuth2AuthorizationContext.class)))
|
||||
|
@ -387,7 +408,11 @@ public class AuthorizedClientServiceReactiveOAuth2AuthorizedClientManagerTests {
|
|||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.build();
|
||||
Mono<OAuth2AuthorizedClient> authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
|
||||
StepVerifier.create(authorizedClient).expectNext(reauthorizedClient).verifyComplete();
|
||||
// @formatter:off
|
||||
StepVerifier.create(authorizedClient)
|
||||
.expectNext(reauthorizedClient)
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
verify(this.authorizedClientProvider).authorize(this.authorizationContextCaptor.capture());
|
||||
verify(this.contextAttributesMapper).apply(eq(authorizeRequest));
|
||||
OAuth2AuthorizationContext authorizationContext = this.authorizationContextCaptor.getValue();
|
||||
|
@ -403,8 +428,11 @@ public class AuthorizedClientServiceReactiveOAuth2AuthorizedClientManagerTests {
|
|||
@Test
|
||||
public void reauthorizeWhenUnsupportedProviderThenNotReauthorized() {
|
||||
given(this.authorizedClientProvider.authorize(any(OAuth2AuthorizationContext.class))).willReturn(Mono.empty());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest reauthorizeRequest = OAuth2AuthorizeRequest.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal).build();
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
Mono<OAuth2AuthorizedClient> authorizedClient = this.authorizedClientManager.authorize(reauthorizeRequest);
|
||||
StepVerifier.create(authorizedClient).expectNext(this.authorizedClient).verifyComplete();
|
||||
verify(this.authorizedClientProvider).authorize(this.authorizationContextCaptor.capture());
|
||||
|
@ -424,8 +452,11 @@ public class AuthorizedClientServiceReactiveOAuth2AuthorizedClientManagerTests {
|
|||
this.principal.getName(), TestOAuth2AccessTokens.noScopes(), TestOAuth2RefreshTokens.refreshToken());
|
||||
given(this.authorizedClientProvider.authorize(any(OAuth2AuthorizationContext.class)))
|
||||
.willReturn(Mono.just(reauthorizedClient));
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest reauthorizeRequest = OAuth2AuthorizeRequest.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal).build();
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
Mono<OAuth2AuthorizedClient> authorizedClient = this.authorizedClientManager.authorize(reauthorizeRequest);
|
||||
StepVerifier.create(authorizedClient).expectNext(reauthorizedClient).verifyComplete();
|
||||
verify(this.authorizedClientProvider).authorize(this.authorizationContextCaptor.capture());
|
||||
|
@ -451,7 +482,11 @@ public class AuthorizedClientServiceReactiveOAuth2AuthorizedClientManagerTests {
|
|||
this.authorizedClientManager.setContextAttributesMapper(
|
||||
new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager.DefaultContextAttributesMapper());
|
||||
Mono<OAuth2AuthorizedClient> authorizedClient = this.authorizedClientManager.authorize(reauthorizeRequest);
|
||||
StepVerifier.create(authorizedClient).expectNext(reauthorizedClient).verifyComplete();
|
||||
// @formatter:off
|
||||
StepVerifier.create(authorizedClient)
|
||||
.expectNext(reauthorizedClient)
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
verify(this.authorizedClientService).saveAuthorizedClient(eq(reauthorizedClient), eq(this.principal));
|
||||
this.saveAuthorizedClientProbe.assertWasSubscribed();
|
||||
verify(this.authorizedClientService, never()).removeAuthorizedClient(any(), any());
|
||||
|
|
|
@ -65,41 +65,58 @@ public class ClientCredentialsOAuth2AuthorizedClientProviderTests {
|
|||
|
||||
@Test
|
||||
public void setAccessTokenResponseClientWhenClientIsNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setAccessTokenResponseClient(null))
|
||||
.isInstanceOf(IllegalArgumentException.class).withMessage("accessTokenResponseClient cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockSkewWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.setClockSkew(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClockSkew(null))
|
||||
.withMessage("clockSkew cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockSkewWhenNegativeSecondsThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClockSkew(Duration.ofSeconds(-1)))
|
||||
.withMessage("clockSkew must be >= 0");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.setClock(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClock(null))
|
||||
.withMessage("clock cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenContextIsNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.authorize(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.authorize(null))
|
||||
.withMessage("context cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenNotClientCredentialsThenUnableToAuthorize() {
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(clientRegistration).principal(this.principal).build();
|
||||
.withClientRegistration(clientRegistration)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext)).isNull();
|
||||
}
|
||||
|
||||
|
@ -107,8 +124,12 @@ public class ClientCredentialsOAuth2AuthorizedClientProviderTests {
|
|||
public void authorizeWhenClientCredentialsAndNotAuthorizedThenAuthorize() {
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse().build();
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(accessTokenResponse);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistration).principal(this.principal).build();
|
||||
.withClientRegistration(this.clientRegistration)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = this.authorizedClientProvider.authorize(authorizationContext);
|
||||
assertThat(authorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principal.getName());
|
||||
|
@ -125,8 +146,12 @@ public class ClientCredentialsOAuth2AuthorizedClientProviderTests {
|
|||
this.principal.getName(), accessToken);
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse().build();
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(accessTokenResponse);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
authorizedClient = this.authorizedClientProvider.authorize(authorizationContext);
|
||||
assertThat(authorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principal.getName());
|
||||
|
@ -137,8 +162,12 @@ public class ClientCredentialsOAuth2AuthorizedClientProviderTests {
|
|||
public void authorizeWhenClientCredentialsAndTokenNotExpiredThenNotReauthorize() {
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.clientRegistration,
|
||||
this.principal.getName(), TestOAuth2AccessTokens.noScopes());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext)).isNull();
|
||||
}
|
||||
|
||||
|
@ -157,8 +186,12 @@ public class ClientCredentialsOAuth2AuthorizedClientProviderTests {
|
|||
this.authorizedClientProvider.setClockSkew(Duration.ofSeconds(90));
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse().build();
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(accessTokenResponse);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient reauthorizedClient = this.authorizedClientProvider.authorize(authorizationContext);
|
||||
assertThat(reauthorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
assertThat(reauthorizedClient.getPrincipalName()).isEqualTo(this.principal.getName());
|
||||
|
|
|
@ -66,41 +66,58 @@ public class ClientCredentialsReactiveOAuth2AuthorizedClientProviderTests {
|
|||
|
||||
@Test
|
||||
public void setAccessTokenResponseClientWhenClientIsNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setAccessTokenResponseClient(null))
|
||||
.withMessage("accessTokenResponseClient cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockSkewWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.setClockSkew(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClockSkew(null))
|
||||
.withMessage("clockSkew cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockSkewWhenNegativeSecondsThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClockSkew(Duration.ofSeconds(-1)))
|
||||
.withMessage("clockSkew must be >= 0");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.setClock(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClock(null))
|
||||
.withMessage("clock cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenContextIsNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.authorize(null).block())
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.authorize(null).block())
|
||||
.withMessage("context cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenNotClientCredentialsThenUnableToAuthorize() {
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(clientRegistration).principal(this.principal).build();
|
||||
.withClientRegistration(clientRegistration)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext).block()).isNull();
|
||||
}
|
||||
|
||||
|
@ -108,8 +125,12 @@ public class ClientCredentialsReactiveOAuth2AuthorizedClientProviderTests {
|
|||
public void authorizeWhenClientCredentialsAndNotAuthorizedThenAuthorize() {
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse().build();
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(Mono.just(accessTokenResponse));
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistration).principal(this.principal).build();
|
||||
.withClientRegistration(this.clientRegistration)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = this.authorizedClientProvider.authorize(authorizationContext).block();
|
||||
assertThat(authorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principal.getName());
|
||||
|
@ -126,8 +147,12 @@ public class ClientCredentialsReactiveOAuth2AuthorizedClientProviderTests {
|
|||
this.principal.getName(), accessToken);
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse().build();
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(Mono.just(accessTokenResponse));
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
authorizedClient = this.authorizedClientProvider.authorize(authorizationContext).block();
|
||||
assertThat(authorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principal.getName());
|
||||
|
@ -138,8 +163,12 @@ public class ClientCredentialsReactiveOAuth2AuthorizedClientProviderTests {
|
|||
public void authorizeWhenClientCredentialsAndTokenNotExpiredThenNotReauthorize() {
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.clientRegistration,
|
||||
this.principal.getName(), TestOAuth2AccessTokens.noScopes());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext).block()).isNull();
|
||||
}
|
||||
|
||||
|
@ -158,8 +187,12 @@ public class ClientCredentialsReactiveOAuth2AuthorizedClientProviderTests {
|
|||
this.authorizedClientProvider.setClockSkew(Duration.ofSeconds(90));
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse().build();
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(Mono.just(accessTokenResponse));
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient reauthorizedClient = this.authorizedClientProvider.authorize(authorizationContext)
|
||||
.block();
|
||||
assertThat(reauthorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
|
|
|
@ -67,9 +67,11 @@ public class InMemoryOAuth2AuthorizedClientServiceTests {
|
|||
|
||||
@Test
|
||||
public void constructorWhenAuthorizedClientsIsNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new InMemoryOAuth2AuthorizedClientService(this.clientRegistrationRepository, null))
|
||||
.withMessage("authorizedClients cannot be empty");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -59,13 +59,21 @@ public class InMemoryReactiveOAuth2AuthorizedClientServiceTests {
|
|||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "token", Instant.now(),
|
||||
Instant.now().plus(Duration.ofDays(1)));
|
||||
|
||||
// @formatter:off
|
||||
private ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(this.clientRegistrationId)
|
||||
.redirectUri("{baseUrl}/{action}/oauth2/code/{registrationId}")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).scope("read:user")
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.scope("read:user")
|
||||
.authorizationUri("https://github.com/login/oauth/authorize")
|
||||
.tokenUri("https://github.com/login/oauth/access_token").userInfoUri("https://api.github.com/user")
|
||||
.userNameAttributeName("id").clientName("GitHub").clientId("clientId").clientSecret("clientSecret").build();
|
||||
.tokenUri("https://github.com/login/oauth/access_token")
|
||||
.userInfoUri("https://api.github.com/user")
|
||||
.userNameAttributeName("id")
|
||||
.clientName("GitHub")
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.build();
|
||||
// @formatter:on
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
@ -83,29 +91,37 @@ public class InMemoryReactiveOAuth2AuthorizedClientServiceTests {
|
|||
@Test
|
||||
public void loadAuthorizedClientWhenClientRegistrationIdNullThenIllegalArgumentException() {
|
||||
this.clientRegistrationId = null;
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadAuthorizedClientWhenClientRegistrationIdEmptyThenIllegalArgumentException() {
|
||||
this.clientRegistrationId = "";
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadAuthorizedClientWhenPrincipalNameNullThenIllegalArgumentException() {
|
||||
this.principalName = null;
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadAuthorizedClientWhenPrincipalNameEmptyThenIllegalArgumentException() {
|
||||
this.principalName = "";
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -132,17 +148,23 @@ public class InMemoryReactiveOAuth2AuthorizedClientServiceTests {
|
|||
.willReturn(Mono.just(this.clientRegistration));
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.clientRegistration,
|
||||
this.principalName, this.accessToken);
|
||||
// @formatter:off
|
||||
Mono<OAuth2AuthorizedClient> saveAndLoad = this.authorizedClientService
|
||||
.saveAuthorizedClient(authorizedClient, this.principal)
|
||||
.then(this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
StepVerifier.create(saveAndLoad).expectNext(authorizedClient).verifyComplete();
|
||||
StepVerifier.create(saveAndLoad)
|
||||
.expectNext(authorizedClient)
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveAuthorizedClientWhenAuthorizedClientNullThenIllegalArgumentException() {
|
||||
OAuth2AuthorizedClient authorizedClient = null;
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService.saveAuthorizedClient(authorizedClient, this.principal));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -150,36 +172,46 @@ public class InMemoryReactiveOAuth2AuthorizedClientServiceTests {
|
|||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.clientRegistration,
|
||||
this.principalName, this.accessToken);
|
||||
this.principal = null;
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService.saveAuthorizedClient(authorizedClient, this.principal));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeAuthorizedClientWhenClientRegistrationIdNullThenIllegalArgumentException() {
|
||||
this.clientRegistrationId = null;
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeAuthorizedClientWhenClientRegistrationIdEmptyThenIllegalArgumentException() {
|
||||
this.clientRegistrationId = "";
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeAuthorizedClientWhenPrincipalNameNullThenIllegalArgumentException() {
|
||||
this.principalName = null;
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientService
|
||||
.removeAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService.removeAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeAuthorizedClientWhenPrincipalNameEmptyThenIllegalArgumentException() {
|
||||
this.principalName = "";
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientService
|
||||
.removeAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService.removeAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -188,10 +220,14 @@ public class InMemoryReactiveOAuth2AuthorizedClientServiceTests {
|
|||
.willReturn(Mono.empty());
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.clientRegistration,
|
||||
this.principalName, this.accessToken);
|
||||
Mono<Void> saveAndDeleteAndLoad = this.authorizedClientService
|
||||
.saveAuthorizedClient(authorizedClient, this.principal).then(this.authorizedClientService
|
||||
.removeAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
StepVerifier.create(saveAndDeleteAndLoad).verifyComplete();
|
||||
// @formatter:off
|
||||
Mono<Void> saveAndDeleteAndLoad = this.authorizedClientService.saveAuthorizedClient(authorizedClient, this.principal)
|
||||
.then(this.authorizedClientService
|
||||
.removeAuthorizedClient(this.clientRegistrationId, this.principalName)
|
||||
);
|
||||
StepVerifier.create(saveAndDeleteAndLoad)
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -200,12 +236,14 @@ public class InMemoryReactiveOAuth2AuthorizedClientServiceTests {
|
|||
.willReturn(Mono.just(this.clientRegistration));
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.clientRegistration,
|
||||
this.principalName, this.accessToken);
|
||||
Mono<OAuth2AuthorizedClient> saveAndDeleteAndLoad = this.authorizedClientService
|
||||
.saveAuthorizedClient(authorizedClient, this.principal)
|
||||
// @formatter:off
|
||||
Mono<OAuth2AuthorizedClient> saveAndDeleteAndLoad = this.authorizedClientService.saveAuthorizedClient(authorizedClient, this.principal)
|
||||
.then(this.authorizedClientService.removeAuthorizedClient(this.clientRegistrationId,
|
||||
this.principalName))
|
||||
.then(this.authorizedClientService.loadAuthorizedClient(this.clientRegistrationId, this.principalName));
|
||||
StepVerifier.create(saveAndDeleteAndLoad).verifyComplete();
|
||||
StepVerifier.create(saveAndDeleteAndLoad)
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -104,9 +104,11 @@ public class JdbcOAuth2AuthorizedClientServiceTests {
|
|||
|
||||
@Test
|
||||
public void constructorWhenJdbcOperationsIsNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new JdbcOAuth2AuthorizedClientService(null, this.clientRegistrationRepository))
|
||||
.withMessage("jdbcOperations cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -118,31 +120,39 @@ public class JdbcOAuth2AuthorizedClientServiceTests {
|
|||
|
||||
@Test
|
||||
public void setAuthorizedClientRowMapperWhenNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService.setAuthorizedClientRowMapper(null))
|
||||
.withMessage("authorizedClientRowMapper cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthorizedClientParametersMapperWhenNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService.setAuthorizedClientParametersMapper(null))
|
||||
.withMessage("authorizedClientParametersMapper cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadAuthorizedClientWhenClientRegistrationIdIsNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService.loadAuthorizedClient(null, "principalName"))
|
||||
.withMessage("clientRegistrationId cannot be empty");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadAuthorizedClientWhenPrincipalNameIsNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientService
|
||||
.loadAuthorizedClient(this.clientRegistration.getRegistrationId(), null))
|
||||
.withMessage("principalName cannot be empty");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -351,8 +361,14 @@ public class JdbcOAuth2AuthorizedClientServiceTests {
|
|||
}
|
||||
|
||||
private static EmbeddedDatabase createDb(String schema) {
|
||||
return new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(EmbeddedDatabaseType.HSQL)
|
||||
.setScriptEncoding("UTF-8").addScript(schema).build();
|
||||
// @formatter:off
|
||||
return new EmbeddedDatabaseBuilder()
|
||||
.generateUniqueName(true)
|
||||
.setType(EmbeddedDatabaseType.HSQL)
|
||||
.setScriptEncoding("UTF-8")
|
||||
.addScript(schema)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private static Authentication createPrincipal() {
|
||||
|
|
|
@ -73,11 +73,16 @@ public class OAuth2AuthorizationContextTests {
|
|||
|
||||
@Test
|
||||
public void withAuthorizedClientWhenAllValuesProvidedThenAllValuesAreSet() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(this.authorizedClient).principal(this.principal).attributes((attributes) -> {
|
||||
.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal)
|
||||
.attributes((attributes) -> {
|
||||
attributes.put("attribute1", "value1");
|
||||
attributes.put("attribute2", "value2");
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(authorizationContext.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
assertThat(authorizationContext.getAuthorizedClient()).isSameAs(this.authorizedClient);
|
||||
assertThat(authorizationContext.getPrincipal()).isSameAs(this.principal);
|
||||
|
|
|
@ -89,11 +89,15 @@ public class OAuth2AuthorizedClientProviderBuilderTests {
|
|||
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeProviderThenProviderAuthorizes() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
|
||||
.authorizationCode().build();
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(TestClientRegistrations.clientRegistration().build()).principal(this.principal)
|
||||
.authorizationCode()
|
||||
.build();
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(TestClientRegistrations.clientRegistration().build())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThatExceptionOfType(ClientAuthorizationRequiredException.class)
|
||||
.isThrownBy(() -> authorizedClientProvider.authorize(authorizationContext));
|
||||
}
|
||||
|
@ -107,8 +111,12 @@ public class OAuth2AuthorizedClientProviderBuilderTests {
|
|||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
|
||||
TestClientRegistrations.clientRegistration().build(), this.principal.getName(), expiredAccessToken(),
|
||||
TestOAuth2RefreshTokens.refreshToken());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient reauthorizedClient = authorizedClientProvider.authorize(authorizationContext);
|
||||
assertThat(reauthorizedClient).isNotNull();
|
||||
verify(this.accessTokenClient).exchange(any(RequestEntity.class), eq(OAuth2AccessTokenResponse.class));
|
||||
|
@ -120,9 +128,12 @@ public class OAuth2AuthorizedClientProviderBuilderTests {
|
|||
.clientCredentials(
|
||||
(configurer) -> configurer.accessTokenResponseClient(this.clientCredentialsTokenResponseClient))
|
||||
.build();
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(TestClientRegistrations.clientCredentials().build()).principal(this.principal)
|
||||
.withClientRegistration(TestClientRegistrations.clientCredentials().build())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = authorizedClientProvider.authorize(authorizationContext);
|
||||
assertThat(authorizedClient).isNotNull();
|
||||
verify(this.accessTokenClient).exchange(any(RequestEntity.class), eq(OAuth2AccessTokenResponse.class));
|
||||
|
@ -130,13 +141,17 @@ public class OAuth2AuthorizedClientProviderBuilderTests {
|
|||
|
||||
@Test
|
||||
public void buildWhenPasswordProviderThenProviderAuthorizes() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
|
||||
.password((configurer) -> configurer.accessTokenResponseClient(this.passwordTokenResponseClient))
|
||||
.build();
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(TestClientRegistrations.password().build()).principal(this.principal)
|
||||
.withClientRegistration(TestClientRegistrations.password().build())
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").build();
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = authorizedClientProvider.authorize(authorizationContext);
|
||||
assertThat(authorizedClient).isNotNull();
|
||||
verify(this.accessTokenClient).exchange(any(RequestEntity.class), eq(OAuth2AccessTokenResponse.class));
|
||||
|
@ -154,8 +169,12 @@ public class OAuth2AuthorizedClientProviderBuilderTests {
|
|||
.build();
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
|
||||
// authorization_code
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationCodeContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(clientRegistration).principal(this.principal).build();
|
||||
.withClientRegistration(clientRegistration)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThatExceptionOfType(ClientAuthorizationRequiredException.class)
|
||||
.isThrownBy(() -> authorizedClientProvider.authorize(authorizationCodeContext));
|
||||
// refresh_token
|
||||
|
@ -168,18 +187,25 @@ public class OAuth2AuthorizedClientProviderBuilderTests {
|
|||
verify(this.accessTokenClient, times(1)).exchange(any(RequestEntity.class),
|
||||
eq(OAuth2AccessTokenResponse.class));
|
||||
// client_credentials
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext clientCredentialsContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(TestClientRegistrations.clientCredentials().build()).principal(this.principal)
|
||||
.withClientRegistration(TestClientRegistrations.clientCredentials().build())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
authorizedClient = authorizedClientProvider.authorize(clientCredentialsContext);
|
||||
assertThat(authorizedClient).isNotNull();
|
||||
verify(this.accessTokenClient, times(2)).exchange(any(RequestEntity.class),
|
||||
eq(OAuth2AccessTokenResponse.class));
|
||||
// password
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext passwordContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(TestClientRegistrations.password().build()).principal(this.principal)
|
||||
.withClientRegistration(TestClientRegistrations.password().build())
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").build();
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.build();
|
||||
// @formatter:on
|
||||
authorizedClient = authorizedClientProvider.authorize(passwordContext);
|
||||
assertThat(authorizedClient).isNotNull();
|
||||
verify(this.accessTokenClient, times(3)).exchange(any(RequestEntity.class),
|
||||
|
@ -189,11 +215,15 @@ public class OAuth2AuthorizedClientProviderBuilderTests {
|
|||
@Test
|
||||
public void buildWhenCustomProviderThenProviderCalled() {
|
||||
OAuth2AuthorizedClientProvider customProvider = mock(OAuth2AuthorizedClientProvider.class);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
|
||||
.provider(customProvider).build();
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(TestClientRegistrations.clientRegistration().build()).principal(this.principal)
|
||||
.provider(customProvider)
|
||||
.build();
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(TestClientRegistrations.clientRegistration().build())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
authorizedClientProvider.authorize(authorizationContext);
|
||||
verify(customProvider).authorize(any(OAuth2AuthorizationContext.class));
|
||||
}
|
||||
|
|
|
@ -72,52 +72,75 @@ public class PasswordOAuth2AuthorizedClientProviderTests {
|
|||
|
||||
@Test
|
||||
public void setClockSkewWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.setClockSkew(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClockSkew(null))
|
||||
.withMessage("clockSkew cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockSkewWhenNegativeSecondsThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClockSkew(Duration.ofSeconds(-1)))
|
||||
.withMessage("clockSkew must be >= 0");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.setClock(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClock(null))
|
||||
.withMessage("clock cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenContextIsNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.authorize(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.authorize(null))
|
||||
.withMessage("context cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenNotPasswordThenUnableToAuthorize() {
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientCredentials().build();
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(clientRegistration).principal(this.principal).build();
|
||||
.withClientRegistration(clientRegistration)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenPasswordAndNotAuthorizedAndEmptyUsernameThenUnableToAuthorize() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistration).principal(this.principal)
|
||||
.withClientRegistration(this.clientRegistration)
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, null)
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").build();
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenPasswordAndNotAuthorizedAndEmptyPasswordThenUnableToAuthorize() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistration).principal(this.principal)
|
||||
.withClientRegistration(this.clientRegistration)
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, null).build();
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, null)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext)).isNull();
|
||||
}
|
||||
|
||||
|
@ -125,10 +148,14 @@ public class PasswordOAuth2AuthorizedClientProviderTests {
|
|||
public void authorizeWhenPasswordAndNotAuthorizedThenAuthorize() {
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse().build();
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(accessTokenResponse);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistration).principal(this.principal)
|
||||
.withClientRegistration(this.clientRegistration)
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").build();
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = this.authorizedClientProvider.authorize(authorizationContext);
|
||||
assertThat(authorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principal.getName());
|
||||
|
@ -145,11 +172,14 @@ public class PasswordOAuth2AuthorizedClientProviderTests {
|
|||
this.principal.getName(), accessToken); // without refresh token
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse().build();
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(accessTokenResponse);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
authorizedClient = this.authorizedClientProvider.authorize(authorizationContext);
|
||||
assertThat(authorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principal.getName());
|
||||
|
@ -166,11 +196,14 @@ public class PasswordOAuth2AuthorizedClientProviderTests {
|
|||
this.principal.getName(), accessToken, TestOAuth2RefreshTokens.refreshToken()); // with
|
||||
// refresh
|
||||
// token
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext)).isNull();
|
||||
}
|
||||
|
||||
|
@ -190,11 +223,14 @@ public class PasswordOAuth2AuthorizedClientProviderTests {
|
|||
this.authorizedClientProvider.setClockSkew(Duration.ofSeconds(90));
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse().build();
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(accessTokenResponse);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient reauthorizedClient = this.authorizedClientProvider.authorize(authorizationContext);
|
||||
assertThat(reauthorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
assertThat(reauthorizedClient.getPrincipalName()).isEqualTo(this.principal.getName());
|
||||
|
|
|
@ -73,52 +73,75 @@ public class PasswordReactiveOAuth2AuthorizedClientProviderTests {
|
|||
|
||||
@Test
|
||||
public void setClockSkewWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.setClockSkew(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClockSkew(null))
|
||||
.withMessage("clockSkew cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockSkewWhenNegativeSecondsThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClockSkew(Duration.ofSeconds(-1)))
|
||||
.withMessage("clockSkew must be >= 0");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.setClock(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClock(null))
|
||||
.withMessage("clock cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenContextIsNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.authorize(null).block())
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.authorize(null).block())
|
||||
.withMessage("context cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenNotPasswordThenUnableToAuthorize() {
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientCredentials().build();
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(clientRegistration).principal(this.principal).build();
|
||||
.withClientRegistration(clientRegistration)
|
||||
.principal(this.principal).
|
||||
build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext).block()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenPasswordAndNotAuthorizedAndEmptyUsernameThenUnableToAuthorize() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistration).principal(this.principal)
|
||||
.withClientRegistration(this.clientRegistration)
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, null)
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").build();
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext).block()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenPasswordAndNotAuthorizedAndEmptyPasswordThenUnableToAuthorize() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistration).principal(this.principal)
|
||||
.withClientRegistration(this.clientRegistration)
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, null).build();
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, null)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext).block()).isNull();
|
||||
}
|
||||
|
||||
|
@ -126,10 +149,14 @@ public class PasswordReactiveOAuth2AuthorizedClientProviderTests {
|
|||
public void authorizeWhenPasswordAndNotAuthorizedThenAuthorize() {
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse().build();
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(Mono.just(accessTokenResponse));
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistration).principal(this.principal)
|
||||
.withClientRegistration(this.clientRegistration)
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").build();
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = this.authorizedClientProvider.authorize(authorizationContext).block();
|
||||
assertThat(authorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principal.getName());
|
||||
|
@ -146,11 +173,14 @@ public class PasswordReactiveOAuth2AuthorizedClientProviderTests {
|
|||
this.principal.getName(), accessToken); // without refresh token
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse().build();
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(Mono.just(accessTokenResponse));
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
authorizedClient = this.authorizedClientProvider.authorize(authorizationContext).block();
|
||||
assertThat(authorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principal.getName());
|
||||
|
@ -167,11 +197,14 @@ public class PasswordReactiveOAuth2AuthorizedClientProviderTests {
|
|||
this.principal.getName(), accessToken, TestOAuth2RefreshTokens.refreshToken()); // with
|
||||
// refresh
|
||||
// token
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext).block()).isNull();
|
||||
}
|
||||
|
||||
|
@ -191,11 +224,14 @@ public class PasswordReactiveOAuth2AuthorizedClientProviderTests {
|
|||
this.authorizedClientProvider.setClockSkew(Duration.ofSeconds(90));
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse().build();
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(Mono.just(accessTokenResponse));
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient reauthorizedClient = this.authorizedClientProvider.authorize(authorizationContext)
|
||||
.block();
|
||||
assertThat(reauthorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
|
|
|
@ -80,10 +80,16 @@ public class ReactiveOAuth2AuthorizedClientProviderBuilderTests {
|
|||
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeProviderThenProviderAuthorizes() {
|
||||
// @formatter:off
|
||||
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
|
||||
.builder().authorizationCode().build();
|
||||
.builder()
|
||||
.authorizationCode()
|
||||
.build();
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistrationBuilder.build()).principal(this.principal).build();
|
||||
.withClientRegistration(this.clientRegistrationBuilder.build())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThatExceptionOfType(ClientAuthorizationRequiredException.class)
|
||||
.isThrownBy(() -> authorizedClientProvider.authorize(authorizationContext).block());
|
||||
}
|
||||
|
@ -93,12 +99,20 @@ public class ReactiveOAuth2AuthorizedClientProviderBuilderTests {
|
|||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
// @formatter:off
|
||||
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
|
||||
.builder().refreshToken().build();
|
||||
.builder()
|
||||
.refreshToken()
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.clientRegistrationBuilder.build(),
|
||||
this.principal.getName(), expiredAccessToken(), TestOAuth2RefreshTokens.refreshToken());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient reauthorizedClient = authorizedClientProvider.authorize(authorizationContext).block();
|
||||
assertThat(reauthorizedClient).isNotNull();
|
||||
assertThat(this.server.getRequestCount()).isEqualTo(1);
|
||||
|
@ -112,12 +126,17 @@ public class ReactiveOAuth2AuthorizedClientProviderBuilderTests {
|
|||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
// @formatter:off
|
||||
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
|
||||
.builder().clientCredentials().build();
|
||||
.builder()
|
||||
.clientCredentials()
|
||||
.build();
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistrationBuilder
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).build())
|
||||
.principal(this.principal).build();
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = authorizedClientProvider.authorize(authorizationContext).block();
|
||||
assertThat(authorizedClient).isNotNull();
|
||||
assertThat(this.server.getRequestCount()).isEqualTo(1);
|
||||
|
@ -133,12 +152,17 @@ public class ReactiveOAuth2AuthorizedClientProviderBuilderTests {
|
|||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
|
||||
.builder().password().build();
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(
|
||||
this.clientRegistrationBuilder.authorizationGrantType(AuthorizationGrantType.PASSWORD).build())
|
||||
.principal(this.principal).attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").build();
|
||||
OAuth2AuthorizedClient authorizedClient = authorizedClientProvider.authorize(authorizationContext).block();
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.build();
|
||||
OAuth2AuthorizedClient authorizedClient = authorizedClientProvider.authorize(authorizationContext)
|
||||
.block();
|
||||
// @formatter:on
|
||||
assertThat(authorizedClient).isNotNull();
|
||||
assertThat(this.server.getRequestCount()).isEqualTo(1);
|
||||
RecordedRequest recordedRequest = this.server.takeRequest();
|
||||
|
@ -156,8 +180,12 @@ public class ReactiveOAuth2AuthorizedClientProviderBuilderTests {
|
|||
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
|
||||
.builder().authorizationCode().refreshToken().clientCredentials().password().build();
|
||||
// authorization_code
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationCodeContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistrationBuilder.build()).principal(this.principal).build();
|
||||
.withClientRegistration(this.clientRegistrationBuilder.build())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThatExceptionOfType(ClientAuthorizationRequiredException.class)
|
||||
.isThrownBy(() -> authorizedClientProvider.authorize(authorizationCodeContext).block());
|
||||
// refresh_token
|
||||
|
@ -172,10 +200,13 @@ public class ReactiveOAuth2AuthorizedClientProviderBuilderTests {
|
|||
String formParameters = recordedRequest.getBody().readUtf8();
|
||||
assertThat(formParameters).contains("grant_type=refresh_token");
|
||||
// client_credentials
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext clientCredentialsContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistrationBuilder
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).build())
|
||||
.principal(this.principal).build();
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
authorizedClient = authorizedClientProvider.authorize(clientCredentialsContext).block();
|
||||
assertThat(authorizedClient).isNotNull();
|
||||
assertThat(this.server.getRequestCount()).isEqualTo(2);
|
||||
|
@ -183,11 +214,15 @@ public class ReactiveOAuth2AuthorizedClientProviderBuilderTests {
|
|||
formParameters = recordedRequest.getBody().readUtf8();
|
||||
assertThat(formParameters).contains("grant_type=client_credentials");
|
||||
// password
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext passwordContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(
|
||||
this.clientRegistrationBuilder.authorizationGrantType(AuthorizationGrantType.PASSWORD).build())
|
||||
.principal(this.principal).attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password").build();
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "username")
|
||||
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password")
|
||||
.build();
|
||||
// @formatter:on
|
||||
authorizedClient = authorizedClientProvider.authorize(passwordContext).block();
|
||||
assertThat(authorizedClient).isNotNull();
|
||||
assertThat(this.server.getRequestCount()).isEqualTo(3);
|
||||
|
@ -200,10 +235,16 @@ public class ReactiveOAuth2AuthorizedClientProviderBuilderTests {
|
|||
public void buildWhenCustomProviderThenProviderCalled() {
|
||||
ReactiveOAuth2AuthorizedClientProvider customProvider = mock(ReactiveOAuth2AuthorizedClientProvider.class);
|
||||
given(customProvider.authorize(any())).willReturn(Mono.empty());
|
||||
// @formatter:off
|
||||
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
|
||||
.builder().provider(customProvider).build();
|
||||
.builder()
|
||||
.provider(customProvider)
|
||||
.build();
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistrationBuilder.build()).principal(this.principal).build();
|
||||
.withClientRegistration(this.clientRegistrationBuilder.build())
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
authorizedClientProvider.authorize(authorizationContext).block();
|
||||
verify(customProvider).authorize(any(OAuth2AuthorizationContext.class));
|
||||
}
|
||||
|
|
|
@ -78,40 +78,57 @@ public class RefreshTokenOAuth2AuthorizedClientProviderTests {
|
|||
|
||||
@Test
|
||||
public void setAccessTokenResponseClientWhenClientIsNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setAccessTokenResponseClient(null))
|
||||
.withMessage("accessTokenResponseClient cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockSkewWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.setClockSkew(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClockSkew(null))
|
||||
.withMessage("clockSkew cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockSkewWhenNegativeSecondsThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClockSkew(Duration.ofSeconds(-1)))
|
||||
.withMessage("clockSkew must be >= 0");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.setClock(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClock(null))
|
||||
.withMessage("clock cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenContextIsNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.authorize(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.authorize(null))
|
||||
.withMessage("context cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenNotAuthorizedThenUnableToReauthorize() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistration).principal(this.principal).build();
|
||||
.withClientRegistration(this.clientRegistration)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext)).isNull();
|
||||
}
|
||||
|
||||
|
@ -119,8 +136,12 @@ public class RefreshTokenOAuth2AuthorizedClientProviderTests {
|
|||
public void authorizeWhenAuthorizedAndRefreshTokenIsNullThenUnableToReauthorize() {
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.clientRegistration,
|
||||
this.principal.getName(), this.authorizedClient.getAccessToken());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext)).isNull();
|
||||
}
|
||||
|
||||
|
@ -128,8 +149,12 @@ public class RefreshTokenOAuth2AuthorizedClientProviderTests {
|
|||
public void authorizeWhenAuthorizedAndAccessTokenNotExpiredThenNotReauthorize() {
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.clientRegistration,
|
||||
this.principal.getName(), TestOAuth2AccessTokens.noScopes(), this.authorizedClient.getRefreshToken());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext)).isNull();
|
||||
}
|
||||
|
||||
|
@ -149,8 +174,12 @@ public class RefreshTokenOAuth2AuthorizedClientProviderTests {
|
|||
// Shorten the lifespan of the access token by 90 seconds, which will ultimately
|
||||
// force it to expire on the client
|
||||
this.authorizedClientProvider.setClockSkew(Duration.ofSeconds(90));
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient reauthorizedClient = this.authorizedClientProvider.authorize(authorizationContext);
|
||||
assertThat(reauthorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
assertThat(reauthorizedClient.getPrincipalName()).isEqualTo(this.principal.getName());
|
||||
|
@ -160,11 +189,19 @@ public class RefreshTokenOAuth2AuthorizedClientProviderTests {
|
|||
|
||||
@Test
|
||||
public void authorizeWhenAuthorizedAndAccessTokenExpiredThenReauthorize() {
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse()
|
||||
.refreshToken("new-refresh-token").build();
|
||||
// @formatter:off
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses
|
||||
.accessTokenResponse()
|
||||
.refreshToken("new-refresh-token")
|
||||
.build();
|
||||
// @formatter:on
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(accessTokenResponse);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(this.authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient reauthorizedClient = this.authorizedClientProvider.authorize(authorizationContext);
|
||||
assertThat(reauthorizedClient.getClientRegistration()).isSameAs(this.clientRegistration);
|
||||
assertThat(reauthorizedClient.getPrincipalName()).isEqualTo(this.principal.getName());
|
||||
|
@ -174,13 +211,21 @@ public class RefreshTokenOAuth2AuthorizedClientProviderTests {
|
|||
|
||||
@Test
|
||||
public void authorizeWhenAuthorizedAndRequestScopeProvidedThenScopeRequested() {
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses.accessTokenResponse()
|
||||
.refreshToken("new-refresh-token").build();
|
||||
// @formatter:off
|
||||
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses
|
||||
.accessTokenResponse()
|
||||
.refreshToken("new-refresh-token")
|
||||
.build();
|
||||
// @formatter:on
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(accessTokenResponse);
|
||||
String[] requestScope = new String[] { "read", "write" };
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(this.authorizedClient).principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.REQUEST_SCOPE_ATTRIBUTE_NAME, requestScope).build();
|
||||
.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.REQUEST_SCOPE_ATTRIBUTE_NAME, requestScope)
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.authorizedClientProvider.authorize(authorizationContext);
|
||||
ArgumentCaptor<OAuth2RefreshTokenGrantRequest> refreshTokenGrantRequestArgCaptor = ArgumentCaptor
|
||||
.forClass(OAuth2RefreshTokenGrantRequest.class);
|
||||
|
@ -192,9 +237,13 @@ public class RefreshTokenOAuth2AuthorizedClientProviderTests {
|
|||
@Test
|
||||
public void authorizeWhenAuthorizedAndInvalidRequestScopeProvidedThenThrowIllegalArgumentException() {
|
||||
String invalidRequestScope = "read write";
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(this.authorizedClient).principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.REQUEST_SCOPE_ATTRIBUTE_NAME, invalidRequestScope).build();
|
||||
.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.REQUEST_SCOPE_ATTRIBUTE_NAME, invalidRequestScope)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.authorize(authorizationContext))
|
||||
.withMessageStartingWith("The context attribute must be of type String[] '"
|
||||
|
|
|
@ -86,33 +86,48 @@ public class RefreshTokenReactiveOAuth2AuthorizedClientProviderTests {
|
|||
|
||||
@Test
|
||||
public void setClockSkewWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.setClockSkew(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClockSkew(null))
|
||||
.withMessage("clockSkew cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockSkewWhenNegativeSecondsThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClockSkew(Duration.ofSeconds(-1)))
|
||||
.withMessage("clockSkew must be >= 0");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.setClock(null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.setClock(null))
|
||||
.withMessage("clock cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenContextIsNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientProvider.authorize(null).block())
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.authorize(null).block())
|
||||
.withMessage("context cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizeWhenNotAuthorizedThenUnableToReauthorize() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withClientRegistration(this.clientRegistration).principal(this.principal).build();
|
||||
.withClientRegistration(this.clientRegistration)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext).block()).isNull();
|
||||
}
|
||||
|
||||
|
@ -120,8 +135,12 @@ public class RefreshTokenReactiveOAuth2AuthorizedClientProviderTests {
|
|||
public void authorizeWhenAuthorizedAndRefreshTokenIsNullThenUnableToReauthorize() {
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.clientRegistration,
|
||||
this.principal.getName(), this.authorizedClient.getAccessToken());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext).block()).isNull();
|
||||
}
|
||||
|
||||
|
@ -129,8 +148,12 @@ public class RefreshTokenReactiveOAuth2AuthorizedClientProviderTests {
|
|||
public void authorizeWhenAuthorizedAndAccessTokenNotExpiredThenNotReauthorize() {
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.clientRegistration,
|
||||
this.principal.getName(), TestOAuth2AccessTokens.noScopes(), this.authorizedClient.getRefreshToken());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(authorizedClient).principal(this.principal).build();
|
||||
.withAuthorizedClient(authorizedClient)
|
||||
.principal(this.principal)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(this.authorizedClientProvider.authorize(authorizationContext).block()).isNull();
|
||||
}
|
||||
|
||||
|
@ -181,9 +204,13 @@ public class RefreshTokenReactiveOAuth2AuthorizedClientProviderTests {
|
|||
.refreshToken("new-refresh-token").build();
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(Mono.just(accessTokenResponse));
|
||||
String[] requestScope = new String[] { "read", "write" };
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(this.authorizedClient).principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.REQUEST_SCOPE_ATTRIBUTE_NAME, requestScope).build();
|
||||
.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.REQUEST_SCOPE_ATTRIBUTE_NAME, requestScope)
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.authorizedClientProvider.authorize(authorizationContext).block();
|
||||
ArgumentCaptor<OAuth2RefreshTokenGrantRequest> refreshTokenGrantRequestArgCaptor = ArgumentCaptor
|
||||
.forClass(OAuth2RefreshTokenGrantRequest.class);
|
||||
|
@ -195,9 +222,13 @@ public class RefreshTokenReactiveOAuth2AuthorizedClientProviderTests {
|
|||
@Test
|
||||
public void authorizeWhenAuthorizedAndInvalidRequestScopeProvidedThenThrowIllegalArgumentException() {
|
||||
String invalidRequestScope = "read write";
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
|
||||
.withAuthorizedClient(this.authorizedClient).principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.REQUEST_SCOPE_ATTRIBUTE_NAME, invalidRequestScope).build();
|
||||
.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal)
|
||||
.attribute(OAuth2AuthorizationContext.REQUEST_SCOPE_ATTRIBUTE_NAME, invalidRequestScope)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.authorizedClientProvider.authorize(authorizationContext).block())
|
||||
.withMessageStartingWith("The context attribute must be of type String[] '"
|
||||
|
|
|
@ -214,9 +214,15 @@ public class OAuth2LoginAuthenticationProviderTests {
|
|||
Map<String, Object> additionalParameters = new HashMap<>();
|
||||
additionalParameters.put("param1", "value1");
|
||||
additionalParameters.put("param2", "value2");
|
||||
return OAuth2AccessTokenResponse.withToken("access-token-1234").tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.expiresIn(expiresAt.getEpochSecond()).scopes(scopes).refreshToken("refresh-token-1234")
|
||||
.additionalParameters(additionalParameters).build();
|
||||
// @formatter:off
|
||||
return OAuth2AccessTokenResponse.withToken("access-token-1234")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.expiresIn(expiresAt.getEpochSecond())
|
||||
.scopes(scopes)
|
||||
.refreshToken("refresh-token-1234")
|
||||
.additionalParameters(additionalParameters)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -124,7 +124,11 @@ public class OAuth2LoginReactiveAuthenticationManagerTests {
|
|||
|
||||
@Test
|
||||
public void authenticationWhenErrorThenOAuth2AuthenticationException() {
|
||||
this.authorizationResponseBldr = OAuth2AuthorizationResponse.error("error").state("state");
|
||||
// @formatter:off
|
||||
this.authorizationResponseBldr = OAuth2AuthorizationResponse
|
||||
.error("error")
|
||||
.state("state");
|
||||
// @formatter:on
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
.isThrownBy(() -> this.manager.authenticate(loginToken()).block());
|
||||
}
|
||||
|
|
|
@ -60,12 +60,22 @@ public class DefaultAuthorizationCodeTokenResponseClientTests {
|
|||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
String tokenUri = this.server.url("/oauth2/token").toString();
|
||||
this.clientRegistration = ClientRegistration.withRegistrationId("registration-1").clientId("client-1")
|
||||
.clientSecret("secret").clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
// @formatter:off
|
||||
this.clientRegistration = ClientRegistration
|
||||
.withRegistrationId("registration-1")
|
||||
.clientId("client-1")
|
||||
.clientSecret("secret")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri("https://client.com/callback/client-1").scope("read", "write")
|
||||
.authorizationUri("https://provider.com/oauth2/authorize").tokenUri(tokenUri)
|
||||
.userInfoUri("https://provider.com/user").userNameAttributeName("id").clientName("client-1").build();
|
||||
.redirectUri("https://client.com/callback/client-1")
|
||||
.scope("read", "write")
|
||||
.authorizationUri("https://provider.com/oauth2/authorize")
|
||||
.tokenUri(tokenUri)
|
||||
.userInfoUri("https://provider.com/user")
|
||||
.userNameAttributeName("id")
|
||||
.clientName("client-1")
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -90,11 +100,17 @@ public class DefaultAuthorizationCodeTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseThenReturnAccessTokenResponse() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\",\n" + " \"refresh_token\": \"refresh-token-1234\",\n"
|
||||
+ " \"custom_parameter_1\": \"custom-value-1\",\n" + " \"custom_parameter_2\": \"custom-value-2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\",\n"
|
||||
+ " \"refresh_token\": \"refresh-token-1234\",\n"
|
||||
+ " \"custom_parameter_1\": \"custom-value-1\",\n"
|
||||
+ " \"custom_parameter_2\": \"custom-value-2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
Instant expiresAtBefore = Instant.now().plusSeconds(3600);
|
||||
OAuth2AccessTokenResponse accessTokenResponse = this.tokenResponseClient
|
||||
|
@ -121,8 +137,11 @@ public class DefaultAuthorizationCodeTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenClientAuthenticationBasicThenAuthorizationHeaderIsSent() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
this.tokenResponseClient.getTokenResponse(this.authorizationCodeGrantRequest());
|
||||
RecordedRequest recordedRequest = this.server.takeRequest();
|
||||
|
@ -131,8 +150,13 @@ public class DefaultAuthorizationCodeTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenClientAuthenticationPostThenFormParametersAreSent() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
ClientRegistration clientRegistration = this.from(this.clientRegistration)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.POST).build();
|
||||
|
@ -146,8 +170,13 @@ public class DefaultAuthorizationCodeTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseAndNotBearerTokenTypeThenThrowOAuth2AuthorizationException() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
assertThatExceptionOfType(OAuth2AuthorizationException.class)
|
||||
.isThrownBy(() -> this.tokenResponseClient.getTokenResponse(this.authorizationCodeGrantRequest()))
|
||||
|
@ -158,7 +187,11 @@ public class DefaultAuthorizationCodeTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseAndMissingTokenTypeParameterThenThrowOAuth2AuthorizationException() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
assertThatExceptionOfType(OAuth2AuthorizationException.class)
|
||||
.isThrownBy(() -> this.tokenResponseClient.getTokenResponse(this.authorizationCodeGrantRequest()))
|
||||
|
@ -169,9 +202,15 @@ public class DefaultAuthorizationCodeTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseIncludesScopeThenAccessTokenHasResponseScope() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"refresh_token\": \"refresh-token-1234\",\n" + " \"scope\": \"read\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"refresh_token\": \"refresh-token-1234\",\n"
|
||||
+ " \"scope\": \"read\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2AccessTokenResponse accessTokenResponse = this.tokenResponseClient
|
||||
.getTokenResponse(this.authorizationCodeGrantRequest());
|
||||
|
@ -180,9 +219,14 @@ public class DefaultAuthorizationCodeTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseDoesNotIncludeScopeThenAccessTokenHasDefaultScope() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"refresh_token\": \"refresh-token-1234\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"refresh_token\": \"refresh-token-1234\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2AccessTokenResponse accessTokenResponse = this.tokenResponseClient
|
||||
.getTokenResponse(this.authorizationCodeGrantRequest());
|
||||
|
@ -201,12 +245,17 @@ public class DefaultAuthorizationCodeTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenMalformedResponseThenThrowOAuth2AuthorizationException() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\",\n" + " \"refresh_token\": \"refresh-token-1234\",\n"
|
||||
+ " \"custom_parameter_1\": \"custom-value-1\",\n"
|
||||
+ " \"custom_parameter_2\": \"custom-value-2\"\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\",\n"
|
||||
+ " \"refresh_token\": \"refresh-token-1234\",\n"
|
||||
+ " \"custom_parameter_1\": \"custom-value-1\",\n"
|
||||
+ " \"custom_parameter_2\": \"custom-value-2\"\n";
|
||||
// "}\n"; // Make the JSON invalid/malformed
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
assertThatExceptionOfType(OAuth2AuthorizationException.class)
|
||||
.isThrownBy(() -> this.tokenResponseClient.getTokenResponse(this.authorizationCodeGrantRequest()))
|
||||
|
@ -253,17 +302,21 @@ public class DefaultAuthorizationCodeTokenResponseClientTests {
|
|||
}
|
||||
|
||||
private ClientRegistration.Builder from(ClientRegistration registration) {
|
||||
// @formatter:off
|
||||
return ClientRegistration.withRegistrationId(registration.getRegistrationId())
|
||||
.clientId(registration.getClientId()).clientSecret(registration.getClientSecret())
|
||||
.clientId(registration.getClientId())
|
||||
.clientSecret(registration.getClientSecret())
|
||||
.clientAuthenticationMethod(registration.getClientAuthenticationMethod())
|
||||
.authorizationGrantType(registration.getAuthorizationGrantType())
|
||||
.redirectUri(registration.getRedirectUri()).scope(registration.getScopes())
|
||||
.redirectUri(registration.getRedirectUri())
|
||||
.scope(registration.getScopes())
|
||||
.authorizationUri(registration.getProviderDetails().getAuthorizationUri())
|
||||
.tokenUri(registration.getProviderDetails().getTokenUri())
|
||||
.userInfoUri(registration.getProviderDetails().getUserInfoEndpoint().getUri())
|
||||
.userNameAttributeName(
|
||||
registration.getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName())
|
||||
.clientName(registration.getClientName());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,10 +57,16 @@ public class DefaultClientCredentialsTokenResponseClientTests {
|
|||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
String tokenUri = this.server.url("/oauth2/token").toString();
|
||||
this.clientRegistration = ClientRegistration.withRegistrationId("registration-1").clientId("client-1")
|
||||
.clientSecret("secret").clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).scope("read", "write")
|
||||
.tokenUri(tokenUri).build();
|
||||
// @formatter:off
|
||||
this.clientRegistration = ClientRegistration.withRegistrationId("registration-1")
|
||||
.clientId("client-1")
|
||||
.clientSecret("secret")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
||||
.scope("read", "write")
|
||||
.tokenUri(tokenUri)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -70,12 +76,18 @@ public class DefaultClientCredentialsTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void setRequestEntityConverterWhenConverterIsNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.tokenResponseClient.setRequestEntityConverter(null));
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.tokenResponseClient.setRequestEntityConverter(null));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setRestOperationsWhenRestOperationsIsNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.tokenResponseClient.setRestOperations(null));
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.tokenResponseClient.setRestOperations(null));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -85,10 +97,16 @@ public class DefaultClientCredentialsTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseThenReturnAccessTokenResponse() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\",\n" + " \"custom_parameter_1\": \"custom-value-1\",\n"
|
||||
+ " \"custom_parameter_2\": \"custom-value-2\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\",\n"
|
||||
+ " \"custom_parameter_1\": \"custom-value-1\",\n"
|
||||
+ " \"custom_parameter_2\": \"custom-value-2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
Instant expiresAtBefore = Instant.now().plusSeconds(3600);
|
||||
OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest = new OAuth2ClientCredentialsGrantRequest(
|
||||
|
@ -116,8 +134,13 @@ public class DefaultClientCredentialsTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenClientAuthenticationBasicThenAuthorizationHeaderIsSent() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest = new OAuth2ClientCredentialsGrantRequest(
|
||||
this.clientRegistration);
|
||||
|
@ -128,8 +151,13 @@ public class DefaultClientCredentialsTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenClientAuthenticationPostThenFormParametersAreSent() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
ClientRegistration clientRegistration = this.from(this.clientRegistration)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.POST).build();
|
||||
|
@ -145,8 +173,13 @@ public class DefaultClientCredentialsTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseAndNotBearerTokenTypeThenThrowOAuth2AuthorizationException() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest = new OAuth2ClientCredentialsGrantRequest(
|
||||
this.clientRegistration);
|
||||
|
@ -172,9 +205,14 @@ public class DefaultClientCredentialsTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseIncludesScopeThenAccessTokenHasResponseScope() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n" + " \"scope\": \"read\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest = new OAuth2ClientCredentialsGrantRequest(
|
||||
this.clientRegistration);
|
||||
|
@ -185,8 +223,13 @@ public class DefaultClientCredentialsTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseDoesNotIncludeScopeThenAccessTokenHasDefaultScope() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest = new OAuth2ClientCredentialsGrantRequest(
|
||||
this.clientRegistration);
|
||||
|
@ -209,11 +252,16 @@ public class DefaultClientCredentialsTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenMalformedResponseThenThrowOAuth2AuthorizationException() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\",\n" + " \"custom_parameter_1\": \"custom-value-1\",\n"
|
||||
+ " \"custom_parameter_2\": \"custom-value-2\"\n";
|
||||
// "}\n"; // Make the JSON invalid/malformed
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\",\n"
|
||||
+ " \"custom_parameter_1\": \"custom-value-1\",\n"
|
||||
+ " \"custom_parameter_2\": \"custom-value-2\"\n";
|
||||
// "}\n"; // Make the JSON invalid/malformed
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest = new OAuth2ClientCredentialsGrantRequest(
|
||||
this.clientRegistration);
|
||||
|
@ -225,7 +273,11 @@ public class DefaultClientCredentialsTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenErrorResponseThenThrowOAuth2AuthorizationException() {
|
||||
String accessTokenErrorResponse = "{\n" + " \"error\": \"unauthorized_client\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenErrorResponse = "{\n"
|
||||
+ " \"error\": \"unauthorized_client\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenErrorResponse).setResponseCode(400));
|
||||
OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest = new OAuth2ClientCredentialsGrantRequest(
|
||||
this.clientRegistration);
|
||||
|
@ -250,11 +302,15 @@ public class DefaultClientCredentialsTokenResponseClientTests {
|
|||
}
|
||||
|
||||
private ClientRegistration.Builder from(ClientRegistration registration) {
|
||||
// @formatter:off
|
||||
return ClientRegistration.withRegistrationId(registration.getRegistrationId())
|
||||
.clientId(registration.getClientId()).clientSecret(registration.getClientSecret())
|
||||
.clientId(registration.getClientId())
|
||||
.clientSecret(registration.getClientSecret())
|
||||
.clientAuthenticationMethod(registration.getClientAuthenticationMethod())
|
||||
.authorizationGrantType(registration.getAuthorizationGrantType()).scope(registration.getScopes())
|
||||
.authorizationGrantType(registration.getAuthorizationGrantType())
|
||||
.scope(registration.getScopes())
|
||||
.tokenUri(registration.getProviderDetails().getTokenUri());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -88,8 +88,13 @@ public class DefaultPasswordTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseThenReturnAccessTokenResponse() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
Instant expiresAtBefore = Instant.now().plusSeconds(3600);
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.build();
|
||||
|
@ -117,8 +122,13 @@ public class DefaultPasswordTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenClientAuthenticationPostThenFormParametersAreSent() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.POST).build();
|
||||
|
@ -134,8 +144,13 @@ public class DefaultPasswordTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseAndNotBearerTokenTypeThenThrowOAuth2AuthorizationException() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2PasswordGrantRequest passwordGrantRequest = new OAuth2PasswordGrantRequest(
|
||||
this.clientRegistrationBuilder.build(), this.username, this.password);
|
||||
|
@ -148,9 +163,14 @@ public class DefaultPasswordTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseIncludesScopeThenAccessTokenHasResponseScope() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n" + " \"scope\": \"read\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2PasswordGrantRequest passwordGrantRequest = new OAuth2PasswordGrantRequest(
|
||||
this.clientRegistrationBuilder.build(), this.username, this.password);
|
||||
|
|
|
@ -92,8 +92,13 @@ public class DefaultRefreshTokenTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseThenReturnAccessTokenResponse() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
Instant expiresAtBefore = Instant.now().plusSeconds(3600);
|
||||
OAuth2RefreshTokenGrantRequest refreshTokenGrantRequest = new OAuth2RefreshTokenGrantRequest(
|
||||
|
@ -137,8 +142,13 @@ public class DefaultRefreshTokenTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseAndNotBearerTokenTypeThenThrowOAuth2AuthorizationException() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2RefreshTokenGrantRequest refreshTokenGrantRequest = new OAuth2RefreshTokenGrantRequest(
|
||||
this.clientRegistrationBuilder.build(), this.accessToken, this.refreshToken);
|
||||
|
@ -151,9 +161,14 @@ public class DefaultRefreshTokenTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseIncludesScopeThenAccessTokenHasResponseScope() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n" + " \"scope\": \"read\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2RefreshTokenGrantRequest refreshTokenGrantRequest = new OAuth2RefreshTokenGrantRequest(
|
||||
this.clientRegistrationBuilder.build(), this.accessToken, this.refreshToken,
|
||||
|
|
|
@ -75,11 +75,17 @@ public class NimbusAuthorizationCodeTokenResponseClientTests {
|
|||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseThenReturnAccessTokenResponse() throws Exception {
|
||||
MockWebServer server = new MockWebServer();
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"openid profile\",\n" + " \"refresh_token\": \"refresh-token-1234\",\n"
|
||||
+ " \"custom_parameter_1\": \"custom-value-1\",\n" + " \"custom_parameter_2\": \"custom-value-2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"openid profile\",\n"
|
||||
+ " \"refresh_token\": \"refresh-token-1234\",\n"
|
||||
+ " \"custom_parameter_1\": \"custom-value-1\",\n"
|
||||
+ " \"custom_parameter_2\": \"custom-value-2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
server.enqueue(new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setBody(accessTokenSuccessResponse));
|
||||
server.start();
|
||||
|
@ -127,11 +133,16 @@ public class NimbusAuthorizationCodeTokenResponseClientTests {
|
|||
this.exception.expect(OAuth2AuthorizationException.class);
|
||||
this.exception.expectMessage(containsString("invalid_token_response"));
|
||||
MockWebServer server = new MockWebServer();
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"openid profile\",\n" + " \"custom_parameter_1\": \"custom-value-1\",\n"
|
||||
+ " \"custom_parameter_2\": \"custom-value-2\"\n";
|
||||
// "}\n"; // Make the JSON invalid/malformed
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"openid profile\",\n"
|
||||
+ " \"custom_parameter_1\": \"custom-value-1\",\n"
|
||||
+ " \"custom_parameter_2\": \"custom-value-2\"\n";
|
||||
// "}\n"; // Make the JSON invalid/malformed
|
||||
// @formatter:on
|
||||
server.enqueue(new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setBody(accessTokenSuccessResponse));
|
||||
server.start();
|
||||
|
@ -160,7 +171,11 @@ public class NimbusAuthorizationCodeTokenResponseClientTests {
|
|||
this.exception.expect(OAuth2AuthorizationException.class);
|
||||
this.exception.expectMessage(containsString("unauthorized_client"));
|
||||
MockWebServer server = new MockWebServer();
|
||||
String accessTokenErrorResponse = "{\n" + " \"error\": \"unauthorized_client\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenErrorResponse = "{\n"
|
||||
+ " \"error\": \"unauthorized_client\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
server.enqueue(new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setResponseCode(500).setBody(accessTokenErrorResponse));
|
||||
server.start();
|
||||
|
@ -200,8 +215,13 @@ public class NimbusAuthorizationCodeTokenResponseClientTests {
|
|||
this.exception.expect(OAuth2AuthorizationException.class);
|
||||
this.exception.expectMessage(containsString("invalid_token_response"));
|
||||
MockWebServer server = new MockWebServer();
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
server.enqueue(new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setBody(accessTokenSuccessResponse));
|
||||
server.start();
|
||||
|
@ -220,9 +240,14 @@ public class NimbusAuthorizationCodeTokenResponseClientTests {
|
|||
public void getTokenResponseWhenSuccessResponseIncludesScopeThenReturnAccessTokenResponseUsingResponseScope()
|
||||
throws Exception {
|
||||
MockWebServer server = new MockWebServer();
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"openid profile\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"openid profile\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
server.enqueue(new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setBody(accessTokenSuccessResponse));
|
||||
server.start();
|
||||
|
@ -242,8 +267,13 @@ public class NimbusAuthorizationCodeTokenResponseClientTests {
|
|||
public void getTokenResponseWhenSuccessResponseDoesNotIncludeScopeThenReturnAccessTokenResponseUsingRequestedScope()
|
||||
throws Exception {
|
||||
MockWebServer server = new MockWebServer();
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
server.enqueue(new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setBody(accessTokenSuccessResponse));
|
||||
server.start();
|
||||
|
|
|
@ -48,21 +48,38 @@ public class OAuth2AuthorizationCodeGrantRequestEntityConverterTests {
|
|||
|
||||
private OAuth2AuthorizationCodeGrantRequestEntityConverter converter = new OAuth2AuthorizationCodeGrantRequestEntityConverter();
|
||||
|
||||
// @formatter:off
|
||||
private ClientRegistration.Builder clientRegistrationBuilder = ClientRegistration
|
||||
.withRegistrationId("registration-1").clientId("client-1").clientSecret("secret")
|
||||
.withRegistrationId("registration-1")
|
||||
.clientId("client-1")
|
||||
.clientSecret("secret")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri("https://client.com/callback/client-1").scope("read", "write")
|
||||
.authorizationUri("https://provider.com/oauth2/authorize").tokenUri("https://provider.com/oauth2/token")
|
||||
.userInfoUri("https://provider.com/user").userNameAttributeName("id").clientName("client-1");
|
||||
|
||||
private OAuth2AuthorizationRequest.Builder authorizationRequestBuilder = OAuth2AuthorizationRequest
|
||||
.authorizationCode().clientId("client-1").state("state-1234")
|
||||
.redirectUri("https://client.com/callback/client-1")
|
||||
.scope("read", "write")
|
||||
.authorizationUri("https://provider.com/oauth2/authorize")
|
||||
.redirectUri("https://client.com/callback/client-1").scopes(new HashSet(Arrays.asList("read", "write")));
|
||||
.tokenUri("https://provider.com/oauth2/token")
|
||||
.userInfoUri("https://provider.com/user")
|
||||
.userNameAttributeName("id")
|
||||
.clientName("client-1");
|
||||
// @formatter:on
|
||||
|
||||
// @formatter:off
|
||||
private OAuth2AuthorizationRequest.Builder authorizationRequestBuilder = OAuth2AuthorizationRequest
|
||||
.authorizationCode()
|
||||
.clientId("client-1")
|
||||
.state("state-1234")
|
||||
.authorizationUri("https://provider.com/oauth2/authorize")
|
||||
.redirectUri("https://client.com/callback/client-1")
|
||||
.scopes(new HashSet(Arrays.asList("read", "write")));
|
||||
// @formatter:on
|
||||
|
||||
// @formatter:off
|
||||
private OAuth2AuthorizationResponse.Builder authorizationResponseBuilder = OAuth2AuthorizationResponse
|
||||
.success("code-1234").state("state-1234").redirectUri("https://client.com/callback/client-1");
|
||||
.success("code-1234")
|
||||
.state("state-1234")
|
||||
.redirectUri("https://client.com/callback/client-1");
|
||||
// @formatter:on
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
|
|
|
@ -44,11 +44,16 @@ public class OAuth2ClientCredentialsGrantRequestEntityConverterTests {
|
|||
|
||||
@Before
|
||||
public void setup() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId("registration-1")
|
||||
.clientId("client-1").clientSecret("secret")
|
||||
.clientId("client-1")
|
||||
.clientSecret("secret")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).scope("read", "write")
|
||||
.tokenUri("https://provider.com/oauth2/token").build();
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
||||
.scope("read", "write")
|
||||
.tokenUri("https://provider.com/oauth2/token")
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.clientCredentialsGrantRequest = new OAuth2ClientCredentialsGrantRequest(clientRegistration);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,10 +37,16 @@ public class OAuth2ClientCredentialsGrantRequestTests {
|
|||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.clientRegistration = ClientRegistration.withRegistrationId("registration-1").clientId("client-1")
|
||||
.clientSecret("secret").clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).scope("read", "write")
|
||||
.tokenUri("https://provider.com/oauth2/token").build();
|
||||
// @formatter:off
|
||||
this.clientRegistration = ClientRegistration.withRegistrationId("registration-1")
|
||||
.clientId("client-1")
|
||||
.clientSecret("secret")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
||||
.scope("read", "write")
|
||||
.tokenUri("https://provider.com/oauth2/token")
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -50,10 +56,15 @@ public class OAuth2ClientCredentialsGrantRequestTests {
|
|||
|
||||
@Test
|
||||
public void constructorWhenClientRegistrationInvalidGrantTypeThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId("registration-1")
|
||||
.clientId("client-1").authorizationGrantType(AuthorizationGrantType.IMPLICIT)
|
||||
.redirectUri("https://localhost:8080/redirect-uri").authorizationUri("https://provider.com/oauth2/auth")
|
||||
.clientName("Client 1").build();
|
||||
.clientId("client-1")
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT)
|
||||
.redirectUri("https://localhost:8080/redirect-uri")
|
||||
.authorizationUri("https://provider.com/oauth2/auth")
|
||||
.clientName("Client 1")
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new OAuth2ClientCredentialsGrantRequest(clientRegistration)).withMessage(
|
||||
"clientRegistration.authorizationGrantType must be AuthorizationGrantType.CLIENT_CREDENTIALS");
|
||||
|
|
|
@ -44,8 +44,12 @@ public class OAuth2PasswordGrantRequestEntityConverterTests {
|
|||
|
||||
@Before
|
||||
public void setup() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration()
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD).scope("read", "write").build();
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
|
||||
.scope("read", "write")
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.passwordGrantRequest = new OAuth2PasswordGrantRequest(clientRegistration, "user1", "password");
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,8 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
|
|||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
String tokenUri = this.server.url("/oauth2/token").toString();
|
||||
this.clientRegistration = TestClientRegistrations.clientRegistration().tokenUri(tokenUri);
|
||||
this.clientRegistration = TestClientRegistrations.clientRegistration()
|
||||
.tokenUri(tokenUri);
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -74,11 +75,17 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseThenReturnAccessTokenResponse() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"openid profile\",\n" + " \"refresh_token\": \"refresh-token-1234\",\n"
|
||||
+ " \"custom_parameter_1\": \"custom-value-1\",\n" + " \"custom_parameter_2\": \"custom-value-2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"openid profile\",\n"
|
||||
+ " \"refresh_token\": \"refresh-token-1234\",\n"
|
||||
+ " \"custom_parameter_1\": \"custom-value-1\",\n"
|
||||
+ " \"custom_parameter_2\": \"custom-value-2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
Instant expiresAtBefore = Instant.now().plusSeconds(3600);
|
||||
OAuth2AccessTokenResponse accessTokenResponse = this.tokenResponseClient
|
||||
|
@ -198,8 +205,13 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseAndNotBearerTokenTypeThenThrowOAuth2AuthorizationException() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ "\"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
assertThatExceptionOfType(OAuth2AuthorizationException.class)
|
||||
.isThrownBy(() -> this.tokenResponseClient.getTokenResponse(authorizationCodeGrantRequest()).block())
|
||||
|
@ -208,9 +220,14 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseIncludesScopeThenReturnAccessTokenResponseUsingResponseScope() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"openid profile\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ "\"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"openid profile\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
this.clientRegistration.scope("openid", "profile", "email", "address");
|
||||
OAuth2AccessTokenResponse accessTokenResponse = this.tokenResponseClient
|
||||
|
@ -220,8 +237,13 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseDoesNotIncludeScopeThenReturnAccessTokenResponseUsingRequestedScope() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
this.clientRegistration.scope("openid", "profile", "email", "address");
|
||||
OAuth2AccessTokenResponse accessTokenResponse = this.tokenResponseClient
|
||||
|
@ -257,9 +279,14 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
|
|||
WebClient customClient = mock(WebClient.class);
|
||||
given(customClient.post()).willReturn(WebClient.builder().build().post());
|
||||
this.tokenResponseClient.setWebClient(customClient);
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"openid profile\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"openid profile\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
this.clientRegistration.scope("openid", "profile", "email", "address");
|
||||
OAuth2AccessTokenResponse response = this.tokenResponseClient.getTokenResponse(authorizationCodeGrantRequest())
|
||||
|
@ -270,8 +297,13 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
|
|||
@Test
|
||||
public void getTokenResponseWhenOAuth2AuthorizationRequestContainsPkceParametersThenTokenRequestBodyShouldContainCodeVerifier()
|
||||
throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
this.tokenResponseClient.getTokenResponse(pkceAuthorizationCodeGrantRequest()).block();
|
||||
String body = this.server.takeRequest().getBody().readUtf8();
|
||||
|
@ -287,13 +319,22 @@ public class WebClientReactiveAuthorizationCodeTokenResponseClientTests {
|
|||
Map<String, Object> additionalParameters = new HashMap<>();
|
||||
additionalParameters.put(PkceParameterNames.CODE_CHALLENGE, "code-challenge-1234");
|
||||
additionalParameters.put(PkceParameterNames.CODE_CHALLENGE_METHOD, "S256");
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
|
||||
.clientId(registration.getClientId()).state("state")
|
||||
.clientId(registration.getClientId())
|
||||
.state("state")
|
||||
.authorizationUri(registration.getProviderDetails().getAuthorizationUri())
|
||||
.redirectUri(registration.getRedirectUri()).scopes(registration.getScopes()).attributes(attributes)
|
||||
.additionalParameters(additionalParameters).build();
|
||||
OAuth2AuthorizationResponse authorizationResponse = OAuth2AuthorizationResponse.success("code").state("state")
|
||||
.redirectUri(registration.getRedirectUri()).build();
|
||||
.redirectUri(registration.getRedirectUri())
|
||||
.scopes(registration.getScopes())
|
||||
.attributes(attributes)
|
||||
.additionalParameters(additionalParameters)
|
||||
.build();
|
||||
OAuth2AuthorizationResponse authorizationResponse = OAuth2AuthorizationResponse
|
||||
.success("code")
|
||||
.state("state")
|
||||
.redirectUri(registration.getRedirectUri())
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationExchange authorizationExchange = new OAuth2AuthorizationExchange(authorizationRequest,
|
||||
authorizationResponse);
|
||||
return new OAuth2AuthorizationCodeGrantRequest(registration, authorizationExchange);
|
||||
|
|
|
@ -68,9 +68,15 @@ public class WebClientReactiveClientCredentialsTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenHeaderThenSuccess() throws Exception {
|
||||
enqueueJson("{\n" + " \"access_token\":\"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3\",\n"
|
||||
+ " \"token_type\":\"bearer\",\n" + " \"expires_in\":3600,\n"
|
||||
+ " \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\",\n" + " \"scope\":\"create\"\n" + "}");
|
||||
// @formatter:off
|
||||
enqueueJson("{\n"
|
||||
+ " \"access_token\":\"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3\",\n"
|
||||
+ " \"token_type\":\"bearer\",\n"
|
||||
+ " \"expires_in\":3600,\n"
|
||||
+ " \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\",\n"
|
||||
+ " \"scope\":\"create\"\n"
|
||||
+ "}");
|
||||
// @formatter:on
|
||||
OAuth2ClientCredentialsGrantRequest request = new OAuth2ClientCredentialsGrantRequest(
|
||||
this.clientRegistration.build());
|
||||
OAuth2AccessTokenResponse response = this.client.getTokenResponse(request).block();
|
||||
|
@ -86,9 +92,15 @@ public class WebClientReactiveClientCredentialsTokenResponseClientTests {
|
|||
public void getTokenResponseWhenPostThenSuccess() throws Exception {
|
||||
ClientRegistration registration = this.clientRegistration
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.POST).build();
|
||||
enqueueJson("{\n" + " \"access_token\":\"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3\",\n"
|
||||
+ " \"token_type\":\"bearer\",\n" + " \"expires_in\":3600,\n"
|
||||
+ " \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\",\n" + " \"scope\":\"create\"\n" + "}");
|
||||
// @formatter:off
|
||||
enqueueJson("{\n"
|
||||
+ " \"access_token\":\"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3\",\n"
|
||||
+ " \"token_type\":\"bearer\",\n"
|
||||
+ " \"expires_in\":3600,\n"
|
||||
+ " \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\",\n"
|
||||
+ " \"scope\":\"create\"\n"
|
||||
+ "}");
|
||||
// @formatter:on
|
||||
OAuth2ClientCredentialsGrantRequest request = new OAuth2ClientCredentialsGrantRequest(registration);
|
||||
OAuth2AccessTokenResponse response = this.client.getTokenResponse(request).block();
|
||||
RecordedRequest actualRequest = this.server.takeRequest();
|
||||
|
@ -102,9 +114,14 @@ public class WebClientReactiveClientCredentialsTokenResponseClientTests {
|
|||
@Test
|
||||
public void getTokenResponseWhenNoScopeThenClientRegistrationScopesDefaulted() {
|
||||
ClientRegistration registration = this.clientRegistration.build();
|
||||
enqueueJson("{\n" + " \"access_token\":\"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3\",\n"
|
||||
+ " \"token_type\":\"bearer\",\n" + " \"expires_in\":3600,\n"
|
||||
+ " \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\"\n" + "}");
|
||||
// @formatter:off
|
||||
enqueueJson("{\n"
|
||||
+ " \"access_token\":\"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3\",\n"
|
||||
+ " \"token_type\":\"bearer\",\n"
|
||||
+ " \"expires_in\":3600,\n"
|
||||
+ " \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\"\n"
|
||||
+ "}");
|
||||
// @formatter:on
|
||||
OAuth2ClientCredentialsGrantRequest request = new OAuth2ClientCredentialsGrantRequest(registration);
|
||||
OAuth2AccessTokenResponse response = this.client.getTokenResponse(request).block();
|
||||
assertThat(response.getAccessToken().getScopes()).isEqualTo(registration.getScopes());
|
||||
|
@ -121,9 +138,14 @@ public class WebClientReactiveClientCredentialsTokenResponseClientTests {
|
|||
given(customClient.post()).willReturn(WebClient.builder().build().post());
|
||||
this.client.setWebClient(customClient);
|
||||
ClientRegistration registration = this.clientRegistration.build();
|
||||
enqueueJson("{\n" + " \"access_token\":\"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3\",\n"
|
||||
+ " \"token_type\":\"bearer\",\n" + " \"expires_in\":3600,\n"
|
||||
+ " \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\"\n" + "}");
|
||||
// @formatter:off
|
||||
enqueueJson("{\n"
|
||||
+ " \"access_token\":\"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3\",\n"
|
||||
+ " \"token_type\":\"bearer\",\n"
|
||||
+ " \"expires_in\":3600,\n"
|
||||
+ " \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\"\n"
|
||||
+ "}");
|
||||
// @formatter:on
|
||||
OAuth2ClientCredentialsGrantRequest request = new OAuth2ClientCredentialsGrantRequest(registration);
|
||||
OAuth2AccessTokenResponse response = this.client.getTokenResponse(request).block();
|
||||
verify(customClient, atLeastOnce()).post();
|
||||
|
@ -142,8 +164,11 @@ public class WebClientReactiveClientCredentialsTokenResponseClientTests {
|
|||
}
|
||||
|
||||
private void enqueueUnexpectedResponse() {
|
||||
MockResponse response = new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
// @formatter:off
|
||||
MockResponse response = new MockResponse()
|
||||
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setResponseCode(301);
|
||||
// @formatter:on
|
||||
this.server.enqueue(response);
|
||||
}
|
||||
|
||||
|
|
|
@ -81,8 +81,13 @@ public class WebClientReactivePasswordTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseThenReturnAccessTokenResponse() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
Instant expiresAtBefore = Instant.now().plusSeconds(3600);
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.build();
|
||||
|
@ -111,8 +116,13 @@ public class WebClientReactivePasswordTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenClientAuthenticationPostThenFormParametersAreSent() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.POST).build();
|
||||
|
@ -128,8 +138,13 @@ public class WebClientReactivePasswordTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseAndNotBearerTokenTypeThenThrowOAuth2AuthorizationException() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2PasswordGrantRequest passwordGrantRequest = new OAuth2PasswordGrantRequest(
|
||||
this.clientRegistrationBuilder.build(), this.username, this.password);
|
||||
|
@ -143,9 +158,14 @@ public class WebClientReactivePasswordTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseIncludesScopeThenAccessTokenHasResponseScope() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n" + " \"scope\": \"read\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2PasswordGrantRequest passwordGrantRequest = new OAuth2PasswordGrantRequest(
|
||||
this.clientRegistrationBuilder.build(), this.username, this.password);
|
||||
|
@ -159,7 +179,11 @@ public class WebClientReactivePasswordTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenErrorResponseThenThrowOAuth2AuthorizationException() {
|
||||
String accessTokenErrorResponse = "{\n" + " \"error\": \"unauthorized_client\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenErrorResponse = "{\n"
|
||||
+ " \"error\": \"unauthorized_client\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenErrorResponse).setResponseCode(400));
|
||||
OAuth2PasswordGrantRequest passwordGrantRequest = new OAuth2PasswordGrantRequest(
|
||||
this.clientRegistrationBuilder.build(), this.username, this.password);
|
||||
|
@ -182,7 +206,11 @@ public class WebClientReactivePasswordTokenResponseClientTests {
|
|||
}
|
||||
|
||||
private MockResponse jsonResponse(String json) {
|
||||
return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody(json);
|
||||
// @formatter:off
|
||||
return new MockResponse()
|
||||
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setBody(json);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -87,8 +87,13 @@ public class WebClientReactiveRefreshTokenTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseThenReturnAccessTokenResponse() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
Instant expiresAtBefore = Instant.now().plusSeconds(3600);
|
||||
OAuth2RefreshTokenGrantRequest refreshTokenGrantRequest = new OAuth2RefreshTokenGrantRequest(
|
||||
|
@ -115,8 +120,13 @@ public class WebClientReactiveRefreshTokenTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenClientAuthenticationPostThenFormParametersAreSent() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.POST).build();
|
||||
|
@ -132,8 +142,13 @@ public class WebClientReactiveRefreshTokenTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseAndNotBearerTokenTypeThenThrowOAuth2AuthorizationException() {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"not-bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2RefreshTokenGrantRequest refreshTokenGrantRequest = new OAuth2RefreshTokenGrantRequest(
|
||||
this.clientRegistrationBuilder.build(), this.accessToken, this.refreshToken);
|
||||
|
@ -146,9 +161,14 @@ public class WebClientReactiveRefreshTokenTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenSuccessResponseIncludesScopeThenAccessTokenHasResponseScope() throws Exception {
|
||||
String accessTokenSuccessResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n" + " \"scope\": \"read\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenSuccessResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenSuccessResponse));
|
||||
OAuth2RefreshTokenGrantRequest refreshTokenGrantRequest = new OAuth2RefreshTokenGrantRequest(
|
||||
this.clientRegistrationBuilder.build(), this.accessToken, this.refreshToken,
|
||||
|
@ -163,7 +183,11 @@ public class WebClientReactiveRefreshTokenTokenResponseClientTests {
|
|||
|
||||
@Test
|
||||
public void getTokenResponseWhenErrorResponseThenThrowOAuth2AuthorizationException() {
|
||||
String accessTokenErrorResponse = "{\n" + " \"error\": \"unauthorized_client\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenErrorResponse = "{\n"
|
||||
+ " \"error\": \"unauthorized_client\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenErrorResponse).setResponseCode(400));
|
||||
OAuth2RefreshTokenGrantRequest refreshTokenGrantRequest = new OAuth2RefreshTokenGrantRequest(
|
||||
this.clientRegistrationBuilder.build(), this.accessToken, this.refreshToken);
|
||||
|
@ -186,7 +210,11 @@ public class WebClientReactiveRefreshTokenTokenResponseClientTests {
|
|||
}
|
||||
|
||||
private MockResponse jsonResponse(String json) {
|
||||
return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody(json);
|
||||
// @formatter:off
|
||||
return new MockResponse()
|
||||
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setBody(json);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,8 +36,12 @@ public class OAuth2ErrorResponseErrorHandlerTests {
|
|||
|
||||
@Test
|
||||
public void handleErrorWhenErrorResponseBodyThenHandled() {
|
||||
String errorResponse = "{\n" + " \"error\": \"unauthorized_client\",\n"
|
||||
+ " \"error_description\": \"The client is not authorized\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String errorResponse = "{\n"
|
||||
+ " \"error\": \"unauthorized_client\",\n"
|
||||
+ " \"error_description\": \"The client is not authorized\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
MockClientHttpResponse response = new MockClientHttpResponse(errorResponse.getBytes(), HttpStatus.BAD_REQUEST);
|
||||
assertThatExceptionOfType(OAuth2AuthorizationException.class)
|
||||
.isThrownBy(() -> this.errorHandler.handleError(response))
|
||||
|
|
|
@ -55,8 +55,11 @@ public class OAuth2AuthorizationRequestMixinTests {
|
|||
Map<String, Object> additionalParameters = new LinkedHashMap<>();
|
||||
additionalParameters.put("param1", "value1");
|
||||
additionalParameters.put("param2", "value2");
|
||||
this.authorizationRequestBuilder = TestOAuth2AuthorizationRequests.request().scope("read", "write")
|
||||
// @formatter:off
|
||||
this.authorizationRequestBuilder = TestOAuth2AuthorizationRequests.request()
|
||||
.scope("read", "write")
|
||||
.additionalParameters(additionalParameters);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -69,8 +72,14 @@ public class OAuth2AuthorizationRequestMixinTests {
|
|||
|
||||
@Test
|
||||
public void serializeWhenRequiredAttributesOnlyThenSerializes() throws Exception {
|
||||
OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestBuilder.scopes(null).state(null)
|
||||
.additionalParameters(Map::clear).attributes(Map::clear).build();
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestBuilder
|
||||
.scopes(null)
|
||||
.state(null)
|
||||
.additionalParameters(Map::clear)
|
||||
.attributes(Map::clear)
|
||||
.build();
|
||||
// @formatter:on
|
||||
String expectedJson = asJson(authorizationRequest);
|
||||
String json = this.mapper.writeValueAsString(authorizationRequest);
|
||||
JSONAssert.assertEquals(expectedJson, json, true);
|
||||
|
@ -106,8 +115,13 @@ public class OAuth2AuthorizationRequestMixinTests {
|
|||
|
||||
@Test
|
||||
public void deserializeWhenRequiredAttributesOnlyThenDeserializes() throws Exception {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationRequest expectedAuthorizationRequest = this.authorizationRequestBuilder.scopes(null)
|
||||
.state(null).additionalParameters(Map::clear).attributes(Map::clear).build();
|
||||
.state(null)
|
||||
.additionalParameters(Map::clear)
|
||||
.attributes(Map::clear)
|
||||
.build();
|
||||
// @formatter:on
|
||||
String json = asJson(expectedAuthorizationRequest);
|
||||
OAuth2AuthorizationRequest authorizationRequest = this.mapper.readValue(json, OAuth2AuthorizationRequest.class);
|
||||
assertThat(authorizationRequest.getAuthorizationUri())
|
||||
|
|
|
@ -67,8 +67,11 @@ public class OAuth2AuthorizedClientMixinTests {
|
|||
Map<String, Object> providerConfigurationMetadata = new LinkedHashMap<>();
|
||||
providerConfigurationMetadata.put("config1", "value1");
|
||||
providerConfigurationMetadata.put("config2", "value2");
|
||||
this.clientRegistrationBuilder = TestClientRegistrations.clientRegistration().scope("read", "write")
|
||||
// @formatter:off
|
||||
this.clientRegistrationBuilder = TestClientRegistrations.clientRegistration()
|
||||
.scope("read", "write")
|
||||
.providerConfigurationMetadata(providerConfigurationMetadata);
|
||||
// @formatter:on
|
||||
this.accessToken = TestOAuth2AccessTokens.scopes("read", "write");
|
||||
this.refreshToken = TestOAuth2RefreshTokens.refreshToken();
|
||||
this.principalName = "principal-name";
|
||||
|
@ -85,8 +88,16 @@ public class OAuth2AuthorizedClientMixinTests {
|
|||
|
||||
@Test
|
||||
public void serializeWhenRequiredAttributesOnlyThenSerializes() throws Exception {
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().clientSecret(null)
|
||||
.clientName(null).userInfoUri(null).userNameAttributeName(null).jwkSetUri(null).issuerUri(null).build();
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration()
|
||||
.clientSecret(null)
|
||||
.clientName(null)
|
||||
.userInfoUri(null)
|
||||
.userNameAttributeName(null)
|
||||
.jwkSetUri(null)
|
||||
.issuerUri(null)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(clientRegistration, this.principalName,
|
||||
TestOAuth2AccessTokens.noScopes());
|
||||
String expectedJson = asJson(authorizedClient);
|
||||
|
@ -154,8 +165,16 @@ public class OAuth2AuthorizedClientMixinTests {
|
|||
|
||||
@Test
|
||||
public void deserializeWhenRequiredAttributesOnlyThenDeserializes() throws Exception {
|
||||
ClientRegistration expectedClientRegistration = TestClientRegistrations.clientRegistration().clientSecret(null)
|
||||
.clientName(null).userInfoUri(null).userNameAttributeName(null).jwkSetUri(null).issuerUri(null).build();
|
||||
// @formatter:off
|
||||
ClientRegistration expectedClientRegistration = TestClientRegistrations.clientRegistration()
|
||||
.clientSecret(null)
|
||||
.clientName(null)
|
||||
.userInfoUri(null)
|
||||
.userNameAttributeName(null)
|
||||
.jwkSetUri(null)
|
||||
.issuerUri(null)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AccessToken expectedAccessToken = TestOAuth2AccessTokens.noScopes();
|
||||
OAuth2AuthorizedClient expectedAuthorizedClient = new OAuth2AuthorizedClient(expectedClientRegistration,
|
||||
this.principalName, expectedAccessToken);
|
||||
|
|
|
@ -117,9 +117,15 @@ public class OidcAuthorizationCodeAuthenticationProviderTests {
|
|||
}
|
||||
catch (NoSuchAlgorithmException ex) {
|
||||
}
|
||||
this.authorizationRequest = TestOAuth2AuthorizationRequests.request().scope("openid", "profile", "email")
|
||||
.attributes(attributes).additionalParameters(additionalParameters).build();
|
||||
this.authorizationResponse = TestOAuth2AuthorizationResponses.success().build();
|
||||
// @formatter:off
|
||||
this.authorizationRequest = TestOAuth2AuthorizationRequests.request()
|
||||
.scope("openid", "profile", "email")
|
||||
.attributes(attributes)
|
||||
.additionalParameters(additionalParameters)
|
||||
.build();
|
||||
this.authorizationResponse = TestOAuth2AuthorizationResponses.success()
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.authorizationExchange = new OAuth2AuthorizationExchange(this.authorizationRequest,
|
||||
this.authorizationResponse);
|
||||
this.accessTokenResponseClient = mock(OAuth2AccessTokenResponseClient.class);
|
||||
|
@ -161,8 +167,11 @@ public class OidcAuthorizationCodeAuthenticationProviderTests {
|
|||
|
||||
@Test
|
||||
public void authenticateWhenAuthorizationRequestDoesNotContainOpenidScopeThenReturnNull() {
|
||||
OAuth2AuthorizationRequest authorizationRequest = TestOAuth2AuthorizationRequests.request().scope("scope1")
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationRequest authorizationRequest = TestOAuth2AuthorizationRequests.request()
|
||||
.scope("scope1")
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationExchange authorizationExchange = new OAuth2AuthorizationExchange(authorizationRequest,
|
||||
this.authorizationResponse);
|
||||
OAuth2LoginAuthenticationToken authentication = (OAuth2LoginAuthenticationToken) this.authenticationProvider
|
||||
|
@ -174,8 +183,11 @@ public class OidcAuthorizationCodeAuthenticationProviderTests {
|
|||
public void authenticateWhenAuthorizationErrorResponseThenThrowOAuth2AuthenticationException() {
|
||||
this.exception.expect(OAuth2AuthenticationException.class);
|
||||
this.exception.expectMessage(containsString(OAuth2ErrorCodes.INVALID_SCOPE));
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationResponse authorizationResponse = TestOAuth2AuthorizationResponses.error()
|
||||
.errorCode(OAuth2ErrorCodes.INVALID_SCOPE).build();
|
||||
.errorCode(OAuth2ErrorCodes.INVALID_SCOPE)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationExchange authorizationExchange = new OAuth2AuthorizationExchange(this.authorizationRequest,
|
||||
authorizationResponse);
|
||||
this.authenticationProvider
|
||||
|
@ -186,8 +198,11 @@ public class OidcAuthorizationCodeAuthenticationProviderTests {
|
|||
public void authenticateWhenAuthorizationResponseStateNotEqualAuthorizationRequestStateThenThrowOAuth2AuthenticationException() {
|
||||
this.exception.expect(OAuth2AuthenticationException.class);
|
||||
this.exception.expectMessage(containsString("invalid_state_parameter"));
|
||||
OAuth2AuthorizationResponse authorizationResponse = TestOAuth2AuthorizationResponses.success().state("89012")
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationResponse authorizationResponse = TestOAuth2AuthorizationResponses.success()
|
||||
.state("89012")
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationExchange authorizationExchange = new OAuth2AuthorizationExchange(this.authorizationRequest,
|
||||
authorizationResponse);
|
||||
this.authenticationProvider
|
||||
|
@ -198,8 +213,12 @@ public class OidcAuthorizationCodeAuthenticationProviderTests {
|
|||
public void authenticateWhenTokenResponseDoesNotContainIdTokenThenThrowOAuth2AuthenticationException() {
|
||||
this.exception.expect(OAuth2AuthenticationException.class);
|
||||
this.exception.expectMessage(containsString("invalid_id_token"));
|
||||
// @formatter:off
|
||||
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse
|
||||
.withResponse(this.accessTokenSuccessResponse()).additionalParameters(Collections.emptyMap()).build();
|
||||
.withResponse(this.accessTokenSuccessResponse())
|
||||
.additionalParameters(Collections.emptyMap())
|
||||
.build();
|
||||
// @formatter:on
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(accessTokenResponse);
|
||||
this.authenticationProvider
|
||||
.authenticate(new OAuth2LoginAuthenticationToken(this.clientRegistration, this.authorizationExchange));
|
||||
|
@ -209,7 +228,11 @@ public class OidcAuthorizationCodeAuthenticationProviderTests {
|
|||
public void authenticateWhenJwkSetUriNotSetThenThrowOAuth2AuthenticationException() {
|
||||
this.exception.expect(OAuth2AuthenticationException.class);
|
||||
this.exception.expectMessage(containsString("missing_signature_verifier"));
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().jwkSetUri(null).build();
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration()
|
||||
.jwkSetUri(null)
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.authenticationProvider
|
||||
.authenticate(new OAuth2LoginAuthenticationToken(clientRegistration, this.authorizationExchange));
|
||||
}
|
||||
|
@ -323,9 +346,15 @@ public class OidcAuthorizationCodeAuthenticationProviderTests {
|
|||
additionalParameters.put("param1", "value1");
|
||||
additionalParameters.put("param2", "value2");
|
||||
additionalParameters.put(OidcParameterNames.ID_TOKEN, "id-token");
|
||||
return OAuth2AccessTokenResponse.withToken("access-token-1234").tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.expiresIn(expiresAt.getEpochSecond()).scopes(scopes).refreshToken("refresh-token-1234")
|
||||
.additionalParameters(additionalParameters).build();
|
||||
// @formatter:off
|
||||
return OAuth2AccessTokenResponse.withToken("access-token-1234")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.expiresIn(expiresAt.getEpochSecond())
|
||||
.scopes(scopes)
|
||||
.refreshToken("refresh-token-1234")
|
||||
.additionalParameters(additionalParameters)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -90,10 +90,15 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests {
|
|||
@Mock
|
||||
private ReactiveJwtDecoder jwtDecoder;
|
||||
|
||||
private ClientRegistration.Builder registration = TestClientRegistrations.clientRegistration().scope("openid");
|
||||
// @formatter:off
|
||||
private ClientRegistration.Builder registration = TestClientRegistrations.clientRegistration()
|
||||
.scope("openid");
|
||||
// @formatter:on
|
||||
|
||||
// @formatter:off
|
||||
private OAuth2AuthorizationResponse.Builder authorizationResponseBldr = OAuth2AuthorizationResponse.success("code")
|
||||
.state("state");
|
||||
// @formatter:on
|
||||
|
||||
private OidcIdToken idToken = TestOidcIdTokens.idToken().build();
|
||||
|
||||
|
@ -153,7 +158,10 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests {
|
|||
|
||||
@Test
|
||||
public void authenticationWhenErrorThenOAuth2AuthenticationException() {
|
||||
this.authorizationResponseBldr = OAuth2AuthorizationResponse.error("error").state("state");
|
||||
// @formatter:off
|
||||
this.authorizationResponseBldr = OAuth2AuthorizationResponse.error("error")
|
||||
.state("state");
|
||||
// @formatter:on
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
.isThrownBy(() -> this.manager.authenticate(loginToken()).block());
|
||||
}
|
||||
|
@ -167,10 +175,12 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests {
|
|||
|
||||
@Test
|
||||
public void authenticateWhenIdTokenValidationErrorThenOAuth2AuthenticationException() {
|
||||
// @formatter:off
|
||||
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER).additionalParameters(
|
||||
Collections.singletonMap(OidcParameterNames.ID_TOKEN, this.idToken.getTokenValue()))
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.additionalParameters(Collections.singletonMap(OidcParameterNames.ID_TOKEN, this.idToken.getTokenValue()))
|
||||
.build();
|
||||
// @formatter:on
|
||||
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(Mono.just(accessTokenResponse));
|
||||
given(this.jwtDecoder.decode(any())).willThrow(new JwtException("ID Token Validation Error"));
|
||||
this.manager.setJwtDecoderFactory((c) -> this.jwtDecoder);
|
||||
|
@ -181,10 +191,13 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests {
|
|||
|
||||
@Test
|
||||
public void authenticateWhenIdTokenInvalidNonceThenOAuth2AuthenticationException() {
|
||||
// @formatter:off
|
||||
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER).additionalParameters(
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.additionalParameters(
|
||||
Collections.singletonMap(OidcParameterNames.ID_TOKEN, this.idToken.getTokenValue()))
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication = loginToken();
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com");
|
||||
|
@ -202,11 +215,13 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests {
|
|||
|
||||
@Test
|
||||
public void authenticationWhenOAuth2UserNotFoundThenEmpty() {
|
||||
// @formatter:off
|
||||
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.additionalParameters(Collections.singletonMap(OidcParameterNames.ID_TOKEN,
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ."))
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication = loginToken();
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com");
|
||||
|
@ -223,10 +238,14 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests {
|
|||
|
||||
@Test
|
||||
public void authenticationWhenOAuth2UserFoundThenSuccess() {
|
||||
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER).additionalParameters(
|
||||
// @formatter:off
|
||||
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse
|
||||
.withToken("foo")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.additionalParameters(
|
||||
Collections.singletonMap(OidcParameterNames.ID_TOKEN, this.idToken.getTokenValue()))
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication = loginToken();
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com");
|
||||
|
@ -248,11 +267,15 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests {
|
|||
|
||||
@Test
|
||||
public void authenticationWhenRefreshTokenThenRefreshTokenInAuthorizedClient() {
|
||||
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo")
|
||||
// @formatter:off
|
||||
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse
|
||||
.withToken("foo")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.additionalParameters(
|
||||
Collections.singletonMap(OidcParameterNames.ID_TOKEN, this.idToken.getTokenValue()))
|
||||
.refreshToken("refresh-token").build();
|
||||
.refreshToken("refresh-token")
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication = loginToken();
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com");
|
||||
|
@ -281,8 +304,13 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests {
|
|||
additionalParameters.put(OidcParameterNames.ID_TOKEN, this.idToken.getTokenValue());
|
||||
additionalParameters.put("param1", "value1");
|
||||
additionalParameters.put("param2", "value2");
|
||||
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER).additionalParameters(additionalParameters).build();
|
||||
// @formatter:off
|
||||
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse
|
||||
.withToken("foo")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.additionalParameters(additionalParameters)
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication = loginToken();
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com");
|
||||
|
@ -304,10 +332,13 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests {
|
|||
@Test
|
||||
public void authenticateWhenAuthoritiesMapperSetThenReturnMappedAuthorities() {
|
||||
ClientRegistration clientRegistration = this.registration.build();
|
||||
// @formatter:off
|
||||
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER).additionalParameters(
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.additionalParameters(
|
||||
Collections.singletonMap(OidcParameterNames.ID_TOKEN, this.idToken.getTokenValue()))
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication = loginToken();
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com");
|
||||
|
@ -342,13 +373,19 @@ public class OidcAuthorizationCodeReactiveAuthenticationManagerTests {
|
|||
}
|
||||
catch (NoSuchAlgorithmException ex) {
|
||||
}
|
||||
OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode().state("state")
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
|
||||
.state("state")
|
||||
.clientId(clientRegistration.getClientId())
|
||||
.authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri())
|
||||
.redirectUri(clientRegistration.getRedirectUri()).scopes(clientRegistration.getScopes())
|
||||
.additionalParameters(additionalParameters).attributes(attributes).build();
|
||||
.redirectUri(clientRegistration.getRedirectUri())
|
||||
.scopes(clientRegistration.getScopes())
|
||||
.additionalParameters(additionalParameters)
|
||||
.attributes(attributes).build();
|
||||
OAuth2AuthorizationResponse authorizationResponse = this.authorizationResponseBldr
|
||||
.redirectUri(clientRegistration.getRedirectUri()).build();
|
||||
.redirectUri(clientRegistration.getRedirectUri())
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationExchange authorizationExchange = new OAuth2AuthorizationExchange(authorizationRequest,
|
||||
authorizationResponse);
|
||||
return new OAuth2AuthorizationCodeAuthenticationToken(clientRegistration, authorizationExchange);
|
||||
|
|
|
@ -50,7 +50,11 @@ import static org.mockito.Mockito.verify;
|
|||
*/
|
||||
public class OidcIdTokenDecoderFactoryTests {
|
||||
|
||||
private ClientRegistration.Builder registration = TestClientRegistrations.clientRegistration().scope("openid");
|
||||
// @formatter:off
|
||||
private ClientRegistration.Builder registration = TestClientRegistrations
|
||||
.clientRegistration()
|
||||
.scope("openid");
|
||||
// @formatter:on
|
||||
|
||||
private OidcIdTokenDecoderFactory idTokenDecoderFactory;
|
||||
|
||||
|
|
|
@ -72,26 +72,39 @@ public class OidcIdTokenValidatorTests {
|
|||
@Test
|
||||
public void setClockSkewWhenNullThenThrowIllegalArgumentException() {
|
||||
OidcIdTokenValidator idTokenValidator = new OidcIdTokenValidator(this.registration.build());
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> idTokenValidator.setClockSkew(null));
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> idTokenValidator.setClockSkew(null));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockSkewWhenNegativeSecondsThenThrowIllegalArgumentException() {
|
||||
OidcIdTokenValidator idTokenValidator = new OidcIdTokenValidator(this.registration.build());
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> idTokenValidator.setClockSkew(Duration.ofSeconds(-1)));
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> idTokenValidator.setClockSkew(Duration.ofSeconds(-1)));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClockWhenNullThenThrowIllegalArgumentException() {
|
||||
OidcIdTokenValidator idTokenValidator = new OidcIdTokenValidator(this.registration.build());
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> idTokenValidator.setClock(null));
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> idTokenValidator.setClock(null));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateWhenIssuerNullThenHasErrors() {
|
||||
this.claims.remove(IdTokenClaimNames.ISS);
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.ISS));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -101,8 +114,12 @@ public class OidcIdTokenValidatorTests {
|
|||
* issuer in the ID Token, the validation must fail
|
||||
*/
|
||||
this.registration = this.registration.issuerUri("https://somethingelse.com");
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.ISS));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -118,22 +135,34 @@ public class OidcIdTokenValidatorTests {
|
|||
@Test
|
||||
public void validateWhenSubNullThenHasErrors() {
|
||||
this.claims.remove(IdTokenClaimNames.SUB);
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.SUB));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateWhenAudNullThenHasErrors() {
|
||||
this.claims.remove(IdTokenClaimNames.AUD);
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.AUD));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateWhenIssuedAtNullThenHasErrors() {
|
||||
this.issuedAt = null;
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.IAT));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -146,15 +175,23 @@ public class OidcIdTokenValidatorTests {
|
|||
@Test
|
||||
public void validateWhenAudMultipleAndAzpNullThenHasErrors() {
|
||||
this.claims.put(IdTokenClaimNames.AUD, Arrays.asList("client-id", "other"));
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.AZP));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateWhenAzpNotClientIdThenHasErrors() {
|
||||
this.claims.put(IdTokenClaimNames.AZP, "other");
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.AZP));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -168,15 +205,23 @@ public class OidcIdTokenValidatorTests {
|
|||
public void validateWhenMultipleAudAzpNotClientIdThenHasErrors() {
|
||||
this.claims.put(IdTokenClaimNames.AUD, Arrays.asList("client-id-1", "client-id-2"));
|
||||
this.claims.put(IdTokenClaimNames.AZP, "other-client");
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.AZP));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateWhenAudNotClientIdThenHasErrors() {
|
||||
this.claims.put(IdTokenClaimNames.AUD, Collections.singletonList("other-client"));
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.AUD));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -192,8 +237,12 @@ public class OidcIdTokenValidatorTests {
|
|||
this.issuedAt = Instant.now().minus(Duration.ofSeconds(60));
|
||||
this.expiresAt = this.issuedAt.plus(Duration.ofSeconds(30));
|
||||
this.clockSkew = Duration.ofSeconds(0);
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.EXP));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -209,8 +258,12 @@ public class OidcIdTokenValidatorTests {
|
|||
this.issuedAt = Instant.now().plus(Duration.ofMinutes(1));
|
||||
this.expiresAt = this.issuedAt.plus(Duration.ofSeconds(60));
|
||||
this.clockSkew = Duration.ofMinutes(0);
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.IAT));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -218,8 +271,12 @@ public class OidcIdTokenValidatorTests {
|
|||
this.issuedAt = Instant.now().minus(Duration.ofSeconds(10));
|
||||
this.expiresAt = this.issuedAt.plus(Duration.ofSeconds(5));
|
||||
this.clockSkew = Duration.ofSeconds(0);
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.EXP));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -228,24 +285,38 @@ public class OidcIdTokenValidatorTests {
|
|||
this.claims.remove(IdTokenClaimNames.AUD);
|
||||
this.issuedAt = null;
|
||||
this.expiresAt = null;
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.SUB))
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.AUD))
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.IAT))
|
||||
.allMatch((msg) -> msg.contains(IdTokenClaimNames.EXP));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateFormatError() {
|
||||
this.claims.remove(IdTokenClaimNames.SUB);
|
||||
this.claims.remove(IdTokenClaimNames.AUD);
|
||||
assertThat(this.validateIdToken()).hasSize(1).extracting(OAuth2Error::getDescription)
|
||||
// @formatter:off
|
||||
assertThat(this.validateIdToken())
|
||||
.hasSize(1)
|
||||
.extracting(OAuth2Error::getDescription)
|
||||
.allMatch((msg) -> msg.equals("The ID Token contains invalid claims: {sub=null, aud=null}"));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Collection<OAuth2Error> validateIdToken() {
|
||||
Jwt idToken = Jwt.withTokenValue("token").issuedAt(this.issuedAt).expiresAt(this.expiresAt)
|
||||
.headers((h) -> h.putAll(this.headers)).claims((c) -> c.putAll(this.claims)).build();
|
||||
// @formatter:off
|
||||
Jwt idToken = Jwt.withTokenValue("token")
|
||||
.issuedAt(this.issuedAt)
|
||||
.expiresAt(this.expiresAt)
|
||||
.headers((h) -> h.putAll(this.headers))
|
||||
.claims((c) -> c.putAll(this.claims))
|
||||
.build();
|
||||
// @formatter:on
|
||||
OidcIdTokenValidator validator = new OidcIdTokenValidator(this.registration.build());
|
||||
validator.setClockSkew(this.clockSkew);
|
||||
return validator.validate(idToken).getErrors();
|
||||
|
|
|
@ -50,7 +50,10 @@ import static org.mockito.Mockito.verify;
|
|||
*/
|
||||
public class ReactiveOidcIdTokenDecoderFactoryTests {
|
||||
|
||||
private ClientRegistration.Builder registration = TestClientRegistrations.clientRegistration().scope("openid");
|
||||
// @formatter:off
|
||||
private ClientRegistration.Builder registration = TestClientRegistrations.clientRegistration()
|
||||
.scope("openid");
|
||||
// @formatter:on
|
||||
|
||||
private ReactiveOidcIdTokenDecoderFactory idTokenDecoderFactory;
|
||||
|
||||
|
|
|
@ -157,9 +157,16 @@ public class OidcUserServiceTests {
|
|||
// gh-6886
|
||||
@Test
|
||||
public void loadUserWhenNonStandardScopesAuthorizedAndAccessibleScopesMatchThenUserInfoEndpointRequested() {
|
||||
String userInfoResponse = "{\n" + " \"sub\": \"subject1\",\n" + " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n" + " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"sub\": \"subject1\",\n"
|
||||
+ " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n"
|
||||
+ " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
|
||||
|
@ -173,9 +180,16 @@ public class OidcUserServiceTests {
|
|||
// gh-6886
|
||||
@Test
|
||||
public void loadUserWhenNonStandardScopesAuthorizedAndAccessibleScopesEmptyThenUserInfoEndpointRequested() {
|
||||
String userInfoResponse = "{\n" + " \"sub\": \"subject1\",\n" + " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n" + " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"sub\": \"subject1\",\n"
|
||||
+ " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n"
|
||||
+ " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
|
||||
|
@ -189,9 +203,16 @@ public class OidcUserServiceTests {
|
|||
// gh-6886
|
||||
@Test
|
||||
public void loadUserWhenStandardScopesAuthorizedThenUserInfoEndpointRequested() {
|
||||
String userInfoResponse = "{\n" + " \"sub\": \"subject1\",\n" + " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n" + " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"sub\": \"subject1\",\n"
|
||||
+ " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n"
|
||||
+ " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
|
||||
|
@ -202,9 +223,16 @@ public class OidcUserServiceTests {
|
|||
|
||||
@Test
|
||||
public void loadUserWhenUserInfoSuccessResponseThenReturnUser() {
|
||||
String userInfoResponse = "{\n" + " \"sub\": \"subject1\",\n" + " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n" + " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"sub\": \"subject1\",\n"
|
||||
+ " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n"
|
||||
+ " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
|
||||
|
@ -234,8 +262,12 @@ public class OidcUserServiceTests {
|
|||
public void loadUserWhenUserInfoSuccessResponseAndUserInfoSubjectIsNullThenThrowOAuth2AuthenticationException() {
|
||||
this.exception.expect(OAuth2AuthenticationException.class);
|
||||
this.exception.expectMessage(containsString("invalid_user_info_response"));
|
||||
String userInfoResponse = "{\n" + " \"email\": \"full_name@provider.com\",\n" + " \"name\": \"full name\"\n"
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"email\": \"full_name@provider.com\",\n"
|
||||
+ " \"name\": \"full name\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri)
|
||||
|
@ -259,10 +291,16 @@ public class OidcUserServiceTests {
|
|||
this.exception.expect(OAuth2AuthenticationException.class);
|
||||
this.exception.expectMessage(containsString(
|
||||
"[invalid_user_info_response] An error occurred while attempting to retrieve the UserInfo Resource"));
|
||||
String userInfoResponse = "{\n" + " \"sub\": \"subject1\",\n" + " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n" + " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n" + " \"email\": \"user1@example.com\"\n";
|
||||
// "}\n"; // Make the JSON invalid/malformed
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"sub\": \"subject1\",\n"
|
||||
+ " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n"
|
||||
+ " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n";
|
||||
// "}\n"; // Make the JSON invalid/malformed
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
|
||||
|
@ -292,9 +330,16 @@ public class OidcUserServiceTests {
|
|||
|
||||
@Test
|
||||
public void loadUserWhenCustomUserNameAttributeNameThenGetNameReturnsCustomUserName() {
|
||||
String userInfoResponse = "{\n" + " \"sub\": \"subject1\",\n" + " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n" + " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"sub\": \"subject1\",\n"
|
||||
+ " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n"
|
||||
+ " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri)
|
||||
|
@ -307,9 +352,16 @@ public class OidcUserServiceTests {
|
|||
// gh-5294
|
||||
@Test
|
||||
public void loadUserWhenUserInfoSuccessResponseThenAcceptHeaderJson() throws Exception {
|
||||
String userInfoResponse = "{\n" + " \"sub\": \"subject1\",\n" + " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n" + " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"sub\": \"subject1\",\n"
|
||||
+ " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n"
|
||||
+ " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
|
||||
|
@ -321,9 +373,16 @@ public class OidcUserServiceTests {
|
|||
// gh-5500
|
||||
@Test
|
||||
public void loadUserWhenAuthenticationMethodHeaderSuccessResponseThenHttpMethodGet() throws Exception {
|
||||
String userInfoResponse = "{\n" + " \"sub\": \"subject1\",\n" + " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n" + " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"sub\": \"subject1\",\n"
|
||||
+ " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n"
|
||||
+ " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
|
||||
|
@ -338,9 +397,16 @@ public class OidcUserServiceTests {
|
|||
// gh-5500
|
||||
@Test
|
||||
public void loadUserWhenAuthenticationMethodFormSuccessResponseThenHttpMethodPost() throws Exception {
|
||||
String userInfoResponse = "{\n" + " \"sub\": \"subject1\",\n" + " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n" + " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"sub\": \"subject1\",\n"
|
||||
+ " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n"
|
||||
+ " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri)
|
||||
|
@ -355,9 +421,16 @@ public class OidcUserServiceTests {
|
|||
|
||||
@Test
|
||||
public void loadUserWhenCustomClaimTypeConverterFactorySetThenApplied() {
|
||||
String userInfoResponse = "{\n" + " \"sub\": \"subject1\",\n" + " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n" + " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"sub\": \"subject1\",\n"
|
||||
+ " \"name\": \"first last\",\n"
|
||||
+ " \"given_name\": \"first\",\n"
|
||||
+ " \"family_name\": \"last\",\n"
|
||||
+ " \"preferred_username\": \"user1\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
|
||||
|
@ -395,7 +468,11 @@ public class OidcUserServiceTests {
|
|||
}
|
||||
|
||||
private MockResponse jsonResponse(String json) {
|
||||
return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody(json);
|
||||
// @formatter:off
|
||||
return new MockResponse()
|
||||
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setBody(json);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,9 +49,12 @@ import static org.mockito.Mockito.mock;
|
|||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class OidcClientInitiatedLogoutSuccessHandlerTests {
|
||||
|
||||
ClientRegistration registration = TestClientRegistrations.clientRegistration()
|
||||
// @formatter:off
|
||||
ClientRegistration registration = TestClientRegistrations
|
||||
.clientRegistration()
|
||||
.providerConfigurationMetadata(Collections.singletonMap("end_session_endpoint", "https://endpoint"))
|
||||
.build();
|
||||
// @formatter:on
|
||||
|
||||
ClientRegistrationRepository repository = new InMemoryClientRegistrationRepository(this.registration);
|
||||
|
||||
|
|
|
@ -51,9 +51,12 @@ import static org.mockito.Mockito.mock;
|
|||
*/
|
||||
public class OidcClientInitiatedServerLogoutSuccessHandlerTests {
|
||||
|
||||
ClientRegistration registration = TestClientRegistrations.clientRegistration()
|
||||
// @formatter:off
|
||||
ClientRegistration registration = TestClientRegistrations
|
||||
.clientRegistration()
|
||||
.providerConfigurationMetadata(Collections.singletonMap("end_session_endpoint", "https://endpoint"))
|
||||
.build();
|
||||
// @formatter:on
|
||||
|
||||
ReactiveClientRegistrationRepository repository = new InMemoryReactiveClientRegistrationRepository(
|
||||
this.registration);
|
||||
|
|
|
@ -72,21 +72,42 @@ public class ClientRegistrationTests {
|
|||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void buildWhenAuthorizationGrantTypeIsNullThenThrowIllegalArgumentException() {
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC).authorizationGrantType(null)
|
||||
.redirectUri(REDIRECT_URI).scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI).userInfoAuthenticationMethod(AuthenticationMethod.FORM).jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME).build();
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(null)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeGrantAllAttributesProvidedThenAllAttributesAreSet() {
|
||||
ClientRegistration registration = ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET).clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).jwkSetUri(JWK_SET_URI).issuerUri(ISSUER_URI)
|
||||
.providerConfigurationMetadata(PROVIDER_CONFIGURATION_METADATA).clientName(CLIENT_NAME).build();
|
||||
// @formatter:off
|
||||
ClientRegistration registration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.issuerUri(ISSUER_URI)
|
||||
.providerConfigurationMetadata(PROVIDER_CONFIGURATION_METADATA)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(registration.getRegistrationId()).isEqualTo(REGISTRATION_ID);
|
||||
assertThat(registration.getClientId()).isEqualTo(CLIENT_ID);
|
||||
assertThat(registration.getClientSecret()).isEqualTo(CLIENT_SECRET);
|
||||
|
@ -107,172 +128,308 @@ public class ClientRegistrationTests {
|
|||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void buildWhenAuthorizationCodeGrantRegistrationIdIsNullThenThrowIllegalArgumentException() {
|
||||
ClientRegistration.withRegistrationId(null).clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(null)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).jwkSetUri(JWK_SET_URI).clientName(CLIENT_NAME)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void buildWhenAuthorizationCodeGrantClientIdIsNullThenThrowIllegalArgumentException() {
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(null).clientSecret(CLIENT_SECRET)
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(null)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).jwkSetUri(JWK_SET_URI).clientName(CLIENT_NAME)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeGrantClientSecretIsNullThenDefaultToEmpty() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID).clientSecret(null).clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).jwkSetUri(JWK_SET_URI).clientName(CLIENT_NAME)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(null)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getClientSecret()).isEqualTo("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeGrantClientAuthenticationMethodNotProvidedThenDefaultToBasic() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).jwkSetUri(JWK_SET_URI).clientName(CLIENT_NAME)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeGrantClientAuthenticationMethodNotProvidedAndClientSecretNullThenDefaultToNone() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID).clientSecret(null)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).jwkSetUri(JWK_SET_URI).clientName(CLIENT_NAME)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(null)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeGrantClientAuthenticationMethodNotProvidedAndClientSecretBlankThenDefaultToNone() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID).clientSecret(" ").authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI).scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI).userInfoAuthenticationMethod(AuthenticationMethod.FORM).jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME).build();
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(" ")
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.NONE);
|
||||
assertThat(clientRegistration.getClientSecret()).isEqualTo("");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void buildWhenAuthorizationCodeGrantRedirectUriIsNullThenThrowIllegalArgumentException() {
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(null)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).jwkSetUri(JWK_SET_URI).clientName(CLIENT_NAME)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(null)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// gh-5494
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeGrantScopeIsNullThenScopeNotRequired() {
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope((String[]) null).authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).jwkSetUri(JWK_SET_URI).clientName(CLIENT_NAME)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope((String[]) null)
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void buildWhenAuthorizationCodeGrantAuthorizationUriIsNullThenThrowIllegalArgumentException() {
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(null).tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).jwkSetUri(JWK_SET_URI).clientName(CLIENT_NAME)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(null)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void buildWhenAuthorizationCodeGrantTokenUriIsNullThenThrowIllegalArgumentException() {
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI).tokenUri(null)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).jwkSetUri(JWK_SET_URI).clientName(CLIENT_NAME)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(null)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeGrantClientNameNotProvidedThenDefaultToRegistrationId() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).jwkSetUri(JWK_SET_URI).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getClientName()).isEqualTo(clientRegistration.getRegistrationId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeGrantScopeDoesNotContainOpenidThenJwkSetUriNotRequired() {
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope("scope1").authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).tokenUri(TOKEN_URI).clientName(CLIENT_NAME)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope("scope1")
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// gh-5494
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeGrantScopeIsNullThenJwkSetUriNotRequired() {
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI).clientName(CLIENT_NAME).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeGrantProviderConfigurationMetadataIsNullThenDefaultToEmpty() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.HEADER).providerConfigurationMetadata(null)
|
||||
.jwkSetUri(JWK_SET_URI).clientName(CLIENT_NAME).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.HEADER)
|
||||
.providerConfigurationMetadata(null)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getProviderDetails().getConfigurationMetadata()).isNotNull();
|
||||
assertThat(clientRegistration.getProviderDetails().getConfigurationMetadata()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenAuthorizationCodeGrantProviderConfigurationMetadataEmptyThenIsEmpty() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.HEADER)
|
||||
.providerConfigurationMetadata(Collections.emptyMap()).jwkSetUri(JWK_SET_URI).clientName(CLIENT_NAME)
|
||||
.providerConfigurationMetadata(Collections.emptyMap())
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getProviderDetails().getConfigurationMetadata()).isNotNull();
|
||||
assertThat(clientRegistration.getProviderDetails().getConfigurationMetadata()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenImplicitGrantAllAttributesProvidedThenAllAttributesAreSet() {
|
||||
ClientRegistration registration = ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID)
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).clientName(CLIENT_NAME).build();
|
||||
// @formatter:off
|
||||
ClientRegistration registration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(registration.getRegistrationId()).isEqualTo(REGISTRATION_ID);
|
||||
assertThat(registration.getClientId()).isEqualTo(CLIENT_ID);
|
||||
assertThat(registration.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.IMPLICIT);
|
||||
|
@ -286,72 +443,129 @@ public class ClientRegistrationTests {
|
|||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void buildWhenImplicitGrantRegistrationIdIsNullThenThrowIllegalArgumentException() {
|
||||
ClientRegistration.withRegistrationId(null).clientId(CLIENT_ID)
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).clientName(CLIENT_NAME).build();
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(null)
|
||||
.clientId(CLIENT_ID)
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void buildWhenImplicitGrantClientIdIsNullThenThrowIllegalArgumentException() {
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(null)
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).clientName(CLIENT_NAME).build();
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(null)
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void buildWhenImplicitGrantRedirectUriIsNullThenThrowIllegalArgumentException() {
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID)
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT).redirectUri(null)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).clientName(CLIENT_NAME).build();
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT)
|
||||
.redirectUri(null)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// gh-5494
|
||||
@Test
|
||||
public void buildWhenImplicitGrantScopeIsNullThenScopeNotRequired() {
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID)
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT).redirectUri(REDIRECT_URI)
|
||||
.scope((String[]) null).authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).clientName(CLIENT_NAME).build();
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope((String[]) null)
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void buildWhenImplicitGrantAuthorizationUriIsNullThenThrowIllegalArgumentException() {
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID)
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(null)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).clientName(CLIENT_NAME).build();
|
||||
// @formatter:off
|
||||
ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(null)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenImplicitGrantClientNameNotProvidedThenDefaultToRegistrationId() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID).authorizationGrantType(AuthorizationGrantType.IMPLICIT).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM).build();
|
||||
.clientId(CLIENT_ID)
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.userInfoAuthenticationMethod(AuthenticationMethod.FORM)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getClientName()).isEqualTo(clientRegistration.getRegistrationId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenOverrideRegistrationIdThenOverridden() {
|
||||
String overriddenId = "override";
|
||||
// @formatter:off
|
||||
ClientRegistration registration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.registrationId(overriddenId).clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
.registrationId(overriddenId)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0])).authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI)
|
||||
.jwkSetUri(JWK_SET_URI).clientName(CLIENT_NAME).build();
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.jwkSetUri(JWK_SET_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(registration.getRegistrationId()).isEqualTo(overriddenId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenClientCredentialsGrantAllAttributesProvidedThenAllAttributesAreSet() {
|
||||
ClientRegistration registration = ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET).clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).scope(SCOPES.toArray(new String[0]))
|
||||
.tokenUri(TOKEN_URI).clientName(CLIENT_NAME).build();
|
||||
// @formatter:off
|
||||
ClientRegistration registration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.tokenUri(TOKEN_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(registration.getRegistrationId()).isEqualTo(REGISTRATION_ID);
|
||||
assertThat(registration.getClientId()).isEqualTo(CLIENT_ID);
|
||||
assertThat(registration.getClientSecret()).isEqualTo(CLIENT_SECRET);
|
||||
|
@ -379,17 +593,28 @@ public class ClientRegistrationTests {
|
|||
|
||||
@Test
|
||||
public void buildWhenClientCredentialsGrantClientSecretIsNullThenDefaultToEmpty() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID).clientSecret(null).clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).tokenUri(TOKEN_URI).build();
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(null)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getClientSecret()).isEqualTo("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenClientCredentialsGrantClientAuthenticationMethodNotProvidedThenDefaultToBasic() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID).clientSecret(CLIENT_SECRET)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).tokenUri(TOKEN_URI).build();
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
|
||||
}
|
||||
|
||||
|
@ -416,10 +641,17 @@ public class ClientRegistrationTests {
|
|||
|
||||
@Test
|
||||
public void buildWhenPasswordGrantAllAttributesProvidedThenAllAttributesAreSet() {
|
||||
ClientRegistration registration = ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET).clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD).scope(SCOPES.toArray(new String[0]))
|
||||
.tokenUri(TOKEN_URI).clientName(CLIENT_NAME).build();
|
||||
// @formatter:off
|
||||
ClientRegistration registration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.tokenUri(TOKEN_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(registration.getRegistrationId()).isEqualTo(REGISTRATION_ID);
|
||||
assertThat(registration.getClientId()).isEqualTo(CLIENT_ID);
|
||||
assertThat(registration.getClientSecret()).isEqualTo(CLIENT_SECRET);
|
||||
|
@ -432,50 +664,91 @@ public class ClientRegistrationTests {
|
|||
|
||||
@Test
|
||||
public void buildWhenPasswordGrantRegistrationIdIsNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> ClientRegistration.withRegistrationId(null).clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET).clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD).tokenUri(TOKEN_URI).build());
|
||||
.isThrownBy(() -> ClientRegistration.withRegistrationId(null)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.build()
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenPasswordGrantClientIdIsNullThenThrowIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(null).clientSecret(CLIENT_SECRET).clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD).tokenUri(TOKEN_URI).build());
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> ClientRegistration
|
||||
.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(null)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.build()
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenPasswordGrantClientSecretIsNullThenDefaultToEmpty() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID).clientSecret(null).clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD).tokenUri(TOKEN_URI).build();
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(null)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getClientSecret()).isEqualTo("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenPasswordGrantClientAuthenticationMethodNotProvidedThenDefaultToBasic() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID).clientSecret(CLIENT_SECRET).authorizationGrantType(AuthorizationGrantType.PASSWORD)
|
||||
.tokenUri(TOKEN_URI).build();
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenPasswordGrantTokenUriIsNullThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET).clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD).tokenUri(null).build());
|
||||
.isThrownBy(() -> ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
|
||||
.tokenUri(null)
|
||||
.build()
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenCustomGrantAllAttributesProvidedThenAllAttributesAreSet() {
|
||||
AuthorizationGrantType customGrantType = new AuthorizationGrantType("CUSTOM");
|
||||
ClientRegistration registration = ClientRegistration.withRegistrationId(REGISTRATION_ID).clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET).clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(customGrantType).scope(SCOPES.toArray(new String[0])).tokenUri(TOKEN_URI)
|
||||
.clientName(CLIENT_NAME).build();
|
||||
// @formatter:off
|
||||
ClientRegistration registration = ClientRegistration
|
||||
.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID)
|
||||
.clientSecret(CLIENT_SECRET)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(customGrantType)
|
||||
.scope(SCOPES.toArray(new String[0]))
|
||||
.tokenUri(TOKEN_URI)
|
||||
.clientName(CLIENT_NAME)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(registration.getRegistrationId()).isEqualTo(REGISTRATION_ID);
|
||||
assertThat(registration.getClientId()).isEqualTo(CLIENT_ID);
|
||||
assertThat(registration.getClientSecret()).isEqualTo(CLIENT_SECRET);
|
||||
|
@ -532,9 +805,13 @@ public class ClientRegistrationTests {
|
|||
@Test
|
||||
public void buildWhenClientRegistrationValuesOverriddenThenPropagated() {
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
|
||||
// @formatter:off
|
||||
ClientRegistration updated = ClientRegistration.withClientRegistration(clientRegistration)
|
||||
.clientSecret("a-new-secret").scope("a-new-scope")
|
||||
.providerConfigurationMetadata(Collections.singletonMap("a-new-config", "a-new-value")).build();
|
||||
.clientSecret("a-new-secret")
|
||||
.scope("a-new-scope")
|
||||
.providerConfigurationMetadata(Collections.singletonMap("a-new-config", "a-new-value"))
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getClientSecret()).isNotEqualTo(updated.getClientSecret());
|
||||
assertThat(updated.getClientSecret()).isEqualTo("a-new-secret");
|
||||
assertThat(clientRegistration.getScopes()).doesNotContain("a-new-scope");
|
||||
|
@ -549,10 +826,16 @@ public class ClientRegistrationTests {
|
|||
@Test
|
||||
public void buildWhenCustomClientAuthenticationMethodProvidedThenSet() {
|
||||
ClientAuthenticationMethod clientAuthenticationMethod = new ClientAuthenticationMethod("tls_client_auth");
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.clientId(CLIENT_ID).authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.clientAuthenticationMethod(clientAuthenticationMethod).redirectUri(REDIRECT_URI)
|
||||
.authorizationUri(AUTHORIZATION_URI).tokenUri(TOKEN_URI).build();
|
||||
.clientId(CLIENT_ID)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.clientAuthenticationMethod(clientAuthenticationMethod)
|
||||
.redirectUri(REDIRECT_URI)
|
||||
.authorizationUri(AUTHORIZATION_URI)
|
||||
.tokenUri(TOKEN_URI)
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThat(clientRegistration.getClientAuthenticationMethod()).isEqualTo(clientAuthenticationMethod);
|
||||
}
|
||||
|
||||
|
|
|
@ -48,27 +48,61 @@ public class ClientRegistrationsTests {
|
|||
/**
|
||||
* Contains all optional parameters that are found in ClientRegistration
|
||||
*/
|
||||
// @formatter:off
|
||||
private static final String DEFAULT_RESPONSE = "{\n"
|
||||
+ " \"authorization_endpoint\": \"https://example.com/o/oauth2/v2/auth\", \n"
|
||||
+ " \"claims_supported\": [\n" + " \"aud\", \n" + " \"email\", \n"
|
||||
+ " \"email_verified\", \n" + " \"exp\", \n" + " \"family_name\", \n"
|
||||
+ " \"given_name\", \n" + " \"iat\", \n" + " \"iss\", \n" + " \"locale\", \n"
|
||||
+ " \"name\", \n" + " \"picture\", \n" + " \"sub\"\n" + " ], \n"
|
||||
+ " \"code_challenge_methods_supported\": [\n" + " \"plain\", \n" + " \"S256\"\n"
|
||||
+ " ], \n" + " \"id_token_signing_alg_values_supported\": [\n" + " \"RS256\"\n" + " ], \n"
|
||||
+ " \"claims_supported\": [\n"
|
||||
+ " \"aud\", \n"
|
||||
+ " \"email\", \n"
|
||||
+ " \"email_verified\", \n"
|
||||
+ " \"exp\", \n"
|
||||
+ " \"family_name\", \n"
|
||||
+ " \"given_name\", \n"
|
||||
+ " \"iat\", \n"
|
||||
+ " \"iss\", \n"
|
||||
+ " \"locale\", \n"
|
||||
+ " \"name\", \n"
|
||||
+ " \"picture\", \n"
|
||||
+ " \"sub\"\n"
|
||||
+ " ], \n"
|
||||
+ " \"code_challenge_methods_supported\": [\n"
|
||||
+ " \"plain\", \n"
|
||||
+ " \"S256\"\n"
|
||||
+ " ], \n"
|
||||
+ " \"id_token_signing_alg_values_supported\": [\n"
|
||||
+ " \"RS256\"\n"
|
||||
+ " ], \n"
|
||||
+ " \"issuer\": \"https://example.com\", \n"
|
||||
+ " \"jwks_uri\": \"https://example.com/oauth2/v3/certs\", \n" + " \"response_types_supported\": [\n"
|
||||
+ " \"code\", \n" + " \"token\", \n" + " \"id_token\", \n"
|
||||
+ " \"code token\", \n" + " \"code id_token\", \n" + " \"token id_token\", \n"
|
||||
+ " \"code token id_token\", \n" + " \"none\"\n" + " ], \n"
|
||||
+ " \"jwks_uri\": \"https://example.com/oauth2/v3/certs\", \n"
|
||||
+ " \"response_types_supported\": [\n"
|
||||
+ " \"code\", \n"
|
||||
+ " \"token\", \n"
|
||||
+ " \"id_token\", \n"
|
||||
+ " \"code token\", \n"
|
||||
+ " \"code id_token\", \n"
|
||||
+ " \"token id_token\", \n"
|
||||
+ " \"code token id_token\", \n"
|
||||
+ " \"none\"\n"
|
||||
+ " ], \n"
|
||||
+ " \"revocation_endpoint\": \"https://example.com/o/oauth2/revoke\", \n"
|
||||
+ " \"scopes_supported\": [\n" + " \"openid\", \n" + " \"email\", \n"
|
||||
+ " \"profile\"\n" + " ], \n" + " \"subject_types_supported\": [\n" + " \"public\"\n"
|
||||
+ " ], \n" + " \"grant_types_supported\" : [\"authorization_code\"], \n"
|
||||
+ " \"scopes_supported\": [\n"
|
||||
+ " \"openid\", \n"
|
||||
+ " \"email\", \n"
|
||||
+ " \"profile\"\n"
|
||||
+ " ], \n"
|
||||
+ " \"subject_types_supported\": [\n"
|
||||
+ " \"public\"\n"
|
||||
+ " ], \n"
|
||||
+ " \"grant_types_supported\" : [\"authorization_code\"], \n"
|
||||
+ " \"token_endpoint\": \"https://example.com/oauth2/v4/token\", \n"
|
||||
+ " \"token_endpoint_auth_methods_supported\": [\n" + " \"client_secret_post\", \n"
|
||||
+ " \"client_secret_basic\", \n" + " \"none\"\n" + " ], \n"
|
||||
+ " \"userinfo_endpoint\": \"https://example.com/oauth2/v3/userinfo\"\n" + "}";
|
||||
+ " \"token_endpoint_auth_methods_supported\": [\n"
|
||||
+ " \"client_secret_post\", \n"
|
||||
+ " \"client_secret_basic\", \n"
|
||||
+ " \"none\"\n"
|
||||
+ " ], \n"
|
||||
+ " \"userinfo_endpoint\": \"https://example.com/oauth2/v3/userinfo\"\n"
|
||||
+ "}";
|
||||
// @formatter:on
|
||||
|
||||
private MockWebServer server;
|
||||
|
||||
|
@ -301,31 +335,43 @@ public class ClientRegistrationsTests {
|
|||
@Test
|
||||
public void issuerWhenTokenEndpointAuthMethodsInvalidThenException() {
|
||||
this.response.put("token_endpoint_auth_methods_supported", Arrays.asList("tls_client_auth"));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> registration(""))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> registration(""))
|
||||
.withMessageContaining("Only ClientAuthenticationMethod.BASIC, ClientAuthenticationMethod.POST and "
|
||||
+ "ClientAuthenticationMethod.NONE are supported. The issuer \"" + this.issuer
|
||||
+ "\" returned a configuration of [tls_client_auth]");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void issuerWhenOAuth2TokenEndpointAuthMethodsInvalidThenException() {
|
||||
this.response.put("token_endpoint_auth_methods_supported", Arrays.asList("tls_client_auth"));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> registrationOAuth2("", null))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> registrationOAuth2("", null))
|
||||
.withMessageContaining("Only ClientAuthenticationMethod.BASIC, ClientAuthenticationMethod.POST and "
|
||||
+ "ClientAuthenticationMethod.NONE are supported. The issuer \"" + this.issuer
|
||||
+ "\" returned a configuration of [tls_client_auth]");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void issuerWhenOAuth2EmptyStringThenMeaningfulErrorMessage() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> ClientRegistrations.fromIssuerLocation(""))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> ClientRegistrations.fromIssuerLocation(""))
|
||||
.withMessageContaining("issuer cannot be empty");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void issuerWhenEmptyStringThenMeaningfulErrorMessage() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> ClientRegistrations.fromOidcIssuerLocation(""))
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> ClientRegistrations.fromOidcIssuerLocation(""))
|
||||
.withMessageContaining("issuer cannot be empty");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -335,9 +381,12 @@ public class ClientRegistrationsTests {
|
|||
MockResponse mockResponse = new MockResponse().setBody(body).setHeader(HttpHeaders.CONTENT_TYPE,
|
||||
MediaType.APPLICATION_JSON_VALUE);
|
||||
this.server.enqueue(mockResponse);
|
||||
assertThatIllegalStateException().isThrownBy(() -> ClientRegistrations.fromOidcIssuerLocation(this.issuer))
|
||||
// @formatter:off
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ClientRegistrations.fromOidcIssuerLocation(this.issuer))
|
||||
.withMessageContaining("The Issuer \"https://example.com\" provided in the configuration metadata did "
|
||||
+ "not match the requested issuer \"" + this.issuer + "\"");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -347,20 +396,28 @@ public class ClientRegistrationsTests {
|
|||
MockResponse mockResponse = new MockResponse().setBody(body).setHeader(HttpHeaders.CONTENT_TYPE,
|
||||
MediaType.APPLICATION_JSON_VALUE);
|
||||
this.server.enqueue(mockResponse);
|
||||
assertThatIllegalStateException().isThrownBy(() -> ClientRegistrations.fromIssuerLocation(this.issuer))
|
||||
// @formatter:off
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ClientRegistrations.fromIssuerLocation(this.issuer))
|
||||
.withMessageContaining("The Issuer \"https://example.com\" provided in the configuration metadata "
|
||||
+ "did not match the requested issuer \"" + this.issuer + "\"");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private ClientRegistration.Builder registration(String path) throws Exception {
|
||||
this.issuer = createIssuerFromServer(path);
|
||||
this.response.put("issuer", this.issuer);
|
||||
String body = this.mapper.writeValueAsString(this.response);
|
||||
MockResponse mockResponse = new MockResponse().setBody(body).setHeader(HttpHeaders.CONTENT_TYPE,
|
||||
// @formatter:off
|
||||
MockResponse mockResponse = new MockResponse()
|
||||
.setBody(body)
|
||||
.setHeader(HttpHeaders.CONTENT_TYPE,
|
||||
MediaType.APPLICATION_JSON_VALUE);
|
||||
this.server.enqueue(mockResponse);
|
||||
return ClientRegistrations.fromOidcIssuerLocation(this.issuer).clientId("client-id")
|
||||
return ClientRegistrations.fromOidcIssuerLocation(this.issuer)
|
||||
.clientId("client-id")
|
||||
.clientSecret("client-secret");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private ClientRegistration.Builder registrationOAuth2(String path, String body) throws Exception {
|
||||
|
@ -380,7 +437,11 @@ public class ClientRegistrationsTests {
|
|||
}
|
||||
};
|
||||
this.server.setDispatcher(dispatcher);
|
||||
return ClientRegistrations.fromIssuerLocation(this.issuer).clientId("client-id").clientSecret("client-secret");
|
||||
// @formatter:off
|
||||
return ClientRegistrations.fromIssuerLocation(this.issuer)
|
||||
.clientId("client-id")
|
||||
.clientSecret("client-secret");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private String createIssuerFromServer(String path) {
|
||||
|
@ -416,8 +477,11 @@ public class ClientRegistrationsTests {
|
|||
}
|
||||
|
||||
private MockResponse buildSuccessMockResponse(String body) {
|
||||
return new MockResponse().setResponseCode(200).setBody(body).setHeader(HttpHeaders.CONTENT_TYPE,
|
||||
MediaType.APPLICATION_JSON_VALUE);
|
||||
// @formatter:off
|
||||
return new MockResponse().setResponseCode(200)
|
||||
.setBody(body)
|
||||
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -75,8 +75,11 @@ public class InMemoryReactiveClientRegistrationRepositoryTests {
|
|||
|
||||
@Test
|
||||
public void findByRegistrationIdWhenValidIdThenFound() {
|
||||
// @formatter:off
|
||||
StepVerifier.create(this.repository.findByRegistrationId(this.registration.getRegistrationId()))
|
||||
.expectNext(this.registration).verifyComplete();
|
||||
.expectNext(this.registration)
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -29,39 +29,61 @@ public final class TestClientRegistrations {
|
|||
}
|
||||
|
||||
public static ClientRegistration.Builder clientRegistration() {
|
||||
// @formatter:off
|
||||
return ClientRegistration.withRegistrationId("registration-id")
|
||||
.redirectUri("{baseUrl}/{action}/oauth2/code/{registrationId}")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).scope("read:user")
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.scope("read:user")
|
||||
.authorizationUri("https://example.com/login/oauth/authorize")
|
||||
.tokenUri("https://example.com/login/oauth/access_token").jwkSetUri("https://example.com/oauth2/jwk")
|
||||
.issuerUri("https://example.com").userInfoUri("https://api.example.com/user")
|
||||
.userNameAttributeName("id").clientName("Client Name").clientId("client-id")
|
||||
.tokenUri("https://example.com/login/oauth/access_token")
|
||||
.jwkSetUri("https://example.com/oauth2/jwk")
|
||||
.issuerUri("https://example.com")
|
||||
.userInfoUri("https://api.example.com/user")
|
||||
.userNameAttributeName("id")
|
||||
.clientName("Client Name")
|
||||
.clientId("client-id")
|
||||
.clientSecret("client-secret");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
public static ClientRegistration.Builder clientRegistration2() {
|
||||
// @formatter:off
|
||||
return ClientRegistration.withRegistrationId("registration-id-2")
|
||||
.redirectUri("{baseUrl}/{action}/oauth2/code/{registrationId}")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).scope("read:user")
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.scope("read:user")
|
||||
.authorizationUri("https://example.com/login/oauth/authorize")
|
||||
.tokenUri("https://example.com/login/oauth/access_token").userInfoUri("https://api.example.com/user")
|
||||
.userNameAttributeName("id").clientName("Client Name").clientId("client-id-2")
|
||||
.tokenUri("https://example.com/login/oauth/access_token")
|
||||
.userInfoUri("https://api.example.com/user")
|
||||
.userNameAttributeName("id")
|
||||
.clientName("Client Name")
|
||||
.clientId("client-id-2")
|
||||
.clientSecret("client-secret");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
public static ClientRegistration.Builder clientCredentials() {
|
||||
return clientRegistration().registrationId("client-credentials").clientId("client-id")
|
||||
// @formatter:off
|
||||
return clientRegistration()
|
||||
.registrationId("client-credentials")
|
||||
.clientId("client-id")
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
public static ClientRegistration.Builder password() {
|
||||
// @formatter:off
|
||||
return ClientRegistration.withRegistrationId("password")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD).scope("read", "write")
|
||||
.tokenUri("https://example.com/login/oauth/access_token").clientName("Client Name")
|
||||
.clientId("client-id").clientSecret("client-secret");
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
|
||||
.scope("read", "write")
|
||||
.tokenUri("https://example.com/login/oauth/access_token")
|
||||
.clientName("Client Name")
|
||||
.clientId("client-id")
|
||||
.clientSecret("client-secret");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -69,7 +69,10 @@ public class CustomUserTypesOAuth2UserServiceTests {
|
|||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
String registrationId = "client-registration-id-1";
|
||||
this.clientRegistrationBuilder = TestClientRegistrations.clientRegistration().registrationId(registrationId);
|
||||
// @formatter:off
|
||||
this.clientRegistrationBuilder = TestClientRegistrations.clientRegistration()
|
||||
.registrationId(registrationId);
|
||||
// @formatter:on
|
||||
this.accessToken = TestOAuth2AccessTokens.noScopes();
|
||||
Map<String, Class<? extends OAuth2User>> customUserTypes = new HashMap<>();
|
||||
customUserTypes.put(registrationId, CustomOAuth2User.class);
|
||||
|
@ -113,16 +116,25 @@ public class CustomUserTypesOAuth2UserServiceTests {
|
|||
|
||||
@Test
|
||||
public void loadUserWhenCustomUserTypeNotFoundThenReturnNull() {
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration()
|
||||
.registrationId("other-client-registration-id-1").build();
|
||||
.registrationId("other-client-registration-id-1")
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2User user = this.userService.loadUser(new OAuth2UserRequest(clientRegistration, this.accessToken));
|
||||
assertThat(user).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadUserWhenUserInfoSuccessResponseThenReturnUser() {
|
||||
String userInfoResponse = "{\n" + " \"id\": \"12345\",\n" + " \"name\": \"first last\",\n"
|
||||
+ " \"login\": \"user1\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"id\": \"12345\",\n"
|
||||
+ " \"name\": \"first last\",\n"
|
||||
+ " \"login\": \"user1\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
|
||||
|
@ -142,9 +154,15 @@ public class CustomUserTypesOAuth2UserServiceTests {
|
|||
this.exception.expect(OAuth2AuthenticationException.class);
|
||||
this.exception.expectMessage(containsString(
|
||||
"[invalid_user_info_response] An error occurred while attempting to retrieve the UserInfo Resource"));
|
||||
String userInfoResponse = "{\n" + " \"id\": \"12345\",\n" + " \"name\": \"first last\",\n"
|
||||
+ " \"login\": \"user1\",\n" + " \"email\": \"user1@example.com\"\n";
|
||||
// "}\n"; // Make the JSON invalid/malformed
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"id\": \"12345\",\n"
|
||||
+ " \"name\": \"first last\",\n"
|
||||
|
||||
+ " \"login\": \"user1\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n";
|
||||
// "}\n"; // Make the JSON invalid/malformed
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri).build();
|
||||
|
@ -173,9 +191,12 @@ public class CustomUserTypesOAuth2UserServiceTests {
|
|||
}
|
||||
|
||||
private ClientRegistration.Builder withRegistrationId(String registrationId) {
|
||||
// @formatter:off
|
||||
return ClientRegistration.withRegistrationId(registrationId)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).clientId("client")
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
||||
.clientId("client")
|
||||
.tokenUri("/token");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private MockResponse jsonResponse(String json) {
|
||||
|
|
|
@ -80,8 +80,11 @@ public class DefaultOAuth2UserServiceTests {
|
|||
public void setup() throws Exception {
|
||||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
this.clientRegistrationBuilder = TestClientRegistrations.clientRegistration().userInfoUri(null)
|
||||
// @formatter:off
|
||||
this.clientRegistrationBuilder = TestClientRegistrations.clientRegistration()
|
||||
.userInfoUri(null)
|
||||
.userNameAttributeName(null);
|
||||
// @formatter:on
|
||||
this.accessToken = TestOAuth2AccessTokens.noScopes();
|
||||
}
|
||||
|
||||
|
@ -120,16 +123,26 @@ public class DefaultOAuth2UserServiceTests {
|
|||
public void loadUserWhenUserNameAttributeNameIsNullThenThrowOAuth2AuthenticationException() {
|
||||
this.exception.expect(OAuth2AuthenticationException.class);
|
||||
this.exception.expectMessage(containsString("missing_user_name_attribute"));
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri("https://provider.com/user")
|
||||
// @formatter:off
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder
|
||||
.userInfoUri("https://provider.com/user")
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.userService.loadUser(new OAuth2UserRequest(clientRegistration, this.accessToken));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadUserWhenUserInfoSuccessResponseThenReturnUser() {
|
||||
String userInfoResponse = "{\n" + " \"user-name\": \"user1\",\n" + " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n" + " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"user-name\": \"user1\",\n"
|
||||
+ " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n"
|
||||
+ " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri)
|
||||
|
@ -155,10 +168,16 @@ public class DefaultOAuth2UserServiceTests {
|
|||
this.exception.expect(OAuth2AuthenticationException.class);
|
||||
this.exception.expectMessage(containsString(
|
||||
"[invalid_user_info_response] An error occurred while attempting to retrieve the UserInfo Resource"));
|
||||
String userInfoResponse = "{\n" + " \"user-name\": \"user1\",\n" + " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n" + " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n" + " \"email\": \"user1@example.com\"\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"user-name\": \"user1\",\n"
|
||||
+ " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n"
|
||||
+ " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n";
|
||||
// "}\n"; // Make the JSON invalid/malformed
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri)
|
||||
|
@ -190,7 +209,11 @@ public class DefaultOAuth2UserServiceTests {
|
|||
this.exception.expectMessage(containsString(
|
||||
"[invalid_user_info_response] An error occurred while attempting to retrieve the UserInfo Resource"));
|
||||
this.exception.expectMessage(containsString("Error Code: invalid_token"));
|
||||
String userInfoErrorResponse = "{\n" + " \"error\": \"invalid_token\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoErrorResponse = "{\n"
|
||||
+ " \"error\": \"invalid_token\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoErrorResponse).setResponseCode(400));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri)
|
||||
|
@ -224,9 +247,16 @@ public class DefaultOAuth2UserServiceTests {
|
|||
// gh-5294
|
||||
@Test
|
||||
public void loadUserWhenUserInfoSuccessResponseThenAcceptHeaderJson() throws Exception {
|
||||
String userInfoResponse = "{\n" + " \"user-name\": \"user1\",\n" + " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n" + " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"user-name\": \"user1\",\n"
|
||||
+ " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n"
|
||||
+ " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri)
|
||||
|
@ -239,9 +269,16 @@ public class DefaultOAuth2UserServiceTests {
|
|||
// gh-5500
|
||||
@Test
|
||||
public void loadUserWhenAuthenticationMethodHeaderSuccessResponseThenHttpMethodGet() throws Exception {
|
||||
String userInfoResponse = "{\n" + " \"user-name\": \"user1\",\n" + " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n" + " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"user-name\": \"user1\",\n"
|
||||
+ " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n"
|
||||
+ " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri)
|
||||
|
@ -257,9 +294,16 @@ public class DefaultOAuth2UserServiceTests {
|
|||
// gh-5500
|
||||
@Test
|
||||
public void loadUserWhenAuthenticationMethodFormSuccessResponseThenHttpMethodPost() throws Exception {
|
||||
String userInfoResponse = "{\n" + " \"user-name\": \"user1\",\n" + " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n" + " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"user-name\": \"user1\",\n"
|
||||
+ " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n"
|
||||
+ " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(userInfoResponse));
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
ClientRegistration clientRegistration = this.clientRegistrationBuilder.userInfoUri(userInfoUri)
|
||||
|
|
|
@ -78,7 +78,10 @@ public class DefaultReactiveOAuth2UserServiceTests {
|
|||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
String userInfoUri = this.server.url("/user").toString();
|
||||
this.clientRegistration = TestClientRegistrations.clientRegistration().userInfoUri(userInfoUri);
|
||||
// @formatter:off
|
||||
this.clientRegistration = TestClientRegistrations.clientRegistration()
|
||||
.userInfoUri(userInfoUri);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -103,16 +106,28 @@ public class DefaultReactiveOAuth2UserServiceTests {
|
|||
@Test
|
||||
public void loadUserWhenUserNameAttributeNameIsNullThenThrowOAuth2AuthenticationException() {
|
||||
this.clientRegistration.userNameAttributeName(null);
|
||||
StepVerifier.create(this.userService.loadUser(oauth2UserRequest())).expectErrorSatisfies((ex) -> assertThat(ex)
|
||||
.isInstanceOf(OAuth2AuthenticationException.class).hasMessageContaining("missing_user_name_attribute"))
|
||||
// @formatter:off
|
||||
StepVerifier.create(this.userService.loadUser(oauth2UserRequest()))
|
||||
.expectErrorSatisfies((ex) -> assertThat(ex)
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.hasMessageContaining("missing_user_name_attribute")
|
||||
)
|
||||
.verify();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadUserWhenUserInfoSuccessResponseThenReturnUser() {
|
||||
String userInfoResponse = "{\n" + " \"id\": \"user1\",\n" + " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n" + " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"id\": \"user1\",\n"
|
||||
+ " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n"
|
||||
+ " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
enqueueApplicationJsonBody(userInfoResponse);
|
||||
OAuth2User user = this.userService.loadUser(oauth2UserRequest()).block();
|
||||
assertThat(user.getName()).isEqualTo("user1");
|
||||
|
@ -134,9 +149,16 @@ public class DefaultReactiveOAuth2UserServiceTests {
|
|||
@Test
|
||||
public void loadUserWhenAuthenticationMethodHeaderSuccessResponseThenHttpMethodGet() throws Exception {
|
||||
this.clientRegistration.userInfoAuthenticationMethod(AuthenticationMethod.HEADER);
|
||||
String userInfoResponse = "{\n" + " \"id\": \"user1\",\n" + " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n" + " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"id\": \"user1\",\n"
|
||||
+ " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n"
|
||||
+ " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
enqueueApplicationJsonBody(userInfoResponse);
|
||||
this.userService.loadUser(oauth2UserRequest()).block();
|
||||
RecordedRequest request = this.server.takeRequest();
|
||||
|
@ -150,9 +172,16 @@ public class DefaultReactiveOAuth2UserServiceTests {
|
|||
@Test
|
||||
public void loadUserWhenAuthenticationMethodFormSuccessResponseThenHttpMethodPost() throws Exception {
|
||||
this.clientRegistration.userInfoAuthenticationMethod(AuthenticationMethod.FORM);
|
||||
String userInfoResponse = "{\n" + " \"id\": \"user1\",\n" + " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n" + " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n" + " \"email\": \"user1@example.com\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"id\": \"user1\",\n"
|
||||
+ " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n"
|
||||
+ " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
enqueueApplicationJsonBody(userInfoResponse);
|
||||
this.userService.loadUser(oauth2UserRequest()).block();
|
||||
RecordedRequest request = this.server.takeRequest();
|
||||
|
@ -164,10 +193,16 @@ public class DefaultReactiveOAuth2UserServiceTests {
|
|||
|
||||
@Test
|
||||
public void loadUserWhenUserInfoSuccessResponseInvalidThenThrowOAuth2AuthenticationException() {
|
||||
String userInfoResponse = "{\n" + " \"id\": \"user1\",\n" + " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n" + " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n" + " \"email\": \"user1@example.com\"\n";
|
||||
// @formatter:off
|
||||
String userInfoResponse = "{\n"
|
||||
+ " \"id\": \"user1\",\n"
|
||||
+ " \"first-name\": \"first\",\n"
|
||||
+ " \"last-name\": \"last\",\n"
|
||||
+ " \"middle-name\": \"middle\",\n"
|
||||
+ " \"address\": \"address\",\n"
|
||||
+ " \"email\": \"user1@example.com\"\n";
|
||||
// "}\n"; // Make the JSON invalid/malformed
|
||||
// @formatter:on
|
||||
enqueueApplicationJsonBody(userInfoResponse);
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class)
|
||||
.isThrownBy(() -> this.userService.loadUser(oauth2UserRequest()).block())
|
||||
|
|
|
@ -48,12 +48,19 @@ public class OAuth2UserRequestTests {
|
|||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.clientRegistration = ClientRegistration.withRegistrationId("registration-1").clientId("client-1")
|
||||
.clientSecret("secret").clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri("https://client.com")
|
||||
// @formatter:off
|
||||
this.clientRegistration = ClientRegistration.withRegistrationId("registration-1")
|
||||
.clientId("client-1")
|
||||
.clientSecret("secret")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri("https://client.com")
|
||||
.scope(new LinkedHashSet<>(Arrays.asList("scope1", "scope2")))
|
||||
.authorizationUri("https://provider.com/oauth2/authorization")
|
||||
.tokenUri("https://provider.com/oauth2/token").clientName("Client 1").build();
|
||||
.tokenUri("https://provider.com/oauth2/token")
|
||||
.clientName("Client 1")
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "access-token-1234", Instant.now(),
|
||||
Instant.now().plusSeconds(60), new LinkedHashSet<>(Arrays.asList("scope1", "scope2")));
|
||||
this.additionalParameters = new HashMap<>();
|
||||
|
|
|
@ -72,11 +72,18 @@ public class DefaultOAuth2AuthorizationRequestResolverTests {
|
|||
this.registration1 = TestClientRegistrations.clientRegistration().build();
|
||||
this.registration2 = TestClientRegistrations.clientRegistration2().build();
|
||||
this.fineRedirectUriTemplateRegistration = fineRedirectUriTemplateClientRegistration().build();
|
||||
// @formatter:off
|
||||
this.pkceRegistration = TestClientRegistrations.clientRegistration()
|
||||
.registrationId("pkce-client-registration-id").clientId("pkce-client-id")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.NONE).clientSecret(null).build();
|
||||
this.oidcRegistration = TestClientRegistrations.clientRegistration().registrationId("oidc-registration-id")
|
||||
.scope(OidcScopes.OPENID).build();
|
||||
.registrationId("pkce-client-registration-id")
|
||||
.clientId("pkce-client-id")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
|
||||
.clientSecret(null)
|
||||
.build();
|
||||
this.oidcRegistration = TestClientRegistrations.clientRegistration()
|
||||
.registrationId("oidc-registration-id")
|
||||
.scope(OidcScopes.OPENID)
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.clientRegistrationRepository = new InMemoryClientRegistrationRepository(this.registration1,
|
||||
this.registration2, this.fineRedirectUriTemplateRegistration, this.pkceRegistration,
|
||||
this.oidcRegistration);
|
||||
|
@ -134,8 +141,11 @@ public class DefaultOAuth2AuthorizationRequestResolverTests {
|
|||
+ "-invalid";
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
|
||||
request.setServletPath(requestUri);
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.resolver.resolve(request)).withMessage(
|
||||
"Invalid Client Registration with Id: " + clientRegistration.getRegistrationId() + "-invalid");
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.resolver.resolve(request))
|
||||
.withMessage("Invalid Client Registration with Id: " + clientRegistration.getRegistrationId() + "-invalid");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -483,14 +493,20 @@ public class DefaultOAuth2AuthorizationRequestResolverTests {
|
|||
}
|
||||
|
||||
private static ClientRegistration.Builder fineRedirectUriTemplateClientRegistration() {
|
||||
// @formatter:off
|
||||
return ClientRegistration.withRegistrationId("fine-redirect-uri-template-client-registration")
|
||||
.redirectUri("{baseScheme}://{baseHost}{basePort}{basePath}/{action}/oauth2/code/{registrationId}")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).scope("read:user")
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.scope("read:user")
|
||||
.authorizationUri("https://example.com/login/oauth/authorize")
|
||||
.tokenUri("https://example.com/login/oauth/access_token").userInfoUri("https://api.example.com/user")
|
||||
.userNameAttributeName("id").clientName("Fine Redirect Uri Template Client")
|
||||
.clientId("fine-redirect-uri-template-client").clientSecret("client-secret");
|
||||
.tokenUri("https://example.com/login/oauth/access_token")
|
||||
.userInfoUri("https://api.example.com/user")
|
||||
.userNameAttributeName("id")
|
||||
.clientName("Fine Redirect Uri Template Client")
|
||||
.clientId("fine-redirect-uri-template-client")
|
||||
.clientSecret("client-secret");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -199,11 +199,16 @@ public class DefaultOAuth2AuthorizedClientManagerTests {
|
|||
|
||||
@Test
|
||||
public void authorizeWhenClientRegistrationNotFoundThenThrowIllegalArgumentException() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId("invalid-registration-id").principal(this.principal).attributes((attrs) -> {
|
||||
.withClientRegistrationId("invalid-registration-id")
|
||||
.principal(this.principal)
|
||||
.attributes((attrs) -> {
|
||||
attrs.put(HttpServletRequest.class.getName(), this.request);
|
||||
attrs.put(HttpServletResponse.class.getName(), this.response);
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.authorizedClientManager.authorize(authorizeRequest))
|
||||
.withMessage("Could not find ClientRegistration with id 'invalid-registration-id'");
|
||||
}
|
||||
|
@ -213,12 +218,16 @@ public class DefaultOAuth2AuthorizedClientManagerTests {
|
|||
public void authorizeWhenNotAuthorizedAndUnsupportedProviderThenNotAuthorized() {
|
||||
given(this.clientRegistrationRepository.findByRegistrationId(eq(this.clientRegistration.getRegistrationId())))
|
||||
.willReturn(this.clientRegistration);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId())
|
||||
.principal(this.principal)
|
||||
.attributes((attrs) -> {
|
||||
attrs.put(HttpServletRequest.class.getName(), this.request);
|
||||
attrs.put(HttpServletResponse.class.getName(), this.response);
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
|
||||
verify(this.authorizedClientProvider).authorize(this.authorizationContextCaptor.capture());
|
||||
verify(this.contextAttributesMapper).apply(eq(authorizeRequest));
|
||||
|
@ -238,12 +247,16 @@ public class DefaultOAuth2AuthorizedClientManagerTests {
|
|||
.willReturn(this.clientRegistration);
|
||||
given(this.authorizedClientProvider.authorize(any(OAuth2AuthorizationContext.class)))
|
||||
.willReturn(this.authorizedClient);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId())
|
||||
.principal(this.principal)
|
||||
.attributes((attrs) -> {
|
||||
attrs.put(HttpServletRequest.class.getName(), this.request);
|
||||
attrs.put(HttpServletResponse.class.getName(), this.response);
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
|
||||
verify(this.authorizedClientProvider).authorize(this.authorizationContextCaptor.capture());
|
||||
verify(this.contextAttributesMapper).apply(eq(authorizeRequest));
|
||||
|
@ -269,12 +282,16 @@ public class DefaultOAuth2AuthorizedClientManagerTests {
|
|||
this.principal.getName(), TestOAuth2AccessTokens.noScopes(), TestOAuth2RefreshTokens.refreshToken());
|
||||
given(this.authorizedClientProvider.authorize(any(OAuth2AuthorizationContext.class)))
|
||||
.willReturn(reauthorizedClient);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId())
|
||||
.principal(this.principal)
|
||||
.attributes((attrs) -> {
|
||||
attrs.put(HttpServletRequest.class.getName(), this.request);
|
||||
attrs.put(HttpServletResponse.class.getName(), this.response);
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
|
||||
verify(this.authorizedClientProvider).authorize(this.authorizationContextCaptor.capture());
|
||||
verify(this.contextAttributesMapper).apply(any());
|
||||
|
@ -309,12 +326,16 @@ public class DefaultOAuth2AuthorizedClientManagerTests {
|
|||
});
|
||||
this.request.addParameter(OAuth2ParameterNames.USERNAME, "username");
|
||||
this.request.addParameter(OAuth2ParameterNames.PASSWORD, "password");
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId()).principal(this.principal)
|
||||
.withClientRegistrationId(this.clientRegistration.getRegistrationId())
|
||||
.principal(this.principal)
|
||||
.attributes((attrs) -> {
|
||||
attrs.put(HttpServletRequest.class.getName(), this.request);
|
||||
attrs.put(HttpServletResponse.class.getName(), this.response);
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.authorizedClientManager.authorize(authorizeRequest);
|
||||
verify(this.authorizedClientProvider).authorize(this.authorizationContextCaptor.capture());
|
||||
OAuth2AuthorizationContext authorizationContext = this.authorizationContextCaptor.getValue();
|
||||
|
@ -327,11 +348,15 @@ public class DefaultOAuth2AuthorizedClientManagerTests {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void reauthorizeWhenUnsupportedProviderThenNotReauthorized() {
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest reauthorizeRequest = OAuth2AuthorizeRequest.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal).attributes((attrs) -> {
|
||||
.principal(this.principal)
|
||||
.attributes((attrs) -> {
|
||||
attrs.put(HttpServletRequest.class.getName(), this.request);
|
||||
attrs.put(HttpServletResponse.class.getName(), this.response);
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(reauthorizeRequest);
|
||||
verify(this.authorizedClientProvider).authorize(this.authorizationContextCaptor.capture());
|
||||
verify(this.contextAttributesMapper).apply(eq(reauthorizeRequest));
|
||||
|
@ -352,11 +377,15 @@ public class DefaultOAuth2AuthorizedClientManagerTests {
|
|||
this.principal.getName(), TestOAuth2AccessTokens.noScopes(), TestOAuth2RefreshTokens.refreshToken());
|
||||
given(this.authorizedClientProvider.authorize(any(OAuth2AuthorizationContext.class)))
|
||||
.willReturn(reauthorizedClient);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest reauthorizeRequest = OAuth2AuthorizeRequest.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal).attributes((attrs) -> {
|
||||
.principal(this.principal)
|
||||
.attributes((attrs) -> {
|
||||
attrs.put(HttpServletRequest.class.getName(), this.request);
|
||||
attrs.put(HttpServletResponse.class.getName(), this.response);
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(reauthorizeRequest);
|
||||
verify(this.authorizedClientProvider).authorize(this.authorizationContextCaptor.capture());
|
||||
verify(this.contextAttributesMapper).apply(eq(reauthorizeRequest));
|
||||
|
@ -381,11 +410,15 @@ public class DefaultOAuth2AuthorizedClientManagerTests {
|
|||
this.authorizedClientManager
|
||||
.setContextAttributesMapper(new DefaultOAuth2AuthorizedClientManager.DefaultContextAttributesMapper());
|
||||
this.request.addParameter(OAuth2ParameterNames.SCOPE, "read write");
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest reauthorizeRequest = OAuth2AuthorizeRequest.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal).attributes((attrs) -> {
|
||||
.principal(this.principal)
|
||||
.attributes((attrs) -> {
|
||||
attrs.put(HttpServletRequest.class.getName(), this.request);
|
||||
attrs.put(HttpServletResponse.class.getName(), this.response);
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.authorizedClientManager.authorize(reauthorizeRequest);
|
||||
verify(this.authorizedClientProvider).authorize(this.authorizationContextCaptor.capture());
|
||||
OAuth2AuthorizationContext authorizationContext = this.authorizationContextCaptor.getValue();
|
||||
|
@ -401,11 +434,15 @@ public class DefaultOAuth2AuthorizedClientManagerTests {
|
|||
this.clientRegistration.getRegistrationId());
|
||||
given(this.authorizedClientProvider.authorize(any(OAuth2AuthorizationContext.class)))
|
||||
.willThrow(authorizationException);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest reauthorizeRequest = OAuth2AuthorizeRequest.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal).attributes((attrs) -> {
|
||||
.principal(this.principal)
|
||||
.attributes((attrs) -> {
|
||||
attrs.put(HttpServletRequest.class.getName(), this.request);
|
||||
attrs.put(HttpServletResponse.class.getName(), this.response);
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThatExceptionOfType(ClientAuthorizationException.class)
|
||||
.isThrownBy(() -> this.authorizedClientManager.authorize(reauthorizeRequest))
|
||||
.isEqualTo(authorizationException);
|
||||
|
@ -421,11 +458,15 @@ public class DefaultOAuth2AuthorizedClientManagerTests {
|
|||
new OAuth2Error("non-matching-error-code", null, null), this.clientRegistration.getRegistrationId());
|
||||
given(this.authorizedClientProvider.authorize(any(OAuth2AuthorizationContext.class)))
|
||||
.willThrow(authorizationException);
|
||||
// @formatter:off
|
||||
OAuth2AuthorizeRequest reauthorizeRequest = OAuth2AuthorizeRequest.withAuthorizedClient(this.authorizedClient)
|
||||
.principal(this.principal).attributes((attrs) -> {
|
||||
.principal(this.principal)
|
||||
.attributes((attrs) -> {
|
||||
attrs.put(HttpServletRequest.class.getName(), this.request);
|
||||
attrs.put(HttpServletResponse.class.getName(), this.response);
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
// @formatter:on
|
||||
assertThatExceptionOfType(ClientAuthorizationException.class)
|
||||
.isThrownBy(() -> this.authorizedClientManager.authorize(reauthorizeRequest))
|
||||
.isEqualTo(authorizationException);
|
||||
|
|
|
@ -77,9 +77,13 @@ public class OAuth2AuthorizationRequestRedirectFilterTests {
|
|||
public void setUp() {
|
||||
this.registration1 = TestClientRegistrations.clientRegistration().build();
|
||||
this.registration2 = TestClientRegistrations.clientRegistration2().build();
|
||||
this.registration3 = TestClientRegistrations.clientRegistration().registrationId("registration-3")
|
||||
// @formatter:off
|
||||
this.registration3 = TestClientRegistrations.clientRegistration()
|
||||
.registrationId("registration-3")
|
||||
.authorizationGrantType(AuthorizationGrantType.IMPLICIT)
|
||||
.redirectUri("{baseUrl}/authorize/oauth2/implicit/{registrationId}").build();
|
||||
.redirectUri("{baseUrl}/authorize/oauth2/implicit/{registrationId}")
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.clientRegistrationRepository = new InMemoryClientRegistrationRepository(this.registration1,
|
||||
this.registration2, this.registration3);
|
||||
this.filter = new OAuth2AuthorizationRequestRedirectFilter(this.clientRegistrationRepository);
|
||||
|
@ -307,13 +311,18 @@ public class OAuth2AuthorizationRequestRedirectFilterTests {
|
|||
OAuth2AuthorizationRequest defaultAuthorizationRequest = defaultAuthorizationRequestResolver.resolve(request);
|
||||
Map<String, Object> additionalParameters = new HashMap<>(defaultAuthorizationRequest.getAdditionalParameters());
|
||||
additionalParameters.put(loginHintParamName, request.getParameter(loginHintParamName));
|
||||
// @formatter:off
|
||||
String customAuthorizationRequestUri = UriComponentsBuilder
|
||||
.fromUriString(defaultAuthorizationRequest.getAuthorizationRequestUri())
|
||||
.queryParam(loginHintParamName, additionalParameters.get(loginHintParamName)).build(true).toUriString();
|
||||
.queryParam(loginHintParamName, additionalParameters.get(loginHintParamName))
|
||||
.build(true)
|
||||
.toUriString();
|
||||
OAuth2AuthorizationRequest result = OAuth2AuthorizationRequest
|
||||
.from(defaultAuthorizationRequestResolver.resolve(request))
|
||||
.additionalParameters(Collections.singletonMap("idp", request.getParameter("idp")))
|
||||
.authorizationRequestUri(customAuthorizationRequestUri).build();
|
||||
.authorizationRequestUri(customAuthorizationRequestUri)
|
||||
.build();
|
||||
// @formatter:on
|
||||
given(resolver.resolve(any())).willReturn(result);
|
||||
OAuth2AuthorizationRequestRedirectFilter filter = new OAuth2AuthorizationRequestRedirectFilter(resolver);
|
||||
filter.doFilter(request, response, filterChain);
|
||||
|
|
|
@ -219,14 +219,21 @@ public class OAuth2LoginAuthenticationFilterTests {
|
|||
request.addParameter(OAuth2ParameterNames.STATE, "state");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
// @formatter:off
|
||||
ClientRegistration registrationNotFound = ClientRegistration.withRegistrationId("registration-not-found")
|
||||
.clientId("client-1").clientSecret("secret")
|
||||
.clientId("client-1")
|
||||
.clientSecret("secret")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri("{baseUrl}/login/oauth2/code/{registrationId}").scope("user")
|
||||
.authorizationUri("https://provider.com/oauth2/authorize").tokenUri("https://provider.com/oauth2/token")
|
||||
.userInfoUri("https://provider.com/oauth2/user").userNameAttributeName("id").clientName("client-1")
|
||||
.redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
|
||||
.scope("user")
|
||||
.authorizationUri("https://provider.com/oauth2/authorize")
|
||||
.tokenUri("https://provider.com/oauth2/token")
|
||||
.userInfoUri("https://provider.com/oauth2/user")
|
||||
.userNameAttributeName("id")
|
||||
.clientName("client-1")
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.setUpAuthorizationRequest(request, response, registrationNotFound, state);
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
ArgumentCaptor<AuthenticationException> authenticationExceptionArgCaptor = ArgumentCaptor
|
||||
|
|
|
@ -110,18 +110,32 @@ public class OAuth2AuthorizedClientArgumentResolverTests {
|
|||
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(this.authentication);
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
this.registration1 = ClientRegistration.withRegistrationId("client1").clientId("client-1")
|
||||
.clientSecret("secret").clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
// @formatter:off
|
||||
this.registration1 = ClientRegistration.withRegistrationId("client1")
|
||||
.clientId("client-1")
|
||||
.clientSecret("secret")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri("{baseUrl}/login/oauth2/code/{registrationId}").scope("user")
|
||||
.authorizationUri("https://provider.com/oauth2/authorize").tokenUri("https://provider.com/oauth2/token")
|
||||
.userInfoUri("https://provider.com/oauth2/user").userNameAttributeName("id").clientName("client-1")
|
||||
.redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
|
||||
.scope("user")
|
||||
.authorizationUri("https://provider.com/oauth2/authorize")
|
||||
.tokenUri("https://provider.com/oauth2/token")
|
||||
.userInfoUri("https://provider.com/oauth2/user")
|
||||
.userNameAttributeName("id")
|
||||
.clientName("client-1")
|
||||
.build();
|
||||
this.registration2 = ClientRegistration.withRegistrationId("client2").clientId("client-2")
|
||||
.clientSecret("secret").clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).scope("read", "write")
|
||||
.tokenUri("https://provider.com/oauth2/token").build();
|
||||
this.registration3 = TestClientRegistrations.password().registrationId("client3").build();
|
||||
this.registration2 = ClientRegistration.withRegistrationId("client2")
|
||||
.clientId("client-2")
|
||||
.clientSecret("secret")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
||||
.scope("read", "write")
|
||||
.tokenUri("https://provider.com/oauth2/token")
|
||||
.build();
|
||||
this.registration3 = TestClientRegistrations.password()
|
||||
.registrationId("client3")
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.clientRegistrationRepository = new InMemoryClientRegistrationRepository(this.registration1,
|
||||
this.registration2, this.registration3);
|
||||
this.authorizedClientRepository = mock(OAuth2AuthorizedClientRepository.class);
|
||||
|
|
|
@ -115,7 +115,11 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
this.serverUrl = this.server.url("/").toString();
|
||||
this.webClient = WebClient.builder().filter(this.authorizedClientFilter).build();
|
||||
// @formatter:off
|
||||
this.webClient = WebClient.builder()
|
||||
.filter(this.authorizedClientFilter)
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.authentication = new TestingAuthenticationToken("principal", "password");
|
||||
this.exchange = MockServerWebExchange.builder(MockServerHttpRequest.get("/").build()).build();
|
||||
}
|
||||
|
@ -127,22 +131,35 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
|
||||
@Test
|
||||
public void requestWhenNotAuthorizedThenAuthorizeAndSendRequest() {
|
||||
String accessTokenResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\"\n" + "}\n";
|
||||
String clientResponse = "{\n" + " \"attribute1\": \"value1\",\n" + " \"attribute2\": \"value2\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\"\n"
|
||||
+ "}\n";
|
||||
String clientResponse = "{\n"
|
||||
+ " \"attribute1\": \"value1\",\n"
|
||||
+ " \"attribute2\": \"value2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenResponse));
|
||||
this.server.enqueue(jsonResponse(clientResponse));
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientCredentials().tokenUri(this.serverUrl)
|
||||
.build();
|
||||
given(this.clientRegistrationRepository.findByRegistrationId(eq(clientRegistration.getRegistrationId())))
|
||||
.willReturn(Mono.just(clientRegistration));
|
||||
this.webClient.get().uri(this.serverUrl)
|
||||
// @formatter:off
|
||||
this.webClient.get()
|
||||
.uri(this.serverUrl)
|
||||
.attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction
|
||||
.clientRegistrationId(clientRegistration.getRegistrationId()))
|
||||
.retrieve().bodyToMono(String.class)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.subscriberContext(Context.of(ServerWebExchange.class, this.exchange))
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(this.authentication)).block();
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(this.authentication))
|
||||
.block();
|
||||
// @formatter:on
|
||||
assertThat(this.server.getRequestCount()).isEqualTo(2);
|
||||
ArgumentCaptor<OAuth2AuthorizedClient> authorizedClientCaptor = ArgumentCaptor
|
||||
.forClass(OAuth2AuthorizedClient.class);
|
||||
|
@ -153,9 +170,17 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
|
||||
@Test
|
||||
public void requestWhenAuthorizedButExpiredThenRefreshAndSendRequest() {
|
||||
String accessTokenResponse = "{\n" + " \"access_token\": \"refreshed-access-token\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
String clientResponse = "{\n" + " \"attribute1\": \"value1\",\n" + " \"attribute2\": \"value2\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenResponse = "{\n"
|
||||
+ " \"access_token\": \"refreshed-access-token\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
String clientResponse = "{\n"
|
||||
+ " \"attribute1\": \"value1\",\n"
|
||||
+ " \"attribute2\": \"value2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenResponse));
|
||||
this.server.enqueue(jsonResponse(clientResponse));
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().tokenUri(this.serverUrl)
|
||||
|
@ -189,10 +214,18 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
|
||||
@Test
|
||||
public void requestMultipleWhenNoneAuthorizedThenAuthorizeAndSendRequest() {
|
||||
String accessTokenResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\"\n" + "}\n";
|
||||
String clientResponse = "{\n" + " \"attribute1\": \"value1\",\n" + " \"attribute2\": \"value2\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\"\n"
|
||||
+ "}\n";
|
||||
String clientResponse = "{\n"
|
||||
+ " \"attribute1\": \"value1\",\n"
|
||||
+ " \"attribute2\": \"value2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
// Client 1
|
||||
this.server.enqueue(jsonResponse(accessTokenResponse));
|
||||
this.server.enqueue(jsonResponse(clientResponse));
|
||||
|
@ -207,16 +240,24 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
.tokenUri(this.serverUrl).build();
|
||||
given(this.clientRegistrationRepository.findByRegistrationId(eq(clientRegistration2.getRegistrationId())))
|
||||
.willReturn(Mono.just(clientRegistration2));
|
||||
this.webClient.get().uri(this.serverUrl)
|
||||
// @formatter:off
|
||||
this.webClient.get()
|
||||
.uri(this.serverUrl)
|
||||
.attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction
|
||||
.clientRegistrationId(clientRegistration1.getRegistrationId()))
|
||||
.retrieve().bodyToMono(String.class)
|
||||
.flatMap((response) -> this.webClient.get().uri(this.serverUrl)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.flatMap((response) -> this.webClient.get()
|
||||
.uri(this.serverUrl)
|
||||
.attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction
|
||||
.clientRegistrationId(clientRegistration2.getRegistrationId()))
|
||||
.retrieve().bodyToMono(String.class))
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
)
|
||||
.subscriberContext(Context.of(ServerWebExchange.class, this.exchange))
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(this.authentication)).block();
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(this.authentication))
|
||||
.block();
|
||||
// @formatter:on
|
||||
assertThat(this.server.getRequestCount()).isEqualTo(4);
|
||||
ArgumentCaptor<OAuth2AuthorizedClient> authorizedClientCaptor = ArgumentCaptor
|
||||
.forClass(OAuth2AuthorizedClient.class);
|
||||
|
@ -232,10 +273,18 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
*/
|
||||
@Test
|
||||
public void requestWhenUnauthorizedThenReAuthorize() {
|
||||
String accessTokenResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\"\n" + "}\n";
|
||||
String clientResponse = "{\n" + " \"attribute1\": \"value1\",\n" + " \"attribute2\": \"value2\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\"\n"
|
||||
+ "}\n";
|
||||
String clientResponse = "{\n"
|
||||
+ " \"attribute1\": \"value1\",\n"
|
||||
+ " \"attribute2\": \"value2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(new MockResponse().setResponseCode(HttpStatus.UNAUTHORIZED.value()));
|
||||
this.server.enqueue(jsonResponse(accessTokenResponse));
|
||||
this.server.enqueue(jsonResponse(clientResponse));
|
||||
|
@ -250,15 +299,22 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
doReturn(Mono.just(authorizedClient)).doReturn(Mono.empty()).when(this.authorizedClientRepository)
|
||||
.loadAuthorizedClient(eq(clientRegistration.getRegistrationId()), eq(this.authentication),
|
||||
eq(this.exchange));
|
||||
Mono<String> requestMono = this.webClient.get().uri(this.serverUrl)
|
||||
// @formatter:off
|
||||
Mono<String> requestMono = this.webClient.get()
|
||||
.uri(this.serverUrl)
|
||||
.attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction
|
||||
.clientRegistrationId(clientRegistration.getRegistrationId()))
|
||||
.retrieve().bodyToMono(String.class)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.subscriberContext(Context.of(ServerWebExchange.class, this.exchange))
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(this.authentication));
|
||||
// @formatter:on
|
||||
// first try should fail, and remove the cached authorized client
|
||||
assertThatExceptionOfType(WebClientResponseException.class).isThrownBy(requestMono::block)
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(WebClientResponseException.class)
|
||||
.isThrownBy(requestMono::block)
|
||||
.satisfies((ex) -> assertThat(ex.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED));
|
||||
// @formatter:on
|
||||
assertThat(this.server.getRequestCount()).isEqualTo(1);
|
||||
verify(this.authorizedClientRepository, never()).saveAuthorizedClient(any(), any(), any());
|
||||
verify(this.authorizedClientRepository).removeAuthorizedClient(eq(clientRegistration.getRegistrationId()),
|
||||
|
@ -274,7 +330,11 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
}
|
||||
|
||||
private MockResponse jsonResponse(String json) {
|
||||
return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody(json);
|
||||
// @formatter:off
|
||||
return new MockResponse()
|
||||
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setBody(json);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -108,6 +108,8 @@ import static org.mockito.Mockito.never;
|
|||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
|
||||
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
|
@ -161,14 +163,17 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
|
||||
@Before
|
||||
public void setup() {
|
||||
// @formatter:off
|
||||
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
|
||||
.builder().authorizationCode()
|
||||
.builder()
|
||||
.authorizationCode()
|
||||
.refreshToken(
|
||||
(configurer) -> configurer.accessTokenResponseClient(this.refreshTokenTokenResponseClient))
|
||||
.clientCredentials(
|
||||
(configurer) -> configurer.accessTokenResponseClient(this.clientCredentialsTokenResponseClient))
|
||||
.password((configurer) -> configurer.accessTokenResponseClient(this.passwordTokenResponseClient))
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.authorizedClientManager = new DefaultReactiveOAuth2AuthorizedClientManager(
|
||||
this.clientRegistrationRepository, this.authorizedClientRepository);
|
||||
this.authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
|
||||
|
@ -220,9 +225,12 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName",
|
||||
this.accessToken);
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
this.function.filter(request, this.exchange).subscriberContext(serverWebExchange()).block();
|
||||
// @formatter:off
|
||||
this.function.filter(request, this.exchange).subscriberContext(serverWebExchange())
|
||||
.block();
|
||||
// @formatter:on
|
||||
assertThat(this.exchange.getRequest().headers().getFirst(HttpHeaders.AUTHORIZATION))
|
||||
.isEqualTo("Bearer " + this.accessToken.getTokenValue());
|
||||
}
|
||||
|
@ -231,10 +239,12 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
public void filterWhenExistingAuthorizationThenSingleAuthorizationHeader() {
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName",
|
||||
this.accessToken);
|
||||
// @formatter:off
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.header(HttpHeaders.AUTHORIZATION, "Existing")
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.function.filter(request, this.exchange).subscriberContext(serverWebExchange()).block();
|
||||
HttpHeaders headers = this.exchange.getRequest().headers();
|
||||
assertThat(headers.get(HttpHeaders.AUTHORIZATION)).containsOnly("Bearer " + this.accessToken.getTokenValue());
|
||||
|
@ -242,8 +252,13 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
|
||||
@Test
|
||||
public void filterWhenClientCredentialsTokenExpiredThenGetNewToken() {
|
||||
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("new-token")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER).expiresIn(360).build();
|
||||
// @formatter:off
|
||||
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse
|
||||
.withToken("new-token")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.expiresIn(360)
|
||||
.build();
|
||||
// @formatter:on
|
||||
given(this.clientCredentialsTokenResponseClient.getTokenResponse(any()))
|
||||
.willReturn(Mono.just(accessTokenResponse));
|
||||
ClientRegistration registration = TestClientRegistrations.clientCredentials().build();
|
||||
|
@ -254,12 +269,15 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(registration, "principalName", accessToken,
|
||||
null);
|
||||
TestingAuthenticationToken authentication = new TestingAuthenticationToken("test", "this");
|
||||
// @formatter:off
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
this.function.filter(request, this.exchange)
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication))
|
||||
.subscriberContext(serverWebExchange()).block();
|
||||
.subscriberContext(serverWebExchange())
|
||||
.block();
|
||||
// @formatter:on
|
||||
verify(this.clientCredentialsTokenResponseClient).getTokenResponse(any());
|
||||
verify(this.authorizedClientRepository).saveAuthorizedClient(any(), eq(authentication), any());
|
||||
List<ClientRequest> requests = this.exchange.getRequests();
|
||||
|
@ -277,12 +295,15 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
ClientRegistration registration = TestClientRegistrations.clientCredentials().build();
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(registration, "principalName",
|
||||
this.accessToken, null);
|
||||
// @formatter:off
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
this.function.filter(request, this.exchange)
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication))
|
||||
.subscriberContext(serverWebExchange()).block();
|
||||
.subscriberContext(serverWebExchange())
|
||||
.block();
|
||||
// @formatter:on
|
||||
verify(this.clientCredentialsTokenResponseClient, never()).getTokenResponse(any());
|
||||
List<ClientRequest> requests = this.exchange.getRequests();
|
||||
assertThat(requests).hasSize(1);
|
||||
|
@ -305,13 +326,18 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
OAuth2RefreshToken refreshToken = new OAuth2RefreshToken("refresh-token", issuedAt);
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName",
|
||||
this.accessToken, refreshToken);
|
||||
// @formatter:off
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
// @formatter:on
|
||||
TestingAuthenticationToken authentication = new TestingAuthenticationToken("test", "this");
|
||||
// @formatter:off
|
||||
this.function.filter(request, this.exchange)
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication))
|
||||
.subscriberContext(serverWebExchange()).block();
|
||||
.subscriberContext(serverWebExchange())
|
||||
.block();
|
||||
// @formatter:on
|
||||
verify(this.refreshTokenTokenResponseClient).getTokenResponse(any());
|
||||
verify(this.authorizedClientRepository).saveAuthorizedClient(this.authorizedClientCaptor.capture(),
|
||||
eq(authentication), any());
|
||||
|
@ -339,10 +365,14 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
OAuth2RefreshToken refreshToken = new OAuth2RefreshToken("refresh-token", issuedAt);
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName",
|
||||
this.accessToken, refreshToken);
|
||||
// @formatter:off
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
this.function.filter(request, this.exchange).subscriberContext(serverWebExchange()).block();
|
||||
this.function.filter(request, this.exchange)
|
||||
.subscriberContext(serverWebExchange())
|
||||
.block();
|
||||
// @formatter:on
|
||||
verify(this.refreshTokenTokenResponseClient).getTokenResponse(any());
|
||||
verify(this.authorizedClientRepository).saveAuthorizedClient(any(), any(), any());
|
||||
List<ClientRequest> requests = this.exchange.getRequests();
|
||||
|
@ -358,10 +388,14 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
public void filterWhenRefreshTokenNullThenShouldRefreshFalse() {
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName",
|
||||
this.accessToken);
|
||||
// @formatter:off
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
this.function.filter(request, this.exchange).subscriberContext(serverWebExchange()).block();
|
||||
this.function.filter(request, this.exchange)
|
||||
.subscriberContext(serverWebExchange())
|
||||
.block();
|
||||
// @formatter:on
|
||||
List<ClientRequest> requests = this.exchange.getRequests();
|
||||
assertThat(requests).hasSize(1);
|
||||
ClientRequest request0 = requests.get(0);
|
||||
|
@ -376,10 +410,14 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
OAuth2RefreshToken refreshToken = new OAuth2RefreshToken("refresh-token", this.accessToken.getIssuedAt());
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName",
|
||||
this.accessToken, refreshToken);
|
||||
// @formatter:off
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
this.function.filter(request, this.exchange).subscriberContext(serverWebExchange()).block();
|
||||
this.function.filter(request, this.exchange)
|
||||
.subscriberContext(serverWebExchange())
|
||||
.block();
|
||||
// @formatter:on
|
||||
List<ClientRequest> requests = this.exchange.getRequests();
|
||||
assertThat(requests).hasSize(1);
|
||||
ClientRequest request0 = requests.get(0);
|
||||
|
@ -398,9 +436,11 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
OAuth2RefreshToken refreshToken = new OAuth2RefreshToken("refresh-token", this.accessToken.getIssuedAt());
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName",
|
||||
this.accessToken, refreshToken);
|
||||
// @formatter:off
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
// @formatter:on
|
||||
given(this.exchange.getResponse().rawStatusCode()).willReturn(HttpStatus.UNAUTHORIZED.value());
|
||||
this.function.filter(request, this.exchange).subscriberContext(serverWebExchange()).block();
|
||||
assertThat(publisherProbe.wasSubscribed()).isTrue();
|
||||
|
@ -427,18 +467,27 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
OAuth2RefreshToken refreshToken = new OAuth2RefreshToken("refresh-token", this.accessToken.getIssuedAt());
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName",
|
||||
this.accessToken, refreshToken);
|
||||
// @formatter:off
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
// @formatter:on
|
||||
WebClientResponseException exception = WebClientResponseException.create(HttpStatus.UNAUTHORIZED.value(),
|
||||
HttpStatus.UNAUTHORIZED.getReasonPhrase(), HttpHeaders.EMPTY, new byte[0], StandardCharsets.UTF_8);
|
||||
ExchangeFunction throwingExchangeFunction = (r) -> Mono.error(exception);
|
||||
assertThatExceptionOfType(WebClientResponseException.class).isThrownBy(() -> this.function
|
||||
.filter(request, throwingExchangeFunction).subscriberContext(serverWebExchange()).block())
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(WebClientResponseException.class)
|
||||
.isThrownBy(() -> this.function
|
||||
.filter(request, throwingExchangeFunction)
|
||||
.subscriberContext(serverWebExchange())
|
||||
.block()
|
||||
)
|
||||
.isEqualTo(exception);
|
||||
// @formatter:on
|
||||
assertThat(publisherProbe.wasSubscribed()).isTrue();
|
||||
verify(this.authorizationFailureHandler).onAuthorizationFailure(this.authorizationExceptionCaptor.capture(),
|
||||
this.authenticationCaptor.capture(), this.attributesCaptor.capture());
|
||||
// @formatter:off
|
||||
assertThat(this.authorizationExceptionCaptor.getValue())
|
||||
.isInstanceOfSatisfying(ClientAuthorizationException.class, (ex) -> {
|
||||
assertThat(ex.getClientRegistrationId()).isEqualTo(this.registration.getRegistrationId());
|
||||
|
@ -446,6 +495,7 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
assertThat(ex).hasCause(exception);
|
||||
assertThat(ex).hasMessageContaining("[invalid_token]");
|
||||
});
|
||||
// @formatter:on
|
||||
assertThat(this.authenticationCaptor.getValue()).isInstanceOf(AnonymousAuthenticationToken.class);
|
||||
assertThat(this.attributesCaptor.getValue())
|
||||
.containsExactly(entry(ServerWebExchange.class.getName(), this.serverWebExchange));
|
||||
|
@ -460,9 +510,11 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
OAuth2RefreshToken refreshToken = new OAuth2RefreshToken("refresh-token", this.accessToken.getIssuedAt());
|
||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName",
|
||||
this.accessToken, refreshToken);
|
||||
// @formatter:off
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
// @formatter:on
|
||||
given(this.exchange.getResponse().rawStatusCode()).willReturn(HttpStatus.FORBIDDEN.value());
|
||||
this.function.filter(request, this.exchange).subscriberContext(serverWebExchange()).block();
|
||||
assertThat(publisherProbe.wasSubscribed()).isTrue();
|
||||
|
@ -490,14 +542,20 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName",
|
||||
this.accessToken, refreshToken);
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
WebClientResponseException exception = WebClientResponseException.create(HttpStatus.FORBIDDEN.value(),
|
||||
HttpStatus.FORBIDDEN.getReasonPhrase(), HttpHeaders.EMPTY, new byte[0], StandardCharsets.UTF_8);
|
||||
ExchangeFunction throwingExchangeFunction = (r) -> Mono.error(exception);
|
||||
assertThatExceptionOfType(WebClientResponseException.class).isThrownBy(() -> this.function
|
||||
.filter(request, throwingExchangeFunction).subscriberContext(serverWebExchange()).block())
|
||||
// @formatter:off
|
||||
assertThatExceptionOfType(WebClientResponseException.class)
|
||||
.isThrownBy(() -> this.function
|
||||
.filter(request, throwingExchangeFunction)
|
||||
.subscriberContext(serverWebExchange())
|
||||
.block()
|
||||
)
|
||||
.isEqualTo(exception);
|
||||
// @formatter:on
|
||||
assertThat(publisherProbe.wasSubscribed()).isTrue();
|
||||
verify(this.authorizationFailureHandler).onAuthorizationFailure(this.authorizationExceptionCaptor.capture(),
|
||||
this.authenticationCaptor.capture(), this.attributesCaptor.capture());
|
||||
|
@ -523,7 +581,7 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName",
|
||||
this.accessToken, refreshToken);
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
String wwwAuthenticateHeader = "Bearer error=\"insufficient_scope\", "
|
||||
+ "error_description=\"The request requires higher privileges than provided by the access token.\", "
|
||||
|
@ -561,7 +619,7 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName",
|
||||
this.accessToken, refreshToken);
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
OAuth2AuthorizationException exception = new OAuth2AuthorizationException(
|
||||
new OAuth2Error(OAuth2ErrorCodes.INVALID_TOKEN, null, null));
|
||||
|
@ -585,7 +643,7 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName",
|
||||
this.accessToken, refreshToken);
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(authorizedClient))
|
||||
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||
.build();
|
||||
given(this.exchange.getResponse().rawStatusCode()).willReturn(HttpStatus.BAD_REQUEST.value());
|
||||
this.function.filter(request, this.exchange).subscriberContext(serverWebExchange()).block();
|
||||
|
@ -621,8 +679,7 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
.contentType(MediaType.APPLICATION_FORM_URLENCODED).body("username=username&password=password"))
|
||||
.build();
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction
|
||||
.clientRegistrationId(registration.getRegistrationId()))
|
||||
.attributes(clientRegistrationId(registration.getRegistrationId()))
|
||||
.build();
|
||||
this.function.filter(request, this.exchange)
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication))
|
||||
|
@ -646,8 +703,7 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
given(this.authorizedClientRepository.loadAuthorizedClient(any(), any(), any()))
|
||||
.willReturn(Mono.just(authorizedClient));
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction
|
||||
.clientRegistrationId(this.registration.getRegistrationId()))
|
||||
.attributes(clientRegistrationId(this.registration.getRegistrationId()))
|
||||
.build();
|
||||
this.function.filter(request, this.exchange).subscriberContext(serverWebExchange()).block();
|
||||
List<ClientRequest> requests = this.exchange.getRequests();
|
||||
|
@ -710,8 +766,11 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
Collections.singletonMap("user", "rob"), "user");
|
||||
OAuth2AuthenticationToken authentication = new OAuth2AuthenticationToken(user, user.getAuthorities(),
|
||||
"client-id");
|
||||
// @formatter:off
|
||||
this.function.filter(request, this.exchange)
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication)).block();
|
||||
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication))
|
||||
.block();
|
||||
// @formatter:on
|
||||
List<ClientRequest> requests = this.exchange.getRequests();
|
||||
assertThat(requests).hasSize(1);
|
||||
verifyZeroInteractions(this.clientRegistrationRepository, this.authorizedClientRepository);
|
||||
|
@ -724,11 +783,14 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
this.accessToken, refreshToken);
|
||||
given(this.authorizedClientRepository.loadAuthorizedClient(any(), any(), any()))
|
||||
.willReturn(Mono.just(authorizedClient));
|
||||
// @formatter:off
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction
|
||||
.clientRegistrationId(this.registration.getRegistrationId()))
|
||||
.attributes(clientRegistrationId(this.registration.getRegistrationId()))
|
||||
.build();
|
||||
this.function.filter(request, this.exchange).subscriberContext(serverWebExchange()).block();
|
||||
this.function.filter(request, this.exchange)
|
||||
.subscriberContext(serverWebExchange())
|
||||
.block();
|
||||
// @formatter:on
|
||||
verify(this.authorizedClientRepository).loadAuthorizedClient(eq(this.registration.getRegistrationId()), any(),
|
||||
eq(this.serverWebExchange));
|
||||
}
|
||||
|
@ -750,10 +812,11 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
|
|||
ClientRegistration registration = TestClientRegistrations.clientCredentials().build();
|
||||
given(this.clientRegistrationRepository.findByRegistrationId(eq(registration.getRegistrationId())))
|
||||
.willReturn(Mono.just(registration));
|
||||
// @formatter:off
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com"))
|
||||
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction
|
||||
.clientRegistrationId(registration.getRegistrationId()))
|
||||
.attributes(clientRegistrationId(registration.getRegistrationId()))
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.function.filter(request, this.exchange).block();
|
||||
verify(unauthenticatedAuthorizedClientRepository).loadAuthorizedClient(any(), any(), any());
|
||||
verify(this.clientCredentialsTokenResponseClient).getTokenResponse(any());
|
||||
|
|
|
@ -65,6 +65,7 @@ import static org.mockito.Mockito.mock;
|
|||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
|
||||
|
||||
/**
|
||||
* @author Joe Grandja
|
||||
|
@ -99,7 +100,11 @@ public class ServletOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
// BlockHound to error.
|
||||
// NOTE: This is an issue with JDK 8. It's been tested on JDK 10 and works fine
|
||||
// w/o this white-list.
|
||||
BlockHound.builder().allowBlockingCallsInside(Class.class.getName(), "getPackage").install();
|
||||
// @formatter:off
|
||||
BlockHound.builder()
|
||||
.allowBlockingCallsInside(Class.class.getName(), "getPackage")
|
||||
.install();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Before
|
||||
|
@ -148,10 +153,18 @@ public class ServletOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
|
||||
@Test
|
||||
public void requestWhenNotAuthorizedThenAuthorizeAndSendRequest() {
|
||||
String accessTokenResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\"\n" + "}\n";
|
||||
String clientResponse = "{\n" + " \"attribute1\": \"value1\",\n" + " \"attribute2\": \"value2\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\"\n"
|
||||
+ "}\n";
|
||||
String clientResponse = "{\n"
|
||||
+ " \"attribute1\": \"value1\",\n"
|
||||
+ " \"attribute2\": \"value2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenResponse));
|
||||
this.server.enqueue(jsonResponse(clientResponse));
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientCredentials().tokenUri(this.serverUrl)
|
||||
|
@ -159,8 +172,7 @@ public class ServletOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
given(this.clientRegistrationRepository.findByRegistrationId(eq(clientRegistration.getRegistrationId())))
|
||||
.willReturn(clientRegistration);
|
||||
this.webClient.get().uri(this.serverUrl)
|
||||
.attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction
|
||||
.clientRegistrationId(clientRegistration.getRegistrationId()))
|
||||
.attributes(clientRegistrationId(clientRegistration.getRegistrationId()))
|
||||
.retrieve().bodyToMono(String.class).block();
|
||||
assertThat(this.server.getRequestCount()).isEqualTo(2);
|
||||
ArgumentCaptor<OAuth2AuthorizedClient> authorizedClientCaptor = ArgumentCaptor
|
||||
|
@ -172,9 +184,17 @@ public class ServletOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
|
||||
@Test
|
||||
public void requestWhenAuthorizedButExpiredThenRefreshAndSendRequest() {
|
||||
String accessTokenResponse = "{\n" + " \"access_token\": \"refreshed-access-token\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\"\n" + "}\n";
|
||||
String clientResponse = "{\n" + " \"attribute1\": \"value1\",\n" + " \"attribute2\": \"value2\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenResponse = "{\n"
|
||||
+ " \"access_token\": \"refreshed-access-token\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\"\n"
|
||||
+ "}\n";
|
||||
String clientResponse = "{\n"
|
||||
+ " \"attribute1\": \"value1\",\n"
|
||||
+ " \"attribute2\": \"value2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
this.server.enqueue(jsonResponse(accessTokenResponse));
|
||||
this.server.enqueue(jsonResponse(clientResponse));
|
||||
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().tokenUri(this.serverUrl)
|
||||
|
@ -191,8 +211,7 @@ public class ServletOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
doReturn(authorizedClient).when(this.authorizedClientRepository).loadAuthorizedClient(
|
||||
eq(clientRegistration.getRegistrationId()), eq(this.authentication), eq(this.request));
|
||||
this.webClient.get().uri(this.serverUrl)
|
||||
.attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction
|
||||
.clientRegistrationId(clientRegistration.getRegistrationId()))
|
||||
.attributes(clientRegistrationId(clientRegistration.getRegistrationId()))
|
||||
.retrieve().bodyToMono(String.class).block();
|
||||
assertThat(this.server.getRequestCount()).isEqualTo(2);
|
||||
ArgumentCaptor<OAuth2AuthorizedClient> authorizedClientCaptor = ArgumentCaptor
|
||||
|
@ -206,10 +225,18 @@ public class ServletOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
|
||||
@Test
|
||||
public void requestMultipleWhenNoneAuthorizedThenAuthorizeAndSendRequest() {
|
||||
String accessTokenResponse = "{\n" + " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\"\n" + "}\n";
|
||||
String clientResponse = "{\n" + " \"attribute1\": \"value1\",\n" + " \"attribute2\": \"value2\"\n" + "}\n";
|
||||
// @formatter:off
|
||||
String accessTokenResponse = "{\n"
|
||||
+ " \"access_token\": \"access-token-1234\",\n"
|
||||
+ " \"token_type\": \"bearer\",\n"
|
||||
+ " \"expires_in\": \"3600\",\n"
|
||||
+ " \"scope\": \"read write\"\n"
|
||||
+ "}\n";
|
||||
String clientResponse = "{\n"
|
||||
+ " \"attribute1\": \"value1\",\n"
|
||||
+ " \"attribute2\": \"value2\"\n"
|
||||
+ "}\n";
|
||||
// @formatter:on
|
||||
// Client 1
|
||||
this.server.enqueue(jsonResponse(accessTokenResponse));
|
||||
this.server.enqueue(jsonResponse(clientResponse));
|
||||
|
@ -224,15 +251,22 @@ public class ServletOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
.tokenUri(this.serverUrl).build();
|
||||
given(this.clientRegistrationRepository.findByRegistrationId(eq(clientRegistration2.getRegistrationId())))
|
||||
.willReturn(clientRegistration2);
|
||||
this.webClient.get().uri(this.serverUrl)
|
||||
.attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction
|
||||
.clientRegistrationId(clientRegistration1.getRegistrationId()))
|
||||
.retrieve().bodyToMono(String.class)
|
||||
.flatMap((response) -> this.webClient.get().uri(this.serverUrl)
|
||||
.attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction
|
||||
.clientRegistrationId(clientRegistration2.getRegistrationId()))
|
||||
.retrieve().bodyToMono(String.class))
|
||||
.subscriberContext(context()).block();
|
||||
// @formatter:off
|
||||
this.webClient.get()
|
||||
.uri(this.serverUrl)
|
||||
.attributes(clientRegistrationId(clientRegistration1.getRegistrationId()))
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.flatMap((response) -> this.webClient
|
||||
.get()
|
||||
.uri(this.serverUrl)
|
||||
.attributes(clientRegistrationId(clientRegistration2.getRegistrationId()))
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
)
|
||||
.subscriberContext(context())
|
||||
.block();
|
||||
// @formatter:on
|
||||
assertThat(this.server.getRequestCount()).isEqualTo(4);
|
||||
ArgumentCaptor<OAuth2AuthorizedClient> authorizedClientCaptor = ArgumentCaptor
|
||||
.forClass(OAuth2AuthorizedClient.class);
|
||||
|
@ -252,7 +286,11 @@ public class ServletOAuth2AuthorizedClientExchangeFilterFunctionITests {
|
|||
}
|
||||
|
||||
private MockResponse jsonResponse(String json) {
|
||||
return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody(json);
|
||||
// @formatter:off
|
||||
return new MockResponse()
|
||||
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setBody(json);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -80,8 +80,14 @@ public class OAuth2AuthorizedClientArgumentResolverTests {
|
|||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// @formatter:off
|
||||
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
|
||||
.builder().authorizationCode().refreshToken().clientCredentials().build();
|
||||
.builder()
|
||||
.authorizationCode()
|
||||
.refreshToken()
|
||||
.clientCredentials()
|
||||
.build();
|
||||
// @formatter:on
|
||||
DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager = new DefaultReactiveOAuth2AuthorizedClientManager(
|
||||
this.clientRegistrationRepository, this.authorizedClientRepository);
|
||||
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
|
||||
|
|
|
@ -93,8 +93,12 @@ public class DefaultServerOAuth2AuthorizationRequestResolverTests {
|
|||
@Test
|
||||
public void resolveWhenForwardedHeadersClientRegistrationFoundThenWorks() {
|
||||
given(this.clientRegistrationRepository.findByRegistrationId(any())).willReturn(Mono.just(this.registration));
|
||||
ServerWebExchange exchange = MockServerWebExchange
|
||||
.from(MockServerHttpRequest.get("/oauth2/authorization/id").header("X-Forwarded-Host", "evil.com"));
|
||||
// @formatter:off
|
||||
MockServerHttpRequest.BaseBuilder<?> httpRequest = MockServerHttpRequest
|
||||
.get("/oauth2/authorization/id")
|
||||
.header("X-Forwarded-Host", "evil.com");
|
||||
// @formatter:on
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(httpRequest);
|
||||
OAuth2AuthorizationRequest request = this.resolver.resolve(exchange).block();
|
||||
assertThat(request.getAuthorizationRequestUri())
|
||||
.matches("https://example.com/login/oauth/authorize\\?" + "response_type=code&client_id=client-id&"
|
||||
|
|
|
@ -301,8 +301,12 @@ public class OAuth2AuthorizationCodeGrantWebFilterTests {
|
|||
MockServerHttpRequest authorizationRequest, ClientRegistration registration) {
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put(OAuth2ParameterNames.REGISTRATION_ID, registration.getRegistrationId());
|
||||
return TestOAuth2AuthorizationRequests.request().attributes(attributes)
|
||||
.redirectUri(authorizationRequest.getURI().toString()).build();
|
||||
// @formatter:off
|
||||
return TestOAuth2AuthorizationRequests.request()
|
||||
.attributes(attributes)
|
||||
.redirectUri(authorizationRequest.getURI().toString())
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private static MockServerHttpRequest createAuthorizationRequest(String requestUri) {
|
||||
|
|
|
@ -41,7 +41,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
|||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
|
@ -86,15 +86,23 @@ public class OAuth2AuthorizationRequestRedirectWebFilterTests {
|
|||
|
||||
@Test
|
||||
public void filterWhenDoesNotMatchThenClientRegistrationRepositoryNotSubscribed() {
|
||||
this.client.get().exchange().expectStatus().isOk();
|
||||
verifyZeroInteractions(this.clientRepository, this.authzRequestRepository);
|
||||
// @formatter:off
|
||||
this.client.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
// @formatter:on
|
||||
verifyNoInteractions(this.clientRepository, this.authzRequestRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterWhenDoesMatchThenClientRegistrationRepositoryNotSubscribed() {
|
||||
// @formatter:off
|
||||
FluxExchangeResult<String> result = this.client.get()
|
||||
.uri("https://example.com/oauth2/authorization/registration-id").exchange().expectStatus()
|
||||
.is3xxRedirection().returnResult(String.class);
|
||||
.uri("https://example.com/oauth2/authorization/registration-id")
|
||||
.exchange()
|
||||
.expectStatus().is3xxRedirection()
|
||||
.returnResult(String.class);
|
||||
// @formatter:on
|
||||
result.assertWithDiagnostics(() -> {
|
||||
URI location = result.getResponseHeaders().getLocation();
|
||||
assertThat(location).hasScheme("https").hasHost("example.com").hasPath("/login/oauth/authorize")
|
||||
|
@ -108,16 +116,23 @@ public class OAuth2AuthorizationRequestRedirectWebFilterTests {
|
|||
// gh-5520
|
||||
@Test
|
||||
public void filterWhenDoesMatchThenResolveRedirectUriExpandedExcludesQueryString() {
|
||||
// @formatter:off
|
||||
FluxExchangeResult<String> result = this.client.get()
|
||||
.uri("https://example.com/oauth2/authorization/registration-id?foo=bar").exchange().expectStatus()
|
||||
.is3xxRedirection().returnResult(String.class);
|
||||
result.assertWithDiagnostics(() -> {
|
||||
URI location = result.getResponseHeaders().getLocation();
|
||||
assertThat(location).hasScheme("https").hasHost("example.com").hasPath("/login/oauth/authorize")
|
||||
.hasParameter("response_type", "code").hasParameter("client_id", "client-id")
|
||||
.hasParameter("scope", "read:user").hasParameter("state")
|
||||
assertThat(location)
|
||||
.hasScheme("https")
|
||||
.hasHost("example.com")
|
||||
.hasPath("/login/oauth/authorize")
|
||||
.hasParameter("response_type", "code")
|
||||
.hasParameter("client_id", "client-id")
|
||||
.hasParameter("scope", "read:user")
|
||||
.hasParameter("state")
|
||||
.hasParameter("redirect_uri", "https://example.com/login/oauth2/code/registration-id");
|
||||
});
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -125,9 +140,15 @@ public class OAuth2AuthorizationRequestRedirectWebFilterTests {
|
|||
FilteringWebHandler webHandler = new FilteringWebHandler(
|
||||
(e) -> Mono.error(new ClientAuthorizationRequiredException(this.registration.getRegistrationId())),
|
||||
Arrays.asList(this.filter));
|
||||
this.client = WebTestClient.bindToWebHandler(webHandler).build();
|
||||
FluxExchangeResult<String> result = this.client.get().uri("https://example.com/foo").exchange().expectStatus()
|
||||
.is3xxRedirection().returnResult(String.class);
|
||||
// @formatter:off
|
||||
this.client = WebTestClient.bindToWebHandler(webHandler)
|
||||
.build();
|
||||
FluxExchangeResult<String> result = this.client.get()
|
||||
.uri("https://example.com/foo")
|
||||
.exchange()
|
||||
.expectStatus().is3xxRedirection()
|
||||
.returnResult(String.class);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -137,18 +158,29 @@ public class OAuth2AuthorizationRequestRedirectWebFilterTests {
|
|||
FilteringWebHandler webHandler = new FilteringWebHandler(
|
||||
(e) -> Mono.error(new ClientAuthorizationRequiredException(this.registration.getRegistrationId())),
|
||||
Arrays.asList(this.filter));
|
||||
this.client = WebTestClient.bindToWebHandler(webHandler).build();
|
||||
this.client.get().uri("https://example.com/foo").exchange().expectStatus().is3xxRedirection()
|
||||
// @formatter:off
|
||||
this.client = WebTestClient.bindToWebHandler(webHandler)
|
||||
.build();
|
||||
this.client.get()
|
||||
.uri("https://example.com/foo")
|
||||
.exchange()
|
||||
.expectStatus().is3xxRedirection()
|
||||
.returnResult(String.class);
|
||||
// @formatter:on
|
||||
verify(this.requestCache).saveRequest(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterWhenPathMatchesThenRequestSessionAttributeNotSaved() {
|
||||
this.filter.setRequestCache(this.requestCache);
|
||||
this.client.get().uri("https://example.com/oauth2/authorization/registration-id").exchange().expectStatus()
|
||||
.is3xxRedirection().returnResult(String.class);
|
||||
verifyZeroInteractions(this.requestCache);
|
||||
// @formatter:off
|
||||
this.client.get()
|
||||
.uri("https://example.com/oauth2/authorization/registration-id")
|
||||
.exchange()
|
||||
.expectStatus().is3xxRedirection()
|
||||
.returnResult(String.class);
|
||||
// @formatter:on
|
||||
verifyNoInteractions(this.requestCache);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -58,18 +58,30 @@ public class ServerOAuth2AuthorizationCodeAuthenticationTokenConverterTests {
|
|||
|
||||
private String clientRegistrationId = "github";
|
||||
|
||||
// @formatter:off
|
||||
private ClientRegistration clientRegistration = ClientRegistration.withRegistrationId(this.clientRegistrationId)
|
||||
.redirectUri("{baseUrl}/{action}/oauth2/code/{registrationId}")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).scope("read:user")
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.scope("read:user")
|
||||
.authorizationUri("https://github.com/login/oauth/authorize")
|
||||
.tokenUri("https://github.com/login/oauth/access_token").userInfoUri("https://api.github.com/user")
|
||||
.userNameAttributeName("id").clientName("GitHub").clientId("clientId").clientSecret("clientSecret").build();
|
||||
.tokenUri("https://github.com/login/oauth/access_token")
|
||||
.userInfoUri("https://api.github.com/user")
|
||||
.userNameAttributeName("id")
|
||||
.clientName("GitHub")
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.build();
|
||||
// @formatter:on
|
||||
|
||||
// @formatter:off
|
||||
private OAuth2AuthorizationRequest.Builder authorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
|
||||
.authorizationUri("https://example.com/oauth2/authorize").clientId("client-id")
|
||||
.redirectUri("http://localhost/client-1").state("state")
|
||||
.authorizationUri("https://example.com/oauth2/authorize")
|
||||
.clientId("client-id")
|
||||
.redirectUri("http://localhost/client-1")
|
||||
.state("state")
|
||||
.attributes(Collections.singletonMap(OAuth2ParameterNames.REGISTRATION_ID, this.clientRegistrationId));
|
||||
// @formatter:on
|
||||
|
||||
private final MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/");
|
||||
|
||||
|
|
|
@ -51,9 +51,14 @@ public class WebSessionOAuth2ServerAuthorizationRequestRepositoryTests {
|
|||
|
||||
private WebSessionOAuth2ServerAuthorizationRequestRepository repository = new WebSessionOAuth2ServerAuthorizationRequestRepository();
|
||||
|
||||
// @formatter:off
|
||||
private OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
|
||||
.authorizationUri("https://example.com/oauth2/authorize").clientId("client-id")
|
||||
.redirectUri("http://localhost/client-1").state("state").build();
|
||||
.authorizationUri("https://example.com/oauth2/authorize")
|
||||
.clientId("client-id")
|
||||
.redirectUri("http://localhost/client-1")
|
||||
.state("state")
|
||||
.build();
|
||||
// @formatter:on
|
||||
|
||||
private ServerWebExchange exchange = MockServerWebExchange
|
||||
.from(MockServerHttpRequest.get("/").queryParam(OAuth2ParameterNames.STATE, "state"));
|
||||
|
@ -66,55 +71,80 @@ public class WebSessionOAuth2ServerAuthorizationRequestRepositoryTests {
|
|||
|
||||
@Test
|
||||
public void loadAuthorizationRequestWhenNoSessionThenEmpty() {
|
||||
StepVerifier.create(this.repository.loadAuthorizationRequest(this.exchange)).verifyComplete();
|
||||
// @formatter:off
|
||||
StepVerifier.create(this.repository.loadAuthorizationRequest(this.exchange))
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
assertSessionStartedIs(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadAuthorizationRequestWhenSessionAndNoRequestThenEmpty() {
|
||||
Mono<OAuth2AuthorizationRequest> setAttrThenLoad = this.exchange.getSession().map(WebSession::getAttributes)
|
||||
// @formatter:off
|
||||
Mono<OAuth2AuthorizationRequest> setAttrThenLoad = this.exchange.getSession()
|
||||
.map(WebSession::getAttributes)
|
||||
.doOnNext((attrs) -> attrs.put("foo", "bar"))
|
||||
.then(this.repository.loadAuthorizationRequest(this.exchange));
|
||||
StepVerifier.create(setAttrThenLoad).verifyComplete();
|
||||
StepVerifier.create(setAttrThenLoad)
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadAuthorizationRequestWhenNoStateParamThenEmpty() {
|
||||
this.exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
|
||||
// @formatter:off
|
||||
Mono<OAuth2AuthorizationRequest> saveAndLoad = this.repository
|
||||
.saveAuthorizationRequest(this.authorizationRequest, this.exchange)
|
||||
.then(this.repository.loadAuthorizationRequest(this.exchange));
|
||||
StepVerifier.create(saveAndLoad).verifyComplete();
|
||||
StepVerifier.create(saveAndLoad)
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadAuthorizationRequestWhenSavedThenAuthorizationRequest() {
|
||||
// @formatter:off
|
||||
Mono<OAuth2AuthorizationRequest> saveAndLoad = this.repository
|
||||
.saveAuthorizationRequest(this.authorizationRequest, this.exchange)
|
||||
.then(this.repository.loadAuthorizationRequest(this.exchange));
|
||||
StepVerifier.create(saveAndLoad).expectNext(this.authorizationRequest).verifyComplete();
|
||||
StepVerifier.create(saveAndLoad)
|
||||
.expectNext(this.authorizationRequest)
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadAuthorizationRequestWhenMultipleSavedThenAuthorizationRequest() {
|
||||
String oldState = "state0";
|
||||
// @formatter:off
|
||||
MockServerHttpRequest oldRequest = MockServerHttpRequest.get("/")
|
||||
.queryParam(OAuth2ParameterNames.STATE, oldState).build();
|
||||
.queryParam(OAuth2ParameterNames.STATE, oldState)
|
||||
.build();
|
||||
OAuth2AuthorizationRequest oldAuthorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
|
||||
.authorizationUri("https://example.com/oauth2/authorize").clientId("client-id")
|
||||
.redirectUri("http://localhost/client-1").state(oldState).build();
|
||||
.authorizationUri("https://example.com/oauth2/authorize")
|
||||
.clientId("client-id")
|
||||
.redirectUri("http://localhost/client-1")
|
||||
.state(oldState)
|
||||
.build();
|
||||
// @formatter:on
|
||||
WebSessionManager sessionManager = (e) -> this.exchange.getSession();
|
||||
this.exchange = new DefaultServerWebExchange(this.exchange.getRequest(), new MockServerHttpResponse(),
|
||||
sessionManager, ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver());
|
||||
ServerWebExchange oldExchange = new DefaultServerWebExchange(oldRequest, new MockServerHttpResponse(),
|
||||
sessionManager, ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver());
|
||||
// @formatter:off
|
||||
Mono<OAuth2AuthorizationRequest> saveAndSaveAndLoad = this.repository
|
||||
.saveAuthorizationRequest(oldAuthorizationRequest, oldExchange)
|
||||
.then(this.repository.saveAuthorizationRequest(this.authorizationRequest, this.exchange))
|
||||
.then(this.repository.loadAuthorizationRequest(oldExchange));
|
||||
StepVerifier.create(saveAndSaveAndLoad).expectNext(oldAuthorizationRequest).verifyComplete();
|
||||
StepVerifier.create(saveAndSaveAndLoad)
|
||||
.expectNext(oldAuthorizationRequest)
|
||||
.verifyComplete();
|
||||
StepVerifier.create(this.repository.loadAuthorizationRequest(this.exchange))
|
||||
.expectNext(this.authorizationRequest).verifyComplete();
|
||||
.expectNext(this.authorizationRequest)
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -147,58 +177,89 @@ public class WebSessionOAuth2ServerAuthorizationRequestRepositoryTests {
|
|||
|
||||
@Test
|
||||
public void removeAuthorizationRequestWhenPresentThenFoundAndRemoved() {
|
||||
// @formatter:off
|
||||
Mono<OAuth2AuthorizationRequest> saveAndRemove = this.repository
|
||||
.saveAuthorizationRequest(this.authorizationRequest, this.exchange)
|
||||
.then(this.repository.removeAuthorizationRequest(this.exchange));
|
||||
StepVerifier.create(saveAndRemove).expectNext(this.authorizationRequest).verifyComplete();
|
||||
StepVerifier.create(this.exchange.getSession().map(WebSession::getAttributes).map(Map::isEmpty))
|
||||
StepVerifier.create(saveAndRemove)
|
||||
.expectNext(this.authorizationRequest)
|
||||
.verifyComplete();
|
||||
StepVerifier.create(this.exchange
|
||||
.getSession()
|
||||
.map(WebSession::getAttributes)
|
||||
.map(Map::isEmpty)
|
||||
)
|
||||
.expectNext(true).verifyComplete();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// gh-5599
|
||||
@Test
|
||||
public void removeAuthorizationRequestWhenStateMissingThenNoErrors() {
|
||||
// @formatter:off
|
||||
MockServerHttpRequest otherState = MockServerHttpRequest.get("/")
|
||||
.queryParam(OAuth2ParameterNames.STATE, "other").build();
|
||||
ServerWebExchange otherStateExchange = this.exchange.mutate().request(otherState).build();
|
||||
.queryParam(OAuth2ParameterNames.STATE, "other")
|
||||
.build();
|
||||
ServerWebExchange otherStateExchange = this.exchange.mutate()
|
||||
.request(otherState)
|
||||
.build();
|
||||
Mono<OAuth2AuthorizationRequest> saveAndRemove = this.repository
|
||||
.saveAuthorizationRequest(this.authorizationRequest, this.exchange)
|
||||
.then(this.repository.removeAuthorizationRequest(otherStateExchange));
|
||||
StepVerifier.create(saveAndRemove).verifyComplete();
|
||||
StepVerifier.create(saveAndRemove)
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeAuthorizationRequestWhenMultipleThenOnlyOneRemoved() {
|
||||
String oldState = "state0";
|
||||
// @formatter:off
|
||||
MockServerHttpRequest oldRequest = MockServerHttpRequest.get("/")
|
||||
.queryParam(OAuth2ParameterNames.STATE, oldState).build();
|
||||
.queryParam(OAuth2ParameterNames.STATE, oldState)
|
||||
.build();
|
||||
OAuth2AuthorizationRequest oldAuthorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
|
||||
.authorizationUri("https://example.com/oauth2/authorize").clientId("client-id")
|
||||
.redirectUri("http://localhost/client-1").state(oldState).build();
|
||||
.authorizationUri("https://example.com/oauth2/authorize")
|
||||
.clientId("client-id")
|
||||
.redirectUri("http://localhost/client-1")
|
||||
.state(oldState)
|
||||
.build();
|
||||
// @formatter:on
|
||||
WebSessionManager sessionManager = (e) -> this.exchange.getSession();
|
||||
this.exchange = new DefaultServerWebExchange(this.exchange.getRequest(), new MockServerHttpResponse(),
|
||||
sessionManager, ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver());
|
||||
ServerWebExchange oldExchange = new DefaultServerWebExchange(oldRequest, new MockServerHttpResponse(),
|
||||
sessionManager, ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver());
|
||||
// @formatter:off
|
||||
Mono<OAuth2AuthorizationRequest> saveAndSaveAndRemove = this.repository
|
||||
.saveAuthorizationRequest(oldAuthorizationRequest, oldExchange)
|
||||
.then(this.repository.saveAuthorizationRequest(this.authorizationRequest, this.exchange))
|
||||
.then(this.repository.removeAuthorizationRequest(this.exchange));
|
||||
StepVerifier.create(saveAndSaveAndRemove).expectNext(this.authorizationRequest).verifyComplete();
|
||||
StepVerifier.create(this.repository.loadAuthorizationRequest(this.exchange)).verifyComplete();
|
||||
StepVerifier.create(this.repository.loadAuthorizationRequest(oldExchange)).expectNext(oldAuthorizationRequest)
|
||||
StepVerifier.create(saveAndSaveAndRemove).expectNext(this.authorizationRequest)
|
||||
.verifyComplete();
|
||||
StepVerifier.create(this.repository.loadAuthorizationRequest(this.exchange))
|
||||
.verifyComplete();
|
||||
StepVerifier.create(this.repository.loadAuthorizationRequest(oldExchange))
|
||||
.expectNext(oldAuthorizationRequest)
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// gh-7327
|
||||
@Test
|
||||
public void removeAuthorizationRequestWhenMultipleThenRemovedAndSessionAttributeUpdated() {
|
||||
String oldState = "state0";
|
||||
// @formatter:off
|
||||
MockServerHttpRequest oldRequest = MockServerHttpRequest.get("/")
|
||||
.queryParam(OAuth2ParameterNames.STATE, oldState).build();
|
||||
.queryParam(OAuth2ParameterNames.STATE, oldState)
|
||||
.build();
|
||||
OAuth2AuthorizationRequest oldAuthorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
|
||||
.authorizationUri("https://example.com/oauth2/authorize").clientId("client-id")
|
||||
.redirectUri("http://localhost/client-1").state(oldState).build();
|
||||
.authorizationUri("https://example.com/oauth2/authorize")
|
||||
.clientId("client-id")
|
||||
.redirectUri("http://localhost/client-1")
|
||||
.state(oldState)
|
||||
.build();
|
||||
// @formatter:on
|
||||
Map<String, Object> sessionAttrs = spy(new HashMap<>());
|
||||
WebSession session = mock(WebSession.class);
|
||||
given(session.getAttributes()).willReturn(sessionAttrs);
|
||||
|
@ -207,18 +268,27 @@ public class WebSessionOAuth2ServerAuthorizationRequestRepositoryTests {
|
|||
sessionManager, ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver());
|
||||
ServerWebExchange oldExchange = new DefaultServerWebExchange(oldRequest, new MockServerHttpResponse(),
|
||||
sessionManager, ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver());
|
||||
// @formatter:off
|
||||
Mono<OAuth2AuthorizationRequest> saveAndSaveAndRemove = this.repository
|
||||
.saveAuthorizationRequest(oldAuthorizationRequest, oldExchange)
|
||||
.then(this.repository.saveAuthorizationRequest(this.authorizationRequest, this.exchange))
|
||||
.then(this.repository.removeAuthorizationRequest(this.exchange));
|
||||
StepVerifier.create(saveAndSaveAndRemove).expectNext(this.authorizationRequest).verifyComplete();
|
||||
StepVerifier.create(this.repository.loadAuthorizationRequest(this.exchange)).verifyComplete();
|
||||
StepVerifier.create(saveAndSaveAndRemove).expectNext(this.authorizationRequest)
|
||||
.verifyComplete();
|
||||
StepVerifier.create(this.repository.loadAuthorizationRequest(this.exchange))
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
verify(sessionAttrs, times(3)).put(any(), any());
|
||||
}
|
||||
|
||||
private void assertSessionStartedIs(boolean expected) {
|
||||
Mono<Boolean> isStarted = this.exchange.getSession().map(WebSession::isStarted);
|
||||
StepVerifier.create(isStarted).expectNext(expected).verifyComplete();
|
||||
// @formatter:off
|
||||
Mono<Boolean> isStarted = this.exchange.getSession()
|
||||
.map(WebSession::isStarted);
|
||||
StepVerifier.create(isStarted)
|
||||
.expectNext(expected)
|
||||
.verifyComplete();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -90,12 +90,19 @@ public class OAuth2LoginAuthenticationWebFilterTests {
|
|||
DefaultOAuth2User user = new DefaultOAuth2User(AuthorityUtils.createAuthorityList("ROLE_USER"),
|
||||
Collections.singletonMap("user", "rob"), "user");
|
||||
ClientRegistration clientRegistration = this.registration.build();
|
||||
OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode().state("state")
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
|
||||
.state("state")
|
||||
.clientId(clientRegistration.getClientId())
|
||||
.authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri())
|
||||
.redirectUri(clientRegistration.getRedirectUri()).scopes(clientRegistration.getScopes()).build();
|
||||
.authorizationUri(clientRegistration.getProviderDetails()
|
||||
.getAuthorizationUri())
|
||||
.redirectUri(clientRegistration.getRedirectUri())
|
||||
.scopes(clientRegistration.getScopes())
|
||||
.build();
|
||||
OAuth2AuthorizationResponse authorizationResponse = this.authorizationResponseBldr
|
||||
.redirectUri(clientRegistration.getRedirectUri()).build();
|
||||
.redirectUri(clientRegistration.getRedirectUri())
|
||||
.build();
|
||||
// @formatter:on
|
||||
OAuth2AuthorizationExchange authorizationExchange = new OAuth2AuthorizationExchange(authorizationRequest,
|
||||
authorizationResponse);
|
||||
return new OAuth2LoginAuthenticationToken(clientRegistration, authorizationExchange, user,
|
||||
|
|
Loading…
Reference in New Issue