Polish oauth2-resource-server format

Issue gh-8945
This commit is contained in:
Rob Winch 2020-08-24 09:49:58 -05:00
parent d5ae4337e3
commit 36ae1fe3f9
30 changed files with 673 additions and 201 deletions

View File

@ -87,23 +87,38 @@ public final class BearerTokenError extends OAuth2Error {
}
private static boolean isDescriptionValid(String description) {
return description == null || description.chars().allMatch((c) -> withinTheRangeOf(c, 0x20, 0x21)
|| withinTheRangeOf(c, 0x23, 0x5B) || withinTheRangeOf(c, 0x5D, 0x7E));
// @formatter:off
return description == null || description.chars().allMatch((c) ->
withinTheRangeOf(c, 0x20, 0x21) ||
withinTheRangeOf(c, 0x23, 0x5B) ||
withinTheRangeOf(c, 0x5D, 0x7E));
// @formatter:on
}
private static boolean isErrorCodeValid(String errorCode) {
return errorCode.chars().allMatch((c) -> withinTheRangeOf(c, 0x20, 0x21) || withinTheRangeOf(c, 0x23, 0x5B)
|| withinTheRangeOf(c, 0x5D, 0x7E));
// @formatter:off
return errorCode.chars().allMatch((c) ->
withinTheRangeOf(c, 0x20, 0x21) ||
withinTheRangeOf(c, 0x23, 0x5B) ||
withinTheRangeOf(c, 0x5D, 0x7E));
// @formatter:on
}
private static boolean isErrorUriValid(String errorUri) {
return errorUri == null || errorUri.chars()
.allMatch((c) -> c == 0x21 || withinTheRangeOf(c, 0x23, 0x5B) || withinTheRangeOf(c, 0x5D, 0x7E));
.allMatch((c) ->
c == 0x21 ||
withinTheRangeOf(c, 0x23, 0x5B) ||
withinTheRangeOf(c, 0x5D, 0x7E));
}
private static boolean isScopeValid(String scope) {
return scope == null || scope.chars().allMatch((c) -> withinTheRangeOf(c, 0x20, 0x21)
|| withinTheRangeOf(c, 0x23, 0x5B) || withinTheRangeOf(c, 0x5D, 0x7E));
// @formatter:off
return scope == null || scope.chars().allMatch((c) ->
withinTheRangeOf(c, 0x20, 0x21) ||
withinTheRangeOf(c, 0x23, 0x5B) ||
withinTheRangeOf(c, 0x5D, 0x7E));
// @formatter:on
}
private static boolean withinTheRangeOf(int c, int min, int max) {

View File

@ -122,9 +122,13 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver
*/
@Override
public Mono<ReactiveAuthenticationManager> resolve(ServerWebExchange exchange) {
// @formatter:off
return this.issuerConverter.convert(exchange)
.flatMap((issuer) -> this.issuerAuthenticationManagerResolver.resolve(issuer)
.switchIfEmpty(Mono.error(() -> new InvalidBearerTokenException("Invalid issuer " + issuer))));
.flatMap((issuer) -> this.issuerAuthenticationManagerResolver
.resolve(issuer)
.switchIfEmpty(Mono.error(() -> new InvalidBearerTokenException("Invalid issuer " + issuer)))
);
// @formatter:on
}
private static class JwtClaimIssuerConverter implements Converter<ServerWebExchange, Mono<String>> {
@ -166,10 +170,13 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver
if (!this.trustedIssuer.test(issuer)) {
return Mono.empty();
}
// @formatter:off
return this.authenticationManagers.computeIfAbsent(issuer,
(k) -> Mono.<ReactiveAuthenticationManager>fromCallable(
() -> new JwtReactiveAuthenticationManager(ReactiveJwtDecoders.fromIssuerLocation(k)))
.subscribeOn(Schedulers.boundedElastic()).cache());
(k) -> Mono.<ReactiveAuthenticationManager>fromCallable(() -> new JwtReactiveAuthenticationManager(ReactiveJwtDecoders.fromIssuerLocation(k)))
.subscribeOn(Schedulers.boundedElastic())
.cache()
);
// @formatter:on
}
}

View File

