Polish oauth-client format

Issue gh-8945
This commit is contained in:
Rob Winch 2020-08-24 09:49:04 -05:00
parent 38aae7f015
commit dc47a7575e
97 changed files with 3421 additions and 1145 deletions

View File

@ -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
}
/**

View File

@ -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
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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(

View File

@ -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) {

View File

@ -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
}
/**

View File

@ -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
}
/**

View File

@ -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
}
/**

View File

@ -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,

View File

@ -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
}
/**

View File

@ -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
}
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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)));
});
}
/**

View File

@ -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,

View File

@ -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
}
}

View File

@ -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
}
/**

View File

@ -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,

View File

@ -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));
});

View File

@ -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
}
}

View File

@ -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) {

View File

@ -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(

View File

@ -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")

View File

@ -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
}
}

View File

@ -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));
}

View File

@ -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());
}

View File

@ -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);

View File

@ -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());

View File

@ -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());

View File

@ -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);

View File

@ -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

View File

@ -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
}
}

View File

@ -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() {

View File

@ -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);

View File

@ -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));
}

View File

@ -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());

View File

@ -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);

View File

@ -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));
}

View File

@ -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[] '"

View File

@ -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[] '"

View File

@ -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
}
}

View File

@ -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());
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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);

View File

@ -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,

View File

@ -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();

View File

@ -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

View File

@ -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);
}

View File

@ -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");

View File

@ -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");
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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))

View File

@ -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())

View File

@ -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);

View File

@ -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
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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) {

View File

@ -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)

View File

@ -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())

View File

@ -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<>();

View File

@ -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
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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
}
}

View File

@ -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());

View File

@ -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
}
}

View File

@ -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);

View File

@ -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&"

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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("/");

View File

@ -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
}
}

View File

@ -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,