/** * Construct a failure {@link OAuth2TokenValidatorResult} with the provided detail * * @param errors the list of errors * @return an {@link OAuth2TokenValidatorResult} with the errors specified */ public static OAuth2TokenValidatorResult failure(OAuth2Error... errors) { return failure(Arrays.asList(errors)); }
/** * {@inheritDoc} */ @Override public OAuth2TokenValidatorResult validate(T token) { Collection<OAuth2Error> errors = new ArrayList<>(); for ( OAuth2TokenValidator<T> validator : this.tokenValidators) { errors.addAll(validator.validate(token).getErrors()); } return OAuth2TokenValidatorResult.failure(errors); } }
/** * {@inheritDoc} */ @Override public OAuth2TokenValidatorResult validate(Jwt token) { Assert.notNull(token, "token cannot be null"); String tokenIssuer = token.getClaimAsString(JwtClaimNames.ISS); if (this.issuer.equals(tokenIssuer)) { return OAuth2TokenValidatorResult.success(); } else { return OAuth2TokenValidatorResult.failure(INVALID_ISSUER); } } }
/** * {@inheritDoc} */ @Override public OAuth2TokenValidatorResult validate(Jwt jwt) { Assert.notNull(jwt, "jwt cannot be null"); Instant expiry = jwt.getExpiresAt(); if (expiry != null) { if (Instant.now(this.clock).minus(clockSkew).isAfter(expiry)) { OAuth2Error error = new OAuth2Error( OAuth2ErrorCodes.INVALID_REQUEST, String.format("Jwt expired at %s", jwt.getExpiresAt()), "https://tools.ietf.org/html/rfc6750#section-3.1"); return OAuth2TokenValidatorResult.failure(error); } } Instant notBefore = jwt.getNotBefore(); if (notBefore != null) { if (Instant.now(this.clock).plus(clockSkew).isBefore(notBefore)) { OAuth2Error error = new OAuth2Error( OAuth2ErrorCodes.INVALID_REQUEST, String.format("Jwt used before %s", jwt.getNotBefore()), "https://tools.ietf.org/html/rfc6750#section-3.1"); return OAuth2TokenValidatorResult.failure(error); } } return OAuth2TokenValidatorResult.success(); }
@Test public void failureWhenInvokedWithDetailReturnsFailureResultIncludingDetail() { OAuth2TokenValidatorResult failure = OAuth2TokenValidatorResult.failure(DETAIL); assertThat(failure.hasErrors()).isTrue(); assertThat(failure.getErrors()).containsExactly(DETAIL); }
@Test public void failureWhenInvokedWithMultipleDetailsReturnsFailureResultIncludingAll() { OAuth2TokenValidatorResult failure = OAuth2TokenValidatorResult.failure(DETAIL, DETAIL); assertThat(failure.hasErrors()).isTrue(); assertThat(failure.getErrors()).containsExactly(DETAIL, DETAIL); } }
@Test public void decodeWhenUsingCustomValidatorThenValidatorIsInvoked() { OAuth2TokenValidator jwtValidator = mock(OAuth2TokenValidator.class); this.decoder.setJwtValidator(jwtValidator); OAuth2Error error = new OAuth2Error("mock-error", "mock-description", "mock-uri"); OAuth2TokenValidatorResult result = OAuth2TokenValidatorResult.failure(error); when(jwtValidator.validate(any(Jwt.class))).thenReturn(result); assertThatCode(() -> this.decoder.decode(this.messageReadToken).block()) .isInstanceOf(JwtException.class) .hasMessageContaining("mock-description"); }
@Test public void validateWhenMultipleValidatorsFailThenReturnsFailureResultContainingAllDetails() { OAuth2TokenValidator<AbstractOAuth2Token> firstFailure = mock(OAuth2TokenValidator.class); OAuth2TokenValidator<AbstractOAuth2Token> secondFailure = mock(OAuth2TokenValidator.class); OAuth2Error otherDetail = new OAuth2Error("another-error"); when(firstFailure.validate(any(AbstractOAuth2Token.class))) .thenReturn(OAuth2TokenValidatorResult.failure(DETAIL)); when(secondFailure.validate(any(AbstractOAuth2Token.class))) .thenReturn(OAuth2TokenValidatorResult.failure(otherDetail)); DelegatingOAuth2TokenValidator<AbstractOAuth2Token> tokenValidator = new DelegatingOAuth2TokenValidator<>(firstFailure, secondFailure); AbstractOAuth2Token token = mock(AbstractOAuth2Token.class); OAuth2TokenValidatorResult result = tokenValidator.validate(token); assertThat(result.hasErrors()).isTrue(); assertThat(result.getErrors()).containsExactly(DETAIL, otherDetail); }
@Test public void decodeWhenJwtFailsValidationThenReturnsCorrespondingErrorMessage() { OAuth2Error failure = new OAuth2Error("mock-error", "mock-description", "mock-uri"); OAuth2TokenValidator<Jwt> jwtValidator = mock(OAuth2TokenValidator.class); when(jwtValidator.validate(any(Jwt.class))) .thenReturn(OAuth2TokenValidatorResult.failure(failure)); this.jwtDecoder.setJwtValidator(jwtValidator); assertThatCode(() -> this.jwtDecoder.decode(SIGNED_JWT)) .isInstanceOf(JwtValidationException.class) .hasMessageContaining("mock-description"); }
@Test public void validateWhenAnyValidatorFailsThenReturnsFailureResultContainingDetailFromFailingValidator() { OAuth2TokenValidator<AbstractOAuth2Token> success = mock(OAuth2TokenValidator.class); OAuth2TokenValidator<AbstractOAuth2Token> failure = mock(OAuth2TokenValidator.class); when(success.validate(any(AbstractOAuth2Token.class))) .thenReturn(OAuth2TokenValidatorResult.success()); when(failure.validate(any(AbstractOAuth2Token.class))) .thenReturn(OAuth2TokenValidatorResult.failure(DETAIL)); DelegatingOAuth2TokenValidator<AbstractOAuth2Token> tokenValidator = new DelegatingOAuth2TokenValidator<>(Arrays.asList(success, failure)); AbstractOAuth2Token token = mock(AbstractOAuth2Token.class); OAuth2TokenValidatorResult result = tokenValidator.validate(token); assertThat(result.hasErrors()).isTrue(); assertThat(result.getErrors()).containsExactly(DETAIL); }
@Test public void decodeWhenJwtValidationHasTwoErrorsThenJwtExceptionMessageShowsFirstError() { OAuth2Error firstFailure = new OAuth2Error("mock-error", "mock-description", "mock-uri"); OAuth2Error secondFailure = new OAuth2Error("another-error", "another-description", "another-uri"); OAuth2TokenValidatorResult result = OAuth2TokenValidatorResult.failure(firstFailure, secondFailure); OAuth2TokenValidator<Jwt> jwtValidator = mock(OAuth2TokenValidator.class); when(jwtValidator.validate(any(Jwt.class))).thenReturn(result); this.jwtDecoder.setJwtValidator(jwtValidator); assertThatCode(() -> this.jwtDecoder.decode(SIGNED_JWT)) .isInstanceOf(JwtValidationException.class) .hasMessageContaining("mock-description") .hasFieldOrPropertyWithValue("errors", Arrays.asList(firstFailure, secondFailure)); }
@Test public void decodeWhenJwtFailsValidationThenReturnsCorrespondingErrorMessage() throws Exception { try ( MockWebServer server = new MockWebServer() ) { server.enqueue(new MockResponse().setBody(JWK_SET)); String jwkSetUrl = server.url("/.well-known/jwks.json").toString(); NimbusJwtDecoderJwkSupport decoder = new NimbusJwtDecoderJwkSupport(jwkSetUrl); OAuth2Error failure = new OAuth2Error("mock-error", "mock-description", "mock-uri"); OAuth2TokenValidator<Jwt> jwtValidator = mock(OAuth2TokenValidator.class); when(jwtValidator.validate(any(Jwt.class))).thenReturn(OAuth2TokenValidatorResult.failure(failure)); decoder.setJwtValidator(jwtValidator); assertThatCode(() -> decoder.decode(SIGNED_JWT)) .isInstanceOf(JwtValidationException.class) .hasMessageContaining("mock-description"); } }
@Test public void decodeWhenJwtValidationHasTwoErrorsThenJwtExceptionMessageShowsFirstError() throws Exception { try ( MockWebServer server = new MockWebServer() ) { server.enqueue(new MockResponse().setBody(JWK_SET)); String jwkSetUrl = server.url("/.well-known/jwks.json").toString(); NimbusJwtDecoderJwkSupport decoder = new NimbusJwtDecoderJwkSupport(jwkSetUrl); OAuth2Error firstFailure = new OAuth2Error("mock-error", "mock-description", "mock-uri"); OAuth2Error secondFailure = new OAuth2Error("another-error", "another-description", "another-uri"); OAuth2TokenValidatorResult result = OAuth2TokenValidatorResult.failure(firstFailure, secondFailure); OAuth2TokenValidator<Jwt> jwtValidator = mock(OAuth2TokenValidator.class); when(jwtValidator.validate(any(Jwt.class))).thenReturn(result); decoder.setJwtValidator(jwtValidator); assertThatCode(() -> decoder.decode(SIGNED_JWT)) .isInstanceOf(JwtValidationException.class) .hasMessageContaining("mock-description") .hasFieldOrPropertyWithValue("errors", Arrays.asList(firstFailure, secondFailure)); } }
@Test public void requestWhenCustomJwtValidatorFailsThenCorrespondingErrorMessage() throws Exception { this.spring.register(RestOperationsConfig.class, CustomJwtValidatorConfig.class).autowire(); mockRestOperations(jwks("Default")); String token = this.token("ValidNoScopes"); OAuth2TokenValidator<Jwt> jwtValidator = this.spring.getContext().getBean(CustomJwtValidatorConfig.class) .getJwtValidator(); OAuth2Error error = new OAuth2Error("custom-error", "custom-description", "custom-uri"); when(jwtValidator.validate(any(Jwt.class))).thenReturn(OAuth2TokenValidatorResult.failure(error)); this.mvc.perform(get("/") .with(bearerToken(token))) .andExpect(status().isUnauthorized()) .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("custom-description"))); }
/** * Construct a failure {@link OAuth2TokenValidatorResult} with the provided detail * * @param errors the list of errors * @return an {@link OAuth2TokenValidatorResult} with the errors specified */ public static OAuth2TokenValidatorResult failure(OAuth2Error... errors) { return failure(Arrays.asList(errors)); }
/** * Construct a failure {@link OAuth2TokenValidatorResult} with the provided detail * * @param errors the list of errors * @return an {@link OAuth2TokenValidatorResult} with the errors specified */ public static OAuth2TokenValidatorResult failure(OAuth2Error... errors) { return failure(Arrays.asList(errors)); }
/** * {@inheritDoc} */ @Override public OAuth2TokenValidatorResult validate(T token) { Collection<OAuth2Error> errors = new ArrayList<>(); for ( OAuth2TokenValidator<T> validator : this.tokenValidators) { errors.addAll(validator.validate(token).getErrors()); } return OAuth2TokenValidatorResult.failure(errors); } }
/** * {@inheritDoc} */ @Override public OAuth2TokenValidatorResult validate(T token) { Collection<OAuth2Error> errors = new ArrayList<>(); for ( OAuth2TokenValidator<T> validator : this.tokenValidators) { errors.addAll(validator.validate(token).getErrors()); } return OAuth2TokenValidatorResult.failure(errors); } }
@Override public OAuth2TokenValidatorResult validate(Jwt t) { if (t.getAudience() != null && t.getAudience().contains(this.audience)) { return OAuth2TokenValidatorResult.success(); } else { if (LOGGER.isWarnEnabled()) { LOGGER.warn(String.format( "Expected audience %s did not match token audience %s", this.audience, t.getAudience())); } return OAuth2TokenValidatorResult.failure(INVALID_AUDIENCE); } }