@ -52,10 +52,16 @@ public final class JwtReactiveAuthenticationManager implements ReactiveAuthentic
@Override
public Mono<Authentication> authenticate(Authentication authentication) {
return Mono.justOrEmpty(authentication).filter((a) -> a instanceof BearerTokenAuthenticationToken)
.cast(BearerTokenAuthenticationToken.class).map(BearerTokenAuthenticationToken::getToken)
.flatMap(this.jwtDecoder::decode).flatMap(this.jwtAuthenticationConverter::convert)
.cast(Authentication.class).onErrorMap(JwtException.class, this::onError);
// @formatter:off
return Mono.justOrEmpty(authentication)
.filter((a) -> a instanceof BearerTokenAuthenticationToken)
.cast(BearerTokenAuthenticationToken.class)
.map(BearerTokenAuthenticationToken::getToken)
.flatMap(this.jwtDecoder::decode)
.flatMap(this.jwtAuthenticationConverter::convert)
.cast(Authentication.class)
.onErrorMap(JwtException.class, this::onError);
// @formatter:on
}
/**

View File

@ -75,19 +75,28 @@ public class OpaqueTokenReactiveAuthenticationManager implements ReactiveAuthent
@Override
public Mono<Authentication> authenticate(Authentication authentication) {
return Mono.justOrEmpty(authentication).filter(BearerTokenAuthenticationToken.class::isInstance)
.cast(BearerTokenAuthenticationToken.class).map(BearerTokenAuthenticationToken::getToken)
.flatMap(this::authenticate).cast(Authentication.class);
// @formatter:off
return Mono.justOrEmpty(authentication)
.filter(BearerTokenAuthenticationToken.class::isInstance)
.cast(BearerTokenAuthenticationToken.class)
.map(BearerTokenAuthenticationToken::getToken)
.flatMap(this::authenticate)
.cast(Authentication.class);
// @formatter:on
}
private Mono<BearerTokenAuthentication> authenticate(String token) {
return this.introspector.introspect(token).map((principal) -> {
Instant iat = principal.getAttribute(OAuth2IntrospectionClaimNames.ISSUED_AT);
Instant exp = principal.getAttribute(OAuth2IntrospectionClaimNames.EXPIRES_AT);
// construct token
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, token, iat, exp);
return new BearerTokenAuthentication(principal, accessToken, principal.getAuthorities());
}).onErrorMap(OAuth2IntrospectionException.class, this::onError);
// @formatter:off
return this.introspector.introspect(token)
.map((principal) -> {
Instant iat = principal.getAttribute(OAuth2IntrospectionClaimNames.ISSUED_AT);
Instant exp = principal.getAttribute(OAuth2IntrospectionClaimNames.EXPIRES_AT);
// construct token
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, token, iat, exp);
return new BearerTokenAuthentication(principal, accessToken, principal.getAuthorities());
})
.onErrorMap(OAuth2IntrospectionException.class, this::onError);
// @formatter:on
}
private AuthenticationException onError(OAuth2IntrospectionException ex) {

View File

@ -39,8 +39,11 @@ public final class ReactiveJwtAuthenticationConverter implements Converter<Jwt,
@Override
public Mono<AbstractAuthenticationToken> convert(Jwt jwt) {
return this.jwtGrantedAuthoritiesConverter.convert(jwt).collectList()
// @formatter:off
return this.jwtGrantedAuthoritiesConverter.convert(jwt)
.collectList()
.map((authorities) -> new JwtAuthenticationToken(jwt, authorities));
// @formatter:on
}
/**

View File

@ -90,25 +90,39 @@ public class NimbusReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
@Override
public Mono<OAuth2AuthenticatedPrincipal> introspect(String token) {
return Mono.just(token).flatMap(this::makeRequest).flatMap(this::adaptToNimbusResponse)
.map(this::parseNimbusResponse).map(this::castToNimbusSuccess)
.doOnNext((response) -> validate(token, response)).map(this::convertClaimsSet)
// @formatter:off
return Mono.just(token)
.flatMap(this::makeRequest)
.flatMap(this::adaptToNimbusResponse)
.map(this::parseNimbusResponse)
.map(this::castToNimbusSuccess)
.doOnNext((response) -> validate(token, response))
.map(this::convertClaimsSet)
.onErrorMap((e) -> !(e instanceof OAuth2IntrospectionException), this::onError);
// @formatter:on
}
private Mono<ClientResponse> makeRequest(String token) {
return this.webClient.post().uri(this.introspectionUri)
// @formatter:off
return this.webClient.post()
.uri(this.introspectionUri)
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_UTF8_VALUE)
.body(BodyInserters.fromFormData("token", token)).exchange();
.body(BodyInserters.fromFormData("token", token))
.exchange();
// @formatter:on
}
private Mono<HTTPResponse> adaptToNimbusResponse(ClientResponse responseEntity) {
HTTPResponse response = new HTTPResponse(responseEntity.rawStatusCode());
response.setHeader(HttpHeaders.CONTENT_TYPE, responseEntity.headers().contentType().get().toString());
if (response.getStatusCode() != HTTPResponse.SC_OK) {
return responseEntity.bodyToFlux(DataBuffer.class).map(DataBufferUtils::release)
// @formatter:off
return responseEntity.bodyToFlux(DataBuffer.class)
.map(DataBufferUtils::release)
.then(Mono.error(new OAuth2IntrospectionException(
"Introspection endpoint responded with " + response.getStatusCode())));
"Introspection endpoint responded with " + response.getStatusCode()))
);
// @formatter:on
}
return responseEntity.bodyToMono(String.class).doOnNext(response::setContent).map((body) -> response);
}

View File

@ -59,9 +59,13 @@ public class BearerTokenServerAccessDeniedHandler implements ServerAccessDeniedH
if (this.realmName != null) {
parameters.put("realm", this.realmName);
}
return exchange.getPrincipal().filter(AbstractOAuth2TokenAuthenticationToken.class::isInstance)
.map((token) -> errorMessageParameters(parameters)).switchIfEmpty(Mono.just(parameters))
// @formatter:off
return exchange.getPrincipal()
.filter(AbstractOAuth2TokenAuthenticationToken.class::isInstance)
.map((token) -> errorMessageParameters(parameters))
.switchIfEmpty(Mono.just(parameters))
.flatMap((params) -> respond(exchange, params));
// @formatter:on
}
/**

View File

@ -53,21 +53,35 @@ public final class ServerBearerExchangeFilterFunction implements ExchangeFilterF
@Override
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
return oauth2Token().map((token) -> bearer(request, token)).defaultIfEmpty(request).flatMap(next::exchange);
// @formatter:off
return oauth2Token().map((token) -> bearer(request, token))
.defaultIfEmpty(request)
.flatMap(next::exchange);
// @formatter:on
}
private Mono<AbstractOAuth2Token> oauth2Token() {
// @formatter:off
return currentAuthentication()
.filter((authentication) -> authentication.getCredentials() instanceof AbstractOAuth2Token)
.map(Authentication::getCredentials).cast(AbstractOAuth2Token.class);
.map(Authentication::getCredentials)
.cast(AbstractOAuth2Token.class);
// @formatter:on
}
private Mono<Authentication> currentAuthentication() {
return ReactiveSecurityContextHolder.getContext().map(SecurityContext::getAuthentication);
// @formatter:off
return ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication);
// @formatter:on
}
private ClientRequest bearer(ClientRequest request, AbstractOAuth2Token token) {
return ClientRequest.from(request).headers((headers) -> headers.setBearerAuth(token.getTokenValue())).build();
// @formatter:off
return ClientRequest.from(request)
.headers((headers) -> headers.setBearerAuth(token.getTokenValue()))
.build();
// @formatter:on
}
}

View File

@ -64,13 +64,21 @@ public final class ServletBearerExchangeFilterFunction implements ExchangeFilter
@Override
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
return oauth2Token().map((token) -> bearer(request, token)).defaultIfEmpty(request).flatMap(next::exchange);
// @formatter:off
return oauth2Token().map((token) -> bearer(request, token))
.defaultIfEmpty(request)
.flatMap(next::exchange);
// @formatter:on
}
private Mono<AbstractOAuth2Token> oauth2Token() {
return Mono.subscriberContext().flatMap(this::currentAuthentication)
// @formatter:off
return Mono.subscriberContext()
.flatMap(this::currentAuthentication)
.filter((authentication) -> authentication.getCredentials() instanceof AbstractOAuth2Token)
.map(Authentication::getCredentials).cast(AbstractOAuth2Token.class);
.map(Authentication::getCredentials)
.cast(AbstractOAuth2Token.class);
// @formatter:on
}
private Mono<Authentication> currentAuthentication(Context ctx) {
@ -88,7 +96,11 @@ public final class ServletBearerExchangeFilterFunction implements ExchangeFilter
}
private ClientRequest bearer(ClientRequest request, AbstractOAuth2Token token) {
return ClientRequest.from(request).headers((headers) -> headers.setBearerAuth(token.getTokenValue())).build();
// @formatter:off
return ClientRequest.from(request)
.headers((headers) -> headers.setBearerAuth(token.getTokenValue()))
.build();
// @formatter:on
}
}

View File

@ -30,14 +30,20 @@ public class BearerTokenAuthenticationTokenTests {
@Test
public void constructorWhenTokenIsNullThenThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new BearerTokenAuthenticationToken(null))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenAuthenticationToken(null))
.withMessageContaining("token cannot be empty");
// @formatter:on
}
@Test
public void constructorWhenTokenIsEmptyThenThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new BearerTokenAuthenticationToken(""))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenAuthenticationToken(""))
.withMessageContaining("token cannot be empty");
// @formatter:on
}
@Test

View File

@ -53,20 +53,29 @@ public class BearerTokenErrorTests {
@Test
public void constructorWithErrorCodeAndHttpStatusWhenErrorCodeIsNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> new BearerTokenError(null, TEST_HTTP_STATUS, null, null))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenError(null, TEST_HTTP_STATUS, null, null))
.withMessage("errorCode cannot be empty");
// @formatter:on
}
@Test
public void constructorWithErrorCodeAndHttpStatusWhenErrorCodeIsEmptyThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> new BearerTokenError("", TEST_HTTP_STATUS, null, null))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenError("", TEST_HTTP_STATUS, null, null))
.withMessage("errorCode cannot be empty");
// @formatter:on
}
@Test
public void constructorWithErrorCodeAndHttpStatusWhenHttpStatusIsNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> new BearerTokenError(TEST_ERROR_CODE, null, null, null))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenError(TEST_ERROR_CODE, null, null, null))
.withMessage("httpStatus cannot be null");
// @formatter:on
}
@Test
@ -82,52 +91,77 @@ public class BearerTokenErrorTests {
@Test
public void constructorWithAllParametersWhenErrorCodeIsNullThenThrowIllegalArgumentException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenError(null, TEST_HTTP_STATUS, TEST_DESCRIPTION, TEST_URI, TEST_SCOPE))
.withMessage("errorCode cannot be empty");
// @formatter:on
}
@Test
public void constructorWithAllParametersWhenErrorCodeIsEmptyThenThrowIllegalArgumentException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenError("", TEST_HTTP_STATUS, TEST_DESCRIPTION, TEST_URI, TEST_SCOPE))
.withMessage("errorCode cannot be empty");
// @formatter:on
}
@Test
public void constructorWithAllParametersWhenHttpStatusIsNullThenThrowIllegalArgumentException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenError(TEST_ERROR_CODE, null, TEST_DESCRIPTION, TEST_URI, TEST_SCOPE))
.withMessage("httpStatus cannot be null");
// @formatter:on
}
@Test
public void constructorWithAllParametersWhenErrorCodeIsInvalidThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> new BearerTokenError(TEST_ERROR_CODE + "\"",
TEST_HTTP_STATUS, TEST_DESCRIPTION, TEST_URI, TEST_SCOPE)).withMessageContaining("errorCode")
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenError(TEST_ERROR_CODE + "\"",
TEST_HTTP_STATUS, TEST_DESCRIPTION, TEST_URI, TEST_SCOPE)
)
.withMessageContaining("errorCode")
.withMessageContaining("RFC 6750");
// @formatter:on
}
@Test
public void constructorWithAllParametersWhenDescriptionIsInvalidThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> new BearerTokenError(TEST_ERROR_CODE, TEST_HTTP_STATUS,
TEST_DESCRIPTION + "\"", TEST_URI, TEST_SCOPE)).withMessageContaining("description")
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenError(TEST_ERROR_CODE, TEST_HTTP_STATUS,
TEST_DESCRIPTION + "\"", TEST_URI, TEST_SCOPE)
)
.withMessageContaining("description")
.withMessageContaining("RFC 6750");
// @formatter:on
}
@Test
public void constructorWithAllParametersWhenErrorUriIsInvalidThenThrowIllegalArgumentException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenError(TEST_ERROR_CODE, TEST_HTTP_STATUS, TEST_DESCRIPTION,
TEST_URI + "\"", TEST_SCOPE))
.withMessageContaining("errorUri").withMessageContaining("RFC 6750");
TEST_URI + "\"", TEST_SCOPE)
)
.withMessageContaining("errorUri")
.withMessageContaining("RFC 6750");
// @formatter:on
}
@Test
public void constructorWithAllParametersWhenScopeIsInvalidThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> new BearerTokenError(TEST_ERROR_CODE, TEST_HTTP_STATUS,
TEST_DESCRIPTION, TEST_URI, TEST_SCOPE + "\"")).withMessageContaining("scope")
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenError(TEST_ERROR_CODE, TEST_HTTP_STATUS,
TEST_DESCRIPTION, TEST_URI, TEST_SCOPE + "\"")
)
.withMessageContaining("scope")
.withMessageContaining("RFC 6750");
// @formatter:on
}
}

View File

@ -84,20 +84,28 @@ public class BearerTokenAuthenticationTests {
@Test
public void getNameWhenTokenHasUsernameThenReturnsUsernameAttribute() {
BearerTokenAuthentication authenticated = new BearerTokenAuthentication(this.principal, this.token, null);
// @formatter:off
assertThat(authenticated.getName())
.isEqualTo(this.principal.getAttribute(OAuth2IntrospectionClaimNames.SUBJECT));
// @formatter:on
}
@Test
public void constructorWhenTokenIsNullThenThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new BearerTokenAuthentication(this.principal, null, null))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenAuthentication(this.principal, null, null))
.withMessageContaining("token cannot be null");
// @formatter:on
}
@Test
public void constructorWhenCredentialIsNullThenThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new BearerTokenAuthentication(null, this.token, null))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenAuthentication(null, this.token, null))
.withMessageContaining("principal cannot be null");
// @formatter:on
}
@Test

View File

@ -70,22 +70,29 @@ public class JwtAuthenticationConverterTests {
@Test
public void whenSettingNullPrincipalClaimName() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> this.jwtAuthenticationConverter.setPrincipalClaimName(null))
.withMessage("principalClaimName cannot be empty");
// @formatter:on
}
@Test
public void whenSettingEmptyPrincipalClaimName() {
assertThatIllegalArgumentException().isThrownBy(() -> this.jwtAuthenticationConverter.setPrincipalClaimName(""))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> this.jwtAuthenticationConverter.setPrincipalClaimName(""))
.withMessage("principalClaimName cannot be empty");
// @formatter:on
}
@Test
public void whenSettingBlankPrincipalClaimName() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> this.jwtAuthenticationConverter.setPrincipalClaimName(" "))
.withMessage("principalClaimName cannot be empty");
// @formatter:on
}
@Test

View File

@ -76,18 +76,22 @@ public class JwtAuthenticationProviderTests {
public void authenticateWhenJwtDecodeFailsThenRespondsWithInvalidToken() {
BearerTokenAuthenticationToken token = this.authentication();
given(this.jwtDecoder.decode("token")).willThrow(BadJwtException.class);
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> this.provider.authenticate(token))
.matches(errorCode(BearerTokenErrorCodes.INVALID_TOKEN));
// @formatter:on
}
@Test
public void authenticateWhenDecoderThrowsIncompatibleErrorMessageThenWrapsWithGenericOne() {
BearerTokenAuthenticationToken token = this.authentication();
given(this.jwtDecoder.decode(token.getToken())).willThrow(new BadJwtException("with \"invalid\" chars"));
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> this.provider.authenticate(token))
.satisfies((ex) -> assertThat(ex).hasFieldOrPropertyWithValue("error.description", "Invalid token"));
// @formatter:on
}
// gh-7785
@ -95,8 +99,11 @@ public class JwtAuthenticationProviderTests {
public void authenticateWhenDecoderFailsGenericallyThenThrowsGenericException() {
BearerTokenAuthenticationToken token = this.authentication();
given(this.jwtDecoder.decode(token.getToken())).willThrow(new JwtException("no jwk set"));
assertThatExceptionOfType(AuthenticationException.class).isThrownBy(() -> this.provider.authenticate(token))
// @formatter:off
assertThatExceptionOfType(AuthenticationException.class)
.isThrownBy(() -> this.provider.authenticate(token))
.isNotInstanceOf(OAuth2AuthenticationException.class);
// @formatter:on
}
@Test
@ -108,8 +115,11 @@ public class JwtAuthenticationProviderTests {
JwtAuthenticationToken authentication = new JwtAuthenticationToken(jwt);
given(this.jwtDecoder.decode(token.getToken())).willReturn(jwt);
given(this.jwtAuthenticationConverter.convert(jwt)).willReturn(authentication);
assertThat(this.provider.authenticate(token)).isEqualTo(authentication).hasFieldOrPropertyWithValue("details",
// @formatter:off
assertThat(this.provider.authenticate(token))
.isEqualTo(authentication).hasFieldOrPropertyWithValue("details",
details);
// @formatter:on
}
@Test

View File

@ -37,7 +37,12 @@ public class JwtBearerTokenAuthenticationConverterTests {
@Test
public void convertWhenJwtThenBearerTokenAuthentication() {
Jwt jwt = Jwt.withTokenValue("token-value").claim("claim", "value").header("header", "value").build();
// @formatter:off
Jwt jwt = Jwt.withTokenValue("token-value")
.claim("claim", "value")
.header("header", "value")
.build();
// @formatter:on
AbstractAuthenticationToken token = this.converter.convert(jwt);
assertThat(token).isInstanceOf(BearerTokenAuthentication.class);
BearerTokenAuthentication bearerToken = (BearerTokenAuthentication) token;
@ -48,8 +53,12 @@ public class JwtBearerTokenAuthenticationConverterTests {
@Test
public void convertWhenJwtWithScopeAttributeThenBearerTokenAuthentication() {
Jwt jwt = Jwt.withTokenValue("token-value").claim("scope", "message:read message:write")
.header("header", "value").build();
// @formatter:off
Jwt jwt = Jwt.withTokenValue("token-value")
.claim("scope", "message:read message:write")
.header("header", "value")
.build();
// @formatter:on
AbstractAuthenticationToken token = this.converter.convert(jwt);
assertThat(token).isInstanceOf(BearerTokenAuthentication.class);
BearerTokenAuthentication bearerToken = (BearerTokenAuthentication) token;
@ -59,8 +68,12 @@ public class JwtBearerTokenAuthenticationConverterTests {
@Test
public void convertWhenJwtWithScpAttributeThenBearerTokenAuthentication() {
Jwt jwt = Jwt.withTokenValue("token-value").claim("scp", Arrays.asList("message:read", "message:write"))
.header("header", "value").build();
// @formatter:off
Jwt jwt = Jwt.withTokenValue("token-value")
.claim("scp", Arrays.asList("message:read", "message:write"))
.header("header", "value")
.build();
// @formatter:on
AbstractAuthenticationToken token = this.converter.convert(jwt);
assertThat(token).isInstanceOf(BearerTokenAuthentication.class);
BearerTokenAuthentication bearerToken = (BearerTokenAuthentication) token;

View File

@ -45,7 +45,11 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWhenTokenHasScopeAttributeThenTranslatedToAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scope", "message:read message:write").build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scope", "message:read message:write")
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly(new SimpleGrantedAuthority("SCOPE_message:read"),
@ -54,7 +58,11 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWithCustomAuthorityPrefixWhenTokenHasScopeAttributeThenTranslatedToAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scope", "message:read message:write").build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scope", "message:read message:write")
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
@ -64,7 +72,11 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWithBlankAsCustomAuthorityPrefixWhenTokenHasScopeAttributeThenTranslatedToAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scope", "message:read message:write").build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scope", "message:read message:write")
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthorityPrefix("");
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
@ -74,7 +86,11 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWhenTokenHasEmptyScopeAttributeThenTranslatedToNoAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scope", "").build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scope", "")
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).isEmpty();
@ -82,7 +98,11 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWhenTokenHasScpAttributeThenTranslatedToAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scp", Arrays.asList("message:read", "message:write")).build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scp", Arrays.asList("message:read", "message:write"))
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly(new SimpleGrantedAuthority("SCOPE_message:read"),
@ -91,7 +111,11 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWithCustomAuthorityPrefixWhenTokenHasScpAttributeThenTranslatedToAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scp", Arrays.asList("message:read", "message:write")).build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scp", Arrays.asList("message:read", "message:write"))
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
@ -101,7 +125,11 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWithBlankAsCustomAuthorityPrefixWhenTokenHasScpAttributeThenTranslatedToAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scp", "message:read message:write").build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scp", "message:read message:write")
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthorityPrefix("");
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
@ -111,7 +139,11 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWhenTokenHasEmptyScpAttributeThenTranslatedToNoAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scp", Collections.emptyList()).build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scp", Collections.emptyList())
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).isEmpty();
@ -119,8 +151,12 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWhenTokenHasBothScopeAndScpThenScopeAttributeIsTranslatedToAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scp", Arrays.asList("message:read", "message:write"))
.claim("scope", "missive:read missive:write").build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scp", Arrays.asList("message:read", "message:write"))
.claim("scope", "missive:read missive:write")
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly(new SimpleGrantedAuthority("SCOPE_missive:read"),
@ -129,8 +165,12 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWhenTokenHasEmptyScopeAndNonEmptyScpThenScopeAttributeIsTranslatedToNoAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scp", Arrays.asList("message:read", "message:write")).claim("scope", "")
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scp", Arrays.asList("message:read", "message:write"))
.claim("scope", "")
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).isEmpty();
@ -138,15 +178,25 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWhenTokenHasEmptyScopeAndEmptyScpAttributeThenTranslatesToNoAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scp", Collections.emptyList()).claim("scope", Collections.emptyList()).build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scp", Collections.emptyList())
.claim("scope", Collections.emptyList())
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).isEmpty();
assertThat(authorities)
.isEmpty();
}
@Test
public void convertWhenTokenHasNoScopeAndNoScpAttributeThenTranslatesToNoAuthorities() {
Jwt jwt = TestJwts.jwt().claim("roles", Arrays.asList("message:read", "message:write")).build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("roles", Arrays.asList("message:read", "message:write"))
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).isEmpty();
@ -154,16 +204,25 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWhenTokenHasUnsupportedTypeForScopeThenTranslatesToNoAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scope", new String[] { "message:read", "message:write" }).build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scope", new String[] { "message:read", "message:write" })
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).isEmpty();
assertThat(authorities)
.isEmpty();
}
@Test
public void convertWhenTokenHasCustomClaimNameThenCustomClaimNameAttributeIsTranslatedToAuthorities() {
Jwt jwt = TestJwts.jwt().claim("roles", Arrays.asList("message:read", "message:write"))
.claim("scope", "missive:read missive:write").build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("roles", Arrays.asList("message:read", "message:write"))
.claim("scope", "missive:read missive:write")
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
@ -173,8 +232,12 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWhenTokenHasEmptyCustomClaimNameThenCustomClaimNameAttributeIsTranslatedToNoAuthorities() {
Jwt jwt = TestJwts.jwt().claim("roles", Collections.emptyList()).claim("scope", "missive:read missive:write")
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("roles", Collections.emptyList())
.claim("scope", "missive:read missive:write")
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
@ -183,7 +246,11 @@ public class JwtGrantedAuthoritiesConverterTests {
@Test
public void convertWhenTokenHasNoCustomClaimNameThenCustomClaimNameAttributeIsTranslatedToNoAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scope", "missive:read missive:write").build();
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scope", "missive:read missive:write")
.build();
// @formatter:on
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);

View File

@ -64,8 +64,12 @@ public class JwtIssuerAuthenticationManagerResolverTests {
try (MockWebServer server = new MockWebServer()) {
server.start();
String issuer = server.url("").toString();
server.enqueue(new MockResponse().setResponseCode(200).setHeader("Content-Type", "application/json")
.setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer)));
// @formatter:off
server.enqueue(new MockResponse().setResponseCode(200)
.setHeader("Content-Type", "application/json")
.setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer)
));
// @formatter:on
JWSObject jws = new JWSObject(new JWSHeader(JWSAlgorithm.RS256),
new Payload(new JSONObject(Collections.singletonMap(JwtClaimNames.ISS, issuer))));
jws.sign(new RSASSASigner(TestKeys.DEFAULT_PRIVATE_KEY));
@ -86,9 +90,11 @@ public class JwtIssuerAuthenticationManagerResolverTests {
"other", "issuers");
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Bearer " + this.jwt);
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> authenticationManagerResolver.resolve(request))
.withMessageContaining("Invalid issuer");
// @formatter:on
}
@Test
@ -108,16 +114,20 @@ public class JwtIssuerAuthenticationManagerResolverTests {
Map<String, AuthenticationManager> authenticationManagers = new HashMap<>();
JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver(
authenticationManagers::get);
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> authenticationManagerResolver.resolve(request))
.withMessageContaining("Invalid issuer");
// @formatter:on
AuthenticationManager authenticationManager = mock(AuthenticationManager.class);
authenticationManagers.put("trusted", authenticationManager);
assertThat(authenticationManagerResolver.resolve(request)).isSameAs(authenticationManager);
authenticationManagers.clear();
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> authenticationManagerResolver.resolve(request))
.withMessageContaining("Invalid issuer");
// @formatter:on
}
@Test
@ -126,9 +136,11 @@ public class JwtIssuerAuthenticationManagerResolverTests {
"trusted");
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Bearer jwt");
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> authenticationManagerResolver.resolve(request))
.withMessageNotContaining("Invalid issuer");
// @formatter:on
}
@Test
@ -137,9 +149,11 @@ public class JwtIssuerAuthenticationManagerResolverTests {
"trusted");
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Bearer " + this.noIssuer);
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> authenticationManagerResolver.resolve(request))
.withMessageContaining("Missing issuer");
// @formatter:on
}
@Test
@ -148,8 +162,13 @@ public class JwtIssuerAuthenticationManagerResolverTests {
"trusted");
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Bearer " + this.evil);
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> authenticationManagerResolver.resolve(request)).withMessage("Invalid issuer");
.isThrownBy(() -> authenticationManagerResolver
.resolve(request)
)
.withMessage("Invalid issuer");
// @formatter:on
}
@Test

View File

@ -52,8 +52,12 @@ import static org.mockito.Mockito.mock;
*/
public class JwtIssuerReactiveAuthenticationManagerResolverTests {
private static final String DEFAULT_RESPONSE_TEMPLATE = "{\n" + " \"issuer\": \"%s\", \n"
+ " \"jwks_uri\": \"%s/.well-known/jwks.json\" \n" + "}";
// @formatter:off
private static final String DEFAULT_RESPONSE_TEMPLATE = "{\n"
+ " \"issuer\": \"%s\", \n"
+ " \"jwks_uri\": \"%s/.well-known/jwks.json\" \n"
+ "}";
// @formatter:on
private String jwt = jwt("iss", "trusted");
@ -87,9 +91,11 @@ public class JwtIssuerReactiveAuthenticationManagerResolverTests {
JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver(
"other", "issuers");
MockServerWebExchange exchange = withBearerToken(this.jwt);
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> authenticationManagerResolver.resolve(exchange).block())
.withMessageContaining("Invalid issuer");
// @formatter:on
}
@Test
@ -114,9 +120,11 @@ public class JwtIssuerReactiveAuthenticationManagerResolverTests {
authenticationManagers.put("trusted", authenticationManager);
assertThat(authenticationManagerResolver.resolve(exchange).block()).isSameAs(authenticationManager);
authenticationManagers.clear();
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> authenticationManagerResolver.resolve(exchange).block())
.withMessageContaining("Invalid issuer");
// @formatter:on
}
@Test
@ -124,9 +132,11 @@ public class JwtIssuerReactiveAuthenticationManagerResolverTests {
JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver(
"trusted");
MockServerWebExchange exchange = withBearerToken("jwt");
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> authenticationManagerResolver.resolve(exchange).block())
.withMessageNotContaining("Invalid issuer");
// @formatter:on
}
@Test
@ -144,8 +154,11 @@ public class JwtIssuerReactiveAuthenticationManagerResolverTests {
JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver(
"trusted");
MockServerWebExchange exchange = withBearerToken(this.evil);
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> authenticationManagerResolver.resolve(exchange).block()).withMessage("Invalid token");
.isThrownBy(() -> authenticationManagerResolver.resolve(exchange).block())
.withMessage("Invalid token");
// @formatter:on
}
@Test
@ -159,7 +172,7 @@ public class JwtIssuerReactiveAuthenticationManagerResolverTests {
@Test
public void constructorWhenNullAuthenticationManagerResolverThenException() {
assertThatIllegalArgumentException().isThrownBy(
() -> new JwtIssuerReactiveAuthenticationManagerResolver((ReactiveAuthenticationManagerResolver) null));
() -> new JwtIssuerReactiveAuthenticationManagerResolver((ReactiveAuthenticationManagerResolver) null));JwtReactiveAuthenticationManagerTests
}
private String jwt(String claim, String value) {
@ -168,8 +181,11 @@ public class JwtIssuerReactiveAuthenticationManagerResolverTests {
}
private MockServerWebExchange withBearerToken(String token) {
MockServerHttpRequest request = MockServerHttpRequest.get("/").header("Authorization", "Bearer " + token)
// @formatter:off
MockServerHttpRequest request = MockServerHttpRequest.get("/")
.header("Authorization", "Bearer " + token)
.build();
// @formatter:on
return MockServerWebExchange.from(request);
}

View File

@ -58,13 +58,20 @@ public class JwtReactiveAuthenticationManagerTests {
@Before
public void setup() {
this.manager = new JwtReactiveAuthenticationManager(this.jwtDecoder);
this.jwt = TestJwts.jwt().claim("scope", "message:read message:write").build();
// @formatter:off
this.jwt = TestJwts.jwt()
.claim("scope", "message:read message:write")
.build();
// @formatter:on
}
@Test
public void constructorWhenJwtDecoderNullThenIllegalArgumentException() {
this.jwtDecoder = null;
assertThatIllegalArgumentException().isThrownBy(() -> new JwtReactiveAuthenticationManager(this.jwtDecoder));
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new JwtReactiveAuthenticationManager(this.jwtDecoder));
// @formatter:on
}
@Test
@ -93,9 +100,13 @@ public class JwtReactiveAuthenticationManagerTests {
public void authenticateWhenDecoderThrowsIncompatibleErrorMessageThenWrapsWithGenericOne() {
BearerTokenAuthenticationToken token = new BearerTokenAuthenticationToken("token-1");
given(this.jwtDecoder.decode(token.getToken())).willThrow(new BadJwtException("with \"invalid\" chars"));
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> this.manager.authenticate(token).block())
.satisfies((ex) -> assertThat(ex).hasFieldOrPropertyWithValue("error.description", "Invalid token"));
.satisfies((ex) -> assertThat(ex)
.hasFieldOrPropertyWithValue("error.description", "Invalid token")
);
// @formatter:on
}
// gh-7785
@ -103,16 +114,21 @@ public class JwtReactiveAuthenticationManagerTests {
public void authenticateWhenDecoderFailsGenericallyThenThrowsGenericException() {
BearerTokenAuthenticationToken token = new BearerTokenAuthenticationToken("token-1");
given(this.jwtDecoder.decode(token.getToken())).willThrow(new JwtException("no jwk set"));
// @formatter:off
assertThatExceptionOfType(AuthenticationException.class)
.isThrownBy(() -> this.manager.authenticate(token).block())
.isNotInstanceOf(OAuth2AuthenticationException.class);
// @formatter:on
}
@Test
public void authenticateWhenNotJwtExceptionThenPropagates() {
BearerTokenAuthenticationToken token = new BearerTokenAuthenticationToken("token-1");
given(this.jwtDecoder.decode(any())).willReturn(Mono.error(new RuntimeException("Oops")));
assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> this.manager.authenticate(token).block());
// @formatter:off
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() -> this.manager.authenticate(token).block());
// @formatter:on
}
@Test
@ -122,8 +138,11 @@ public class JwtReactiveAuthenticationManagerTests {
Authentication authentication = this.manager.authenticate(token).block();
assertThat(authentication).isNotNull();
assertThat(authentication.isAuthenticated()).isTrue();
assertThat(authentication.getAuthorities()).extracting(GrantedAuthority::getAuthority)
// @formatter:off
assertThat(authentication.getAuthorities())
.extracting(GrantedAuthority::getAuthority)
.containsOnly("SCOPE_message:read", "SCOPE_message:write");
// @formatter:on
}
}

