/** * {@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); } } }
/** * 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(Collection<OAuth2Error> errors) { if (errors.isEmpty()) { return NO_ERRORS; } return new OAuth2TokenValidatorResult(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); } }
@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); }
/** * 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)); }
@Test public void validateWhenAllValidatorsSucceedThenReturnsSuccessfulResult() { OAuth2TokenValidator<AbstractOAuth2Token> firstSuccess = mock(OAuth2TokenValidator.class); OAuth2TokenValidator<AbstractOAuth2Token> secondSuccess = mock(OAuth2TokenValidator.class); when(firstSuccess.validate(any(AbstractOAuth2Token.class))) .thenReturn(OAuth2TokenValidatorResult.success()); when(secondSuccess.validate(any(AbstractOAuth2Token.class))) .thenReturn(OAuth2TokenValidatorResult.success()); DelegatingOAuth2TokenValidator<AbstractOAuth2Token> tokenValidator = new DelegatingOAuth2TokenValidator<>(Arrays.asList(firstSuccess, secondSuccess)); AbstractOAuth2Token token = mock(AbstractOAuth2Token.class); OAuth2TokenValidatorResult result = tokenValidator.validate(token); assertThat(result.hasErrors()).isFalse(); assertThat(result.getErrors()).isEmpty(); }
@Test public void validateWhenJwtIsTooEarlyThenErrorMessageIndicatesNotBeforeTime() { Instant oneHourFromNow = Instant.now().plusSeconds(3600); Jwt jwt = new Jwt( MOCK_TOKEN_VALUE, MOCK_ISSUED_AT, null, MOCK_HEADER, Collections.singletonMap(JwtClaimNames.NBF, oneHourFromNow)); JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); Collection<OAuth2Error> details = jwtValidator.validate(jwt).getErrors(); Collection<String> messages = details.stream().map(OAuth2Error::getDescription).collect(Collectors.toList()); assertThat(messages).contains("Jwt used before " + oneHourFromNow); }
@Test public void validateWhenIssuerMatchesThenReturnsSuccess() { Jwt jwt = new Jwt( MOCK_TOKEN, MOCK_ISSUED_AT, MOCK_EXPIRES_AT, MOCK_HEADERS, Collections.singletonMap("iss", ISSUER)); assertThat(this.validator.validate(jwt)) .isEqualTo(OAuth2TokenValidatorResult.success()); }
@Test public void validateWhenNoValidatorsConfiguredThenReturnsSuccessfulResult() { DelegatingOAuth2TokenValidator<AbstractOAuth2Token> tokenValidator = new DelegatingOAuth2TokenValidator<>(); AbstractOAuth2Token token = mock(AbstractOAuth2Token.class); assertThat(tokenValidator.validate(token).hasErrors()).isFalse(); }
@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"); }
/** * {@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); } }
private Jwt validateJwt(Jwt jwt){ OAuth2TokenValidatorResult result = this.jwtValidator.validate(jwt); if (result.hasErrors()) { String description = result.getErrors().iterator().next().getDescription(); throw new JwtValidationException( String.format(DECODING_ERROR_MESSAGE_TEMPLATE, description), result.getErrors()); } return jwt; } }
@Test public void validateWhenJwtHasNoIssuerThenReturnsError() { Jwt jwt = new Jwt( MOCK_TOKEN, MOCK_ISSUED_AT, MOCK_EXPIRES_AT, MOCK_HEADERS, Collections.singletonMap(JwtClaimNames.AUD, "https://aud")); OAuth2TokenValidatorResult result = this.validator.validate(jwt); assertThat(result.getErrors()).isNotEmpty(); }
@Test public void validateWhenIssuerMatchesAndIsNotAUriThenReturnsSuccess() { Jwt jwt = new Jwt( MOCK_TOKEN, MOCK_ISSUED_AT, MOCK_EXPIRES_AT, MOCK_HEADERS, Collections.singletonMap(JwtClaimNames.ISS, "issuer")); JwtIssuerValidator validator = new JwtIssuerValidator("issuer"); assertThat(validator.validate(jwt)) .isEqualTo(OAuth2TokenValidatorResult.success()); }
@Test public void validateWhenNotBeforeIsValidAndExpiryIsNotSpecifiedThenReturnsSuccessfulResult() { Jwt jwt = new Jwt( MOCK_TOKEN_VALUE, MOCK_ISSUED_AT, null, MOCK_HEADER, Collections.singletonMap(JwtClaimNames.NBF, Instant.MIN)); JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse(); }
/** * {@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(); }