View File

@ -58,7 +58,10 @@ public class OpaqueTokenAuthenticationProviderTests {
Authentication result = provider.authenticate(new BearerTokenAuthenticationToken("token"));
assertThat(result.getPrincipal()).isInstanceOf(OAuth2IntrospectionAuthenticatedPrincipal.class);
Map<String, Object> attributes = ((OAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes();
assertThat(attributes).isNotNull().containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
// @formatter:off
assertThat(attributes)
.isNotNull()
.containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
.containsEntry(OAuth2IntrospectionClaimNames.AUDIENCE,
Arrays.asList("https://protected.example.net/resource"))
.containsEntry(OAuth2IntrospectionClaimNames.CLIENT_ID, "l238j323ds-23ij4")
@ -69,8 +72,11 @@ public class OpaqueTokenAuthenticationProviderTests {
.containsEntry(OAuth2IntrospectionClaimNames.SUBJECT, "Z5O3upPC88QrAjx00dis")
.containsEntry(OAuth2IntrospectionClaimNames.USERNAME, "jdoe")
.containsEntry("extension_field", "twenty-seven");
assertThat(result.getAuthorities()).extracting("authority").containsExactly("SCOPE_read", "SCOPE_write",
assertThat(result.getAuthorities())
.extracting("authority")
.containsExactly("SCOPE_read", "SCOPE_write",
"SCOPE_dolphin");
// @formatter:on
}
@Test
@ -83,7 +89,11 @@ public class OpaqueTokenAuthenticationProviderTests {
Authentication result = provider.authenticate(new BearerTokenAuthenticationToken("token"));
assertThat(result.getPrincipal()).isInstanceOf(OAuth2AuthenticatedPrincipal.class);
Map<String, Object> attributes = ((OAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes();
assertThat(attributes).isNotNull().doesNotContainKey(OAuth2IntrospectionClaimNames.SCOPE);
// @formatter:off
assertThat(attributes)
.isNotNull()
.doesNotContainKey(OAuth2IntrospectionClaimNames.SCOPE);
// @formatter:on
assertThat(result.getAuthorities()).isEmpty();
}
@ -98,7 +108,10 @@ public class OpaqueTokenAuthenticationProviderTests {
@Test
public void constructorWhenIntrospectionClientIsNullThenIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> new OpaqueTokenAuthenticationProvider(null));
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new OpaqueTokenAuthenticationProvider(null));
// @formatter:on
}
}

View File

@ -59,7 +59,10 @@ public class OpaqueTokenReactiveAuthenticationManagerTests {
Authentication result = provider.authenticate(new BearerTokenAuthenticationToken("token")).block();
assertThat(result.getPrincipal()).isInstanceOf(OAuth2IntrospectionAuthenticatedPrincipal.class);
Map<String, Object> attributes = ((OAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes();
assertThat(attributes).isNotNull().containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
// @formatter:off
assertThat(attributes)
.isNotNull()
.containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
.containsEntry(OAuth2IntrospectionClaimNames.AUDIENCE,
Arrays.asList("https://protected.example.net/resource"))
.containsEntry(OAuth2IntrospectionClaimNames.CLIENT_ID, "l238j323ds-23ij4")
@ -70,8 +73,11 @@ public class OpaqueTokenReactiveAuthenticationManagerTests {
.containsEntry(OAuth2IntrospectionClaimNames.SUBJECT, "Z5O3upPC88QrAjx00dis")
.containsEntry(OAuth2IntrospectionClaimNames.USERNAME, "jdoe")
.containsEntry("extension_field", "twenty-seven");
assertThat(result.getAuthorities()).extracting("authority").containsExactly("SCOPE_read", "SCOPE_write",
assertThat(result.getAuthorities())
.extracting("authority")
.containsExactly("SCOPE_read", "SCOPE_write",
"SCOPE_dolphin");
// @formatter:on
}
@Test
@ -100,7 +106,10 @@ public class OpaqueTokenReactiveAuthenticationManagerTests {
@Test
public void constructorWhenIntrospectionClientIsNullThenIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> new OpaqueTokenReactiveAuthenticationManager(null));
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new OpaqueTokenReactiveAuthenticationManager(null));
// @formatter:on
}
}

View File

@ -47,8 +47,11 @@ public class ReactiveJwtAuthenticationConverterAdapterTests {
Jwt jwt = TestJwts.jwt().claim("scope", "message:read message:write").build();
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block();
Collection<GrantedAuthority> authorities = authentication.getAuthorities();
assertThat(authorities).containsExactly(new SimpleGrantedAuthority("SCOPE_message:read"),
new SimpleGrantedAuthority("SCOPE_message:write"));
// @formatter:off
assertThat(authorities)
.containsExactly(new SimpleGrantedAuthority("SCOPE_message:read"),
new SimpleGrantedAuthority("SCOPE_message:write"));
// @formatter:on
}
@Test
@ -64,8 +67,11 @@ public class ReactiveJwtAuthenticationConverterAdapterTests {
Jwt jwt = TestJwts.jwt().claim("scp", Arrays.asList("message:read", "message:write")).build();
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block();
Collection<GrantedAuthority> authorities = authentication.getAuthorities();
assertThat(authorities).containsExactly(new SimpleGrantedAuthority("SCOPE_message:read"),
new SimpleGrantedAuthority("SCOPE_message:write"));
// @formatter:off
assertThat(authorities)
.containsExactly(new SimpleGrantedAuthority("SCOPE_message:read"),
new SimpleGrantedAuthority("SCOPE_message:write"));
// @formatter:on
}
@Test
@ -82,14 +88,21 @@ public class ReactiveJwtAuthenticationConverterAdapterTests {
.claim("scope", "missive:read missive:write").build();
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block();
Collection<GrantedAuthority> authorities = authentication.getAuthorities();
assertThat(authorities).containsExactly(new SimpleGrantedAuthority("SCOPE_missive:read"),
new SimpleGrantedAuthority("SCOPE_missive:write"));
// @formatter:off
assertThat(authorities)
.containsExactly(new SimpleGrantedAuthority("SCOPE_missive:read"),
new SimpleGrantedAuthority("SCOPE_missive:write"));
// @formatter:on
}
@Test
public void convertWhenTokenHasEmptyScopeAndNonEmptyScpThenScopeAttributeIsTranslatedToNoAuthorities() {
Jwt jwt = TestJwts.jwt().claim("scp", Arrays.asList("message:read", "message:write")).claim("scope", "")
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("scp", Arrays.asList("message:read", "message:write"))
.claim("scope", "")
.build();
// @formatter:on
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block();
Collection<GrantedAuthority> authorities = authentication.getAuthorities();
assertThat(authorities).containsExactly();

View File

@ -51,8 +51,11 @@ public class ReactiveJwtGrantedAuthoritiesConverterAdapterTests {
@Test
public void whenConstructingWithInvalidConverter() {
assertThatIllegalArgumentException().isThrownBy(() -> new ReactiveJwtGrantedAuthoritiesConverterAdapter(null))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new ReactiveJwtGrantedAuthoritiesConverterAdapter(null))
.withMessage("grantedAuthoritiesConverter cannot be null");
// @formatter:on
}
}

View File

@ -62,31 +62,62 @@ public class NimbusOpaqueTokenIntrospectorTests {
private static final String CLIENT_SECRET = "secret";
private static final String ACTIVE_RESPONSE = "{\n" + " \"active\": true,\n"
+ " \"client_id\": \"l238j323ds-23ij4\",\n" + " \"username\": \"jdoe\",\n"
+ " \"scope\": \"read write dolphin\",\n" + " \"sub\": \"Z5O3upPC88QrAjx00dis\",\n"
+ " \"aud\": \"https://protected.example.net/resource\",\n"
+ " \"iss\": \"https://server.example.com/\",\n" + " \"exp\": 1419356238,\n"
+ " \"iat\": 1419350238,\n" + " \"extension_field\": \"twenty-seven\"\n" + " }";
private static final String INACTIVE_RESPONSE = "{\n" + " \"active\": false\n" + " }";
private static final String INVALID_RESPONSE = "{\n" + " \"client_id\": \"l238j323ds-23ij4\",\n"
+ " \"username\": \"jdoe\",\n" + " \"scope\": \"read write dolphin\",\n"
// @formatter:off
private static final String ACTIVE_RESPONSE = "{\n"
+ " \"active\": true,\n"
+ " \"client_id\": \"l238j323ds-23ij4\",\n"
+ " \"username\": \"jdoe\",\n"
+ " \"scope\": \"read write dolphin\",\n"
+ " \"sub\": \"Z5O3upPC88QrAjx00dis\",\n"
+ " \"aud\": \"https://protected.example.net/resource\",\n"
+ " \"iss\": \"https://server.example.com/\",\n" + " \"exp\": 1419356238,\n"
+ " \"iat\": 1419350238,\n" + " \"extension_field\": \"twenty-seven\"\n" + " }";
+ " \"iss\": \"https://server.example.com/\",\n"
+ " \"exp\": 1419356238,\n"
+ " \"iat\": 1419350238,\n"
+ " \"extension_field\": \"twenty-seven\"\n"
+ " }";
// @formatter:on
private static final String MALFORMED_ISSUER_RESPONSE = "{\n" + " \"active\" : \"true\",\n"
+ " \"iss\" : \"badissuer\"\n" + " }";
// @formatter:off
private static final String INACTIVE_RESPONSE = "{\n"
+ " \"active\": false\n"
+ " }";
// @formatter:on
private static final String MALFORMED_SCOPE_RESPONSE = "{\n" + " \"active\": true,\n"
+ " \"client_id\": \"l238j323ds-23ij4\",\n" + " \"username\": \"jdoe\",\n"
+ " \"scope\": [ \"read\", \"write\", \"dolphin\" ],\n" + " \"sub\": \"Z5O3upPC88QrAjx00dis\",\n"
// @formatter:off
private static final String INVALID_RESPONSE = "{\n"
+ " \"client_id\": \"l238j323ds-23ij4\",\n"
+ " \"username\": \"jdoe\",\n"
+ " \"scope\": \"read write dolphin\",\n"
+ " \"sub\": \"Z5O3upPC88QrAjx00dis\",\n"
+ " \"aud\": \"https://protected.example.net/resource\",\n"
+ " \"iss\": \"https://server.example.com/\",\n" + " \"exp\": 1419356238,\n"
+ " \"iat\": 1419350238,\n" + " \"extension_field\": \"twenty-seven\"\n" + " }";
+ " \"iss\": \"https://server.example.com/\",\n"
+ " \"exp\": 1419356238,\n"
+ " \"iat\": 1419350238,\n"
+ " \"extension_field\": \"twenty-seven\"\n"
+ " }";
// @formatter:on
// @formatter:off
private static final String MALFORMED_ISSUER_RESPONSE = "{\n"
+ " \"active\" : \"true\",\n"
+ " \"iss\" : \"badissuer\"\n"
+ " }";
// @formatter:on
// @formatter:off
private static final String MALFORMED_SCOPE_RESPONSE = "{\n"
+ " \"active\": true,\n"
+ " \"client_id\": \"l238j323ds-23ij4\",\n"
+ " \"username\": \"jdoe\",\n"
+ " \"scope\": [ \"read\", \"write\", \"dolphin\" ],\n"
+ " \"sub\": \"Z5O3upPC88QrAjx00dis\",\n"
+ " \"aud\": \"https://protected.example.net/resource\",\n"
+ " \"iss\": \"https://server.example.com/\",\n"
+ " \"exp\": 1419356238,\n"
+ " \"iat\": 1419350238,\n"
+ " \"extension_field\": \"twenty-seven\"\n"
+ " }";
// @formatter:on
private static final ResponseEntity<String> ACTIVE = response(ACTIVE_RESPONSE);
@ -106,7 +137,10 @@ public class NimbusOpaqueTokenIntrospectorTests {
OpaqueTokenIntrospector introspectionClient = new NimbusOpaqueTokenIntrospector(introspectUri, CLIENT_ID,
CLIENT_SECRET);
OAuth2AuthenticatedPrincipal authority = introspectionClient.introspect("token");
assertThat(authority.getAttributes()).isNotNull().containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
// @formatter:off
assertThat(authority.getAttributes())
.isNotNull()
.containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
.containsEntry(OAuth2IntrospectionClaimNames.AUDIENCE,
Arrays.asList("https://protected.example.net/resource"))
.containsEntry(OAuth2IntrospectionClaimNames.CLIENT_ID, "l238j323ds-23ij4")
@ -116,6 +150,7 @@ public class NimbusOpaqueTokenIntrospectorTests {
.containsEntry(OAuth2IntrospectionClaimNames.SUBJECT, "Z5O3upPC88QrAjx00dis")
.containsEntry(OAuth2IntrospectionClaimNames.USERNAME, "jdoe")
.containsEntry("extension_field", "twenty-seven");
// @formatter:on
}
}
@ -137,8 +172,11 @@ public class NimbusOpaqueTokenIntrospectorTests {
OpaqueTokenIntrospector introspectionClient = new NimbusOpaqueTokenIntrospector(INTROSPECTION_URL,
restOperations);
given(restOperations.exchange(any(RequestEntity.class), eq(String.class))).willReturn(INACTIVE);
// @formatter:off
assertThatExceptionOfType(OAuth2IntrospectionException.class)
.isThrownBy(() -> introspectionClient.introspect("token")).withMessage("Provided token isn't active");
.isThrownBy(() -> introspectionClient.introspect("token"))
.withMessage("Provided token isn't active");
// @formatter:on
}
@Test
@ -153,11 +191,15 @@ public class NimbusOpaqueTokenIntrospectorTests {
given(restOperations.exchange(any(RequestEntity.class), eq(String.class)))
.willReturn(response(new JSONObject(introspectedValues).toJSONString()));
OAuth2AuthenticatedPrincipal authority = introspectionClient.introspect("token");
assertThat(authority.getAttributes()).isNotNull().containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
// @formatter:off
assertThat(authority.getAttributes())
.isNotNull()
.containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
.containsEntry(OAuth2IntrospectionClaimNames.AUDIENCE, Arrays.asList("aud"))
.containsEntry(OAuth2IntrospectionClaimNames.NOT_BEFORE, Instant.ofEpochSecond(29348723984L))
.doesNotContainKey(OAuth2IntrospectionClaimNames.CLIENT_ID)
.doesNotContainKey(OAuth2IntrospectionClaimNames.SCOPE);
// @formatter:on
}
@Test
@ -167,8 +209,11 @@ public class NimbusOpaqueTokenIntrospectorTests {
restOperations);
given(restOperations.exchange(any(RequestEntity.class), eq(String.class)))
.willThrow(new IllegalStateException("server was unresponsive"));
// @formatter:off
assertThatExceptionOfType(OAuth2IntrospectionException.class)
.isThrownBy(() -> introspectionClient.introspect("token")).withMessage("server was unresponsive");
.isThrownBy(() -> introspectionClient.introspect("token"))
.withMessage("server was unresponsive");
// @formatter:on
}
@Test
@ -274,8 +319,12 @@ public class NimbusOpaqueTokenIntrospectorTests {
@Override
public MockResponse dispatch(RecordedRequest request) {
String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);
return Optional.ofNullable(authorization).filter((a) -> isAuthorized(authorization, username, password))
.map((a) -> ok(response)).orElse(unauthorized());
// @formatter:off
return Optional.ofNullable(authorization)
.filter((a) -> isAuthorized(authorization, username, password))
.map((a) -> ok(response))
.orElse(unauthorized());
// @formatter:on
}
};
}
@ -286,8 +335,10 @@ public class NimbusOpaqueTokenIntrospectorTests {
}
private static MockResponse ok(String response) {
return new MockResponse().setBody(response).setHeader(HttpHeaders.CONTENT_TYPE,
MediaType.APPLICATION_JSON_VALUE);
// @formatter:off
return new MockResponse().setBody(response)
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
// @formatter:on
}
private static MockResponse unauthorized() {

View File

@ -58,24 +58,47 @@ public class NimbusReactiveOpaqueTokenIntrospectorTests {
private static final String CLIENT_SECRET = "secret";
private static final String ACTIVE_RESPONSE = "{\n" + " \"active\": true,\n"
+ " \"client_id\": \"l238j323ds-23ij4\",\n" + " \"username\": \"jdoe\",\n"
+ " \"scope\": \"read write dolphin\",\n" + " \"sub\": \"Z5O3upPC88QrAjx00dis\",\n"
+ " \"aud\": \"https://protected.example.net/resource\",\n"
+ " \"iss\": \"https://server.example.com/\",\n" + " \"exp\": 1419356238,\n"
+ " \"iat\": 1419350238,\n" + " \"extension_field\": \"twenty-seven\"\n" + " }";
private static final String INACTIVE_RESPONSE = "{\n" + " \"active\": false\n" + " }";
private static final String INVALID_RESPONSE = "{\n" + " \"client_id\": \"l238j323ds-23ij4\",\n"
+ " \"username\": \"jdoe\",\n" + " \"scope\": \"read write dolphin\",\n"
// @formatter:off
private static final String ACTIVE_RESPONSE = "{\n"
+ " \"active\": true,\n"
+ " \"client_id\": \"l238j323ds-23ij4\",\n"
+ " \"username\": \"jdoe\",\n"
+ " \"scope\": \"read write dolphin\",\n"
+ " \"sub\": \"Z5O3upPC88QrAjx00dis\",\n"
+ " \"aud\": \"https://protected.example.net/resource\",\n"
+ " \"iss\": \"https://server.example.com/\",\n" + " \"exp\": 1419356238,\n"
+ " \"iat\": 1419350238,\n" + " \"extension_field\": \"twenty-seven\"\n" + " }";
+ " \"iss\": \"https://server.example.com/\",\n"
+ " \"exp\": 1419356238,\n"
+ " \"iat\": 1419350238,\n"
+ " \"extension_field\": \"twenty-seven\"\n"
+ " }";
// @formatter:on
private static final String MALFORMED_ISSUER_RESPONSE = "{\n" + " \"active\" : \"true\",\n"
+ " \"iss\" : \"badissuer\"\n" + " }";
// @formatter:off
private static final String INACTIVE_RESPONSE = "{\n"
+ " \"active\": false\n"
+ " }";
// @formatter:on
// @formatter:off
private static final String INVALID_RESPONSE = "{\n"
+ " \"client_id\": \"l238j323ds-23ij4\",\n"
+ " \"username\": \"jdoe\",\n"
+ " \"scope\": \"read write dolphin\",\n"
+ " \"sub\": \"Z5O3upPC88QrAjx00dis\",\n"
+ " \"aud\": \"https://protected.example.net/resource\",\n"
+ " \"iss\": \"https://server.example.com/\",\n"
+ " \"exp\": 1419356238,\n"
+ " \"iat\": 1419350238,\n"
+ " \"extension_field\": \"twenty-seven\"\n"
+ " }";
// @formatter:on
// @formatter:off
private static final String MALFORMED_ISSUER_RESPONSE = "{\n"
+ " \"active\" : \"true\",\n"
+ " \"iss\" : \"badissuer\"\n"
+ " }";
// @formatter:on
@Test
public void authenticateWhenActiveTokenThenOk() throws Exception {
@ -85,7 +108,10 @@ public class NimbusReactiveOpaqueTokenIntrospectorTests {
NimbusReactiveOpaqueTokenIntrospector introspectionClient = new NimbusReactiveOpaqueTokenIntrospector(
introspectUri, CLIENT_ID, CLIENT_SECRET);
OAuth2AuthenticatedPrincipal authority = introspectionClient.introspect("token").block();
assertThat(authority.getAttributes()).isNotNull().containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
// @formatter:off
assertThat(authority.getAttributes())
.isNotNull()
.containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
.containsEntry(OAuth2IntrospectionClaimNames.AUDIENCE,
Arrays.asList("https://protected.example.net/resource"))
.containsEntry(OAuth2IntrospectionClaimNames.CLIENT_ID, "l238j323ds-23ij4")
@ -95,6 +121,7 @@ public class NimbusReactiveOpaqueTokenIntrospectorTests {
.containsEntry(OAuth2IntrospectionClaimNames.SUBJECT, "Z5O3upPC88QrAjx00dis")
.containsEntry(OAuth2IntrospectionClaimNames.USERNAME, "jdoe")
.containsEntry("extension_field", "twenty-seven");
// @formatter:on
}
}
@ -131,11 +158,15 @@ public class NimbusReactiveOpaqueTokenIntrospectorTests {
NimbusReactiveOpaqueTokenIntrospector introspectionClient = new NimbusReactiveOpaqueTokenIntrospector(
INTROSPECTION_URL, webClient);
OAuth2AuthenticatedPrincipal authority = introspectionClient.introspect("token").block();
assertThat(authority.getAttributes()).isNotNull().containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
// @formatter:off
assertThat(authority.getAttributes())
.isNotNull()
.containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
.containsEntry(OAuth2IntrospectionClaimNames.AUDIENCE, Arrays.asList("aud"))
.containsEntry(OAuth2IntrospectionClaimNames.NOT_BEFORE, Instant.ofEpochSecond(29348723984L))
.doesNotContainKey(OAuth2IntrospectionClaimNames.CLIENT_ID)
.doesNotContainKey(OAuth2IntrospectionClaimNames.SCOPE);
// @formatter:on
}
@Test
@ -143,9 +174,11 @@ public class NimbusReactiveOpaqueTokenIntrospectorTests {
WebClient webClient = mockResponse(new IllegalStateException("server was unresponsive"));
NimbusReactiveOpaqueTokenIntrospector introspectionClient = new NimbusReactiveOpaqueTokenIntrospector(
INTROSPECTION_URL, webClient);
// @formatter:off
assertThatExceptionOfType(OAuth2IntrospectionException.class)
.isThrownBy(() -> introspectionClient.introspect("token").block())
.withMessage("server was unresponsive");
// @formatter:on
}
@Test
@ -162,8 +195,10 @@ public class NimbusReactiveOpaqueTokenIntrospectorTests {
WebClient webClient = mockResponse(INVALID_RESPONSE);
NimbusReactiveOpaqueTokenIntrospector introspectionClient = new NimbusReactiveOpaqueTokenIntrospector(
INTROSPECTION_URL, webClient);
// @formatter:off
assertThatExceptionOfType(OAuth2IntrospectionException.class)
.isThrownBy(() -> introspectionClient.introspect("token").block());
// @formatter:on
}
@Test
@ -229,8 +264,12 @@ public class NimbusReactiveOpaqueTokenIntrospectorTests {
@Override
public MockResponse dispatch(RecordedRequest request) {
String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);
return Optional.ofNullable(authorization).filter((a) -> isAuthorized(authorization, username, password))
.map((a) -> ok(response)).orElse(unauthorized());
// @formatter:off
return Optional.ofNullable(authorization)
.filter((a) -> isAuthorized(authorization, username, password))
.map((a) -> ok(response))
.orElse(unauthorized());
// @formatter:on
}
};
}
@ -241,8 +280,10 @@ public class NimbusReactiveOpaqueTokenIntrospectorTests {
}
private static MockResponse ok(String response) {
return new MockResponse().setBody(response).setHeader(HttpHeaders.CONTENT_TYPE,
MediaType.APPLICATION_JSON_VALUE);
// @formatter:off
return new MockResponse().setBody(response)
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
// @formatter:on
}
private static MockResponse unauthorized() {

View File

@ -157,29 +157,39 @@ public class BearerTokenAuthenticationFilterTests {
@Test
public void setAuthenticationEntryPointWhenNullThenThrowsException() {
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);
assertThatIllegalArgumentException().isThrownBy(() -> filter.setAuthenticationEntryPoint(null))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> filter.setAuthenticationEntryPoint(null))
.withMessageContaining("authenticationEntryPoint cannot be null");
// @formatter:on
}
@Test
public void setBearerTokenResolverWhenNullThenThrowsException() {
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);
assertThatIllegalArgumentException().isThrownBy(() -> filter.setBearerTokenResolver(null))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> filter.setBearerTokenResolver(null))
.withMessageContaining("bearerTokenResolver cannot be null");
// @formatter:on
}
@Test
public void constructorWhenNullAuthenticationManagerThenThrowsException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenAuthenticationFilter((AuthenticationManager) null))
.withMessageContaining("authenticationManager cannot be null");
// @formatter:on
}
@Test
public void constructorWhenNullAuthenticationManagerResolverThenThrowsException() {
assertThatIllegalArgumentException().isThrownBy(
() -> new BearerTokenAuthenticationFilter((AuthenticationManagerResolver<HttpServletRequest>) null))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new BearerTokenAuthenticationFilter((AuthenticationManagerResolver<HttpServletRequest>) null))
.withMessageContaining("authenticationManagerResolver cannot be null");
// @formatter:on
}
private BearerTokenAuthenticationFilter addMocks(BearerTokenAuthenticationFilter filter) {

View File

@ -38,14 +38,20 @@ public class HeaderBearerTokenResolverTests {
@Test
public void constructorWhenHeaderNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> new HeaderBearerTokenResolver(null))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new HeaderBearerTokenResolver(null))
.withMessage("header cannot be empty");
// @formatter:on
}
@Test
public void constructorWhenHeaderEmptyThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> new HeaderBearerTokenResolver(""))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new HeaderBearerTokenResolver(""))
.withMessage("header cannot be empty");
// @formatter:on
}
@Test

View File

@ -77,9 +77,12 @@ public class BearerTokenAccessDeniedHandlerTests {
request.setUserPrincipal(token);
this.accessDeniedHandler.handle(request, response, null);
assertThat(response.getStatus()).isEqualTo(403);
assertThat(response.getHeader("WWW-Authenticate")).isEqualTo("Bearer error=\"insufficient_scope\", "
+ "error_description=\"The request requires higher privileges than provided by the access token.\", "
+ "error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"");
// @formatter:off
assertThat(response.getHeader("WWW-Authenticate"))
.isEqualTo("Bearer error=\"insufficient_scope\", "
+ "error_description=\"The request requires higher privileges than provided by the access token.\", "
+ "error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"");
// @formatter:on
}
@Test

View File

@ -77,10 +77,12 @@ public class BearerTokenServerAccessDeniedHandlerTests {
given(exchange.getResponse()).willReturn(new MockServerHttpResponse());
this.accessDeniedHandler.handle(exchange, null).block();
assertThat(exchange.getResponse().getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
// @formatter:off
assertThat(exchange.getResponse().getHeaders().get("WWW-Authenticate"))
.isEqualTo(Arrays.asList("Bearer error=\"insufficient_scope\", "
+ "error_description=\"The request requires higher privileges than provided by the access token.\", "
+ "error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\""));
// @formatter:on
}
@Test

View File

@ -52,8 +52,10 @@ public class ServerBearerTokenAuthenticationConverterTests {
@Test
public void resolveWhenValidHeaderIsPresentThenTokenIsResolved() {
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/").header(HttpHeaders.AUTHORIZATION,
"Bearer " + TEST_TOKEN);
// @formatter:off
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
.header(HttpHeaders.AUTHORIZATION, "Bearer " + TEST_TOKEN);
// @formatter:on
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
}
@ -61,16 +63,20 @@ public class ServerBearerTokenAuthenticationConverterTests {
@Test
public void resolveWhenHeaderEndsWithPaddingIndicatorThenTokenIsResolved() {
String token = TEST_TOKEN + "==";
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/").header(HttpHeaders.AUTHORIZATION,
"Bearer " + token);
// @formatter:off
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
.header(HttpHeaders.AUTHORIZATION, "Bearer " + token);
// @formatter:on
assertThat(convertToToken(request).getToken()).isEqualTo(token);
}
@Test
public void resolveWhenCustomDefinedHeaderIsValidAndPresentThenTokenIsResolved() {
this.converter.setBearerTokenHeaderName(CUSTOM_HEADER);
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/").header(CUSTOM_HEADER,
"Bearer " + TEST_TOKEN);
// @formatter:off
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
.header(CUSTOM_HEADER, "Bearer " + TEST_TOKEN);
// @formatter:on
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
}
@ -79,19 +85,24 @@ public class ServerBearerTokenAuthenticationConverterTests {
public void resolveWhenValidHeaderIsEmptyStringThenTokenIsResolved() {
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/").header(HttpHeaders.AUTHORIZATION,
"Bearer ");
assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> convertToToken(request))
// @formatter:off
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> convertToToken(request))
.satisfies((ex) -> {
BearerTokenError error = (BearerTokenError) ex.getError();
assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_TOKEN);
assertThat(error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6750#section-3.1");
assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.UNAUTHORIZED);
});
// @formatter:on
}
@Test
public void resolveWhenLowercaseHeaderIsPresentThenTokenIsResolved() {
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/").header(HttpHeaders.AUTHORIZATION,
"bearer " + TEST_TOKEN);
// @formatter:off
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
.header(HttpHeaders.AUTHORIZATION, "bearer " + TEST_TOKEN);
// @formatter:on
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
}
@ -103,48 +114,65 @@ public class ServerBearerTokenAuthenticationConverterTests {
@Test
public void resolveWhenHeaderWithWrongSchemeIsPresentThenTokenIsNotResolved() {
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/").header(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString("test:test".getBytes()));
// @formatter:off
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
.header(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString("test:test".getBytes()));
// @formatter:on
assertThat(convertToToken(request)).isNull();
}
@Test
public void resolveWhenHeaderWithMissingTokenIsPresentThenAuthenticationExceptionIsThrown() {
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/").header(HttpHeaders.AUTHORIZATION,
"Bearer ");
assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> convertToToken(request))
// @formatter:off
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
.header(HttpHeaders.AUTHORIZATION, "Bearer ");
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> convertToToken(request))
.withMessageContaining(("Bearer token is malformed"));
// @formatter:on
}
@Test
public void resolveWhenHeaderWithInvalidCharactersIsPresentThenAuthenticationExceptionIsThrown() {
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/").header(HttpHeaders.AUTHORIZATION,
"Bearer an\"invalid\"token");
assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> convertToToken(request))
// @formatter:off
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
.header(HttpHeaders.AUTHORIZATION, "Bearer an\"invalid\"token");
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> convertToToken(request))
.withMessageContaining(("Bearer token is malformed"));
// @formatter:on
}
// gh-8865
@Test
public void resolveWhenHeaderWithInvalidCharactersIsPresentAndNotSubscribedThenNoneExceptionIsThrown() {
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/").header(HttpHeaders.AUTHORIZATION,
"Bearer an\"invalid\"token");
// @formatter:off
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
.header(HttpHeaders.AUTHORIZATION, "Bearer an\"invalid\"token");
// @formatter:on
this.converter.convert(MockServerWebExchange.from(request));
}
@Test
public void resolveWhenValidHeaderIsPresentTogetherWithQueryParameterThenAuthenticationExceptionIsThrown() {
// @formatter:off
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
.queryParam("access_token", TEST_TOKEN).header(HttpHeaders.AUTHORIZATION, "Bearer " + TEST_TOKEN);
assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> convertToToken(request))
.queryParam("access_token", TEST_TOKEN)
.header(HttpHeaders.AUTHORIZATION, "Bearer " + TEST_TOKEN);
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> convertToToken(request))
.withMessageContaining("Found multiple bearer tokens in the request");
// @formatter:on
}
@Test
public void resolveWhenQueryParameterIsPresentAndSupportedThenTokenIsResolved() {
this.converter.setAllowUriQueryParameter(true);
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/").queryParam("access_token",
TEST_TOKEN);
// @formatter:off
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
.queryParam("access_token", TEST_TOKEN);
// @formatter:on
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
}
@ -152,20 +180,26 @@ public class ServerBearerTokenAuthenticationConverterTests {
@Test
public void resolveWhenQueryParameterIsEmptyAndSupportedThenOAuth2AuthenticationException() {
this.converter.setAllowUriQueryParameter(true);
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/").queryParam("access_token", "");
assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> convertToToken(request))
// @formatter:off
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
.queryParam("access_token", "");
assertThatExceptionOfType(OAuth2AuthenticationException.class)
.isThrownBy(() -> convertToToken(request))
.satisfies((ex) -> {
BearerTokenError error = (BearerTokenError) ex.getError();
assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_TOKEN);
assertThat(error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6750#section-3.1");
assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.UNAUTHORIZED);
});
// @formatter:on
}
@Test
public void resolveWhenQueryParameterIsPresentAndNotSupportedThenTokenIsNotResolved() {
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/").queryParam("access_token",
TEST_TOKEN);
// @formatter:off
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
.queryParam("access_token", TEST_TOKEN);
// @formatter:on
assertThat(convertToToken(request)).isNull();
}
@ -175,7 +209,11 @@ public class ServerBearerTokenAuthenticationConverterTests {
private BearerTokenAuthenticationToken convertToToken(MockServerHttpRequest request) {
MockServerWebExchange exchange = MockServerWebExchange.from(request);
return this.converter.convert(exchange).cast(BearerTokenAuthenticationToken.class).block();
// @formatter:off
return this.converter.convert(exchange)
.cast(BearerTokenAuthenticationToken.class)
.block();
// @formatter:on
}
}