@Test public void constructorWhenParametersProvidedAndValidThenCreated() { Jwt jwt = new Jwt(JWT_TOKEN_VALUE, Instant.ofEpochMilli(IAT_VALUE), Instant.ofEpochMilli(EXP_VALUE), HEADERS, CLAIMS); assertThat(jwt.getTokenValue()).isEqualTo(JWT_TOKEN_VALUE); assertThat(jwt.getHeaders()).isEqualTo(HEADERS); assertThat(jwt.getClaims()).isEqualTo(CLAIMS); assertThat(jwt.getIssuer().toString()).isEqualTo(ISS_VALUE); assertThat(jwt.getSubject()).isEqualTo(SUB_VALUE); assertThat(jwt.getAudience()).isEqualTo(AUD_VALUE); assertThat(jwt.getExpiresAt().toEpochMilli()).isEqualTo(EXP_VALUE); assertThat(jwt.getNotBefore().getEpochSecond()).isEqualTo(NBF_VALUE); assertThat(jwt.getIssuedAt().toEpochMilli()).isEqualTo(IAT_VALUE); assertThat(jwt.getId()).isEqualTo(JTI_VALUE); } }
if (!idToken.getAudience().contains(this.clientRegistration.getClientId())) { invalidClaims.put(IdTokenClaimNames.AUD, idToken.getAudience()); String authorizedParty = idToken.getClaimAsString(IdTokenClaimNames.AZP); if (idToken.getAudience().size() > 1 && authorizedParty == null) { invalidClaims.put(IdTokenClaimNames.AZP, authorizedParty); if (now.minus(this.clockSkew).isAfter(idToken.getExpiresAt())) { invalidClaims.put(IdTokenClaimNames.EXP, idToken.getExpiresAt()); if (now.plus(this.clockSkew).isBefore(idToken.getIssuedAt())) { invalidClaims.put(IdTokenClaimNames.IAT, idToken.getIssuedAt());
private static Map<String, Object> validateRequiredClaims(Jwt idToken) { Map<String, Object> requiredClaims = new HashMap<>(); URL issuer = idToken.getIssuer(); if (issuer == null) { requiredClaims.put(IdTokenClaimNames.ISS, issuer); } String subject = idToken.getSubject(); if (subject == null) { requiredClaims.put(IdTokenClaimNames.SUB, subject); } List<String> audience = idToken.getAudience(); if (CollectionUtils.isEmpty(audience)) { requiredClaims.put(IdTokenClaimNames.AUD, audience); } Instant expiresAt = idToken.getExpiresAt(); if (expiresAt == null) { requiredClaims.put(IdTokenClaimNames.EXP, expiresAt); } Instant issuedAt = idToken.getIssuedAt(); if (issuedAt == null) { requiredClaims.put(IdTokenClaimNames.IAT, issuedAt); } return requiredClaims; } }
private Mono<OidcIdToken> createOidcToken(ClientRegistration clientRegistration, OAuth2AccessTokenResponse accessTokenResponse) { ReactiveJwtDecoder jwtDecoder = this.jwtDecoderFactory.createDecoder(clientRegistration); String rawIdToken = (String) accessTokenResponse.getAdditionalParameters().get(OidcParameterNames.ID_TOKEN); return jwtDecoder.decode(rawIdToken) .map(jwt -> new OidcIdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims())); } }
/** * {@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(); }
private Jwt createJwt(JWT parsedJwt, JWTClaimsSet jwtClaimsSet) { Map<String, Object> headers = new LinkedHashMap<>(parsedJwt.getHeader().toJSONObject()); Map<String, Object> claims = this.claimSetConverter.convert(jwtClaimsSet.getClaims()); Instant expiresAt = (Instant) claims.get(JwtClaimNames.EXP); Instant issuedAt = (Instant) claims.get(JwtClaimNames.IAT); return new Jwt(parsedJwt.getParsedString(), issuedAt, expiresAt, headers, claims); }
/** * {@inheritDoc} */ @Override public Map<String, Object> getTokenAttributes() { return this.getToken().getClaims(); }
@RequestMapping("/topsecret") public String secured() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null && authentication.getPrincipal() instanceof Jwt) { Jwt jwt = (Jwt) authentication.getPrincipal(); return String.format("You are [%s] with e-mail address [%s].%n", jwt.getSubject(), jwt.getClaimAsString("email")); } else { return "Something went wrong; authentication is not provided by IAP/JWT.\n"; } }
/** * The {@link Jwt}'s subject, if any */ @Override public String getName() { return this.getToken().getSubject(); } }
@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); } }
/** * {@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); } } }
private OidcIdToken createOidcToken(ClientRegistration clientRegistration, OAuth2AccessTokenResponse accessTokenResponse) { JwtDecoder jwtDecoder = this.jwtDecoderFactory.createDecoder(clientRegistration); Jwt jwt; try { jwt = jwtDecoder.decode((String) accessTokenResponse.getAdditionalParameters().get(OidcParameterNames.ID_TOKEN)); } catch (JwtException ex) { OAuth2Error invalidIdTokenError = new OAuth2Error(INVALID_ID_TOKEN_ERROR_CODE, ex.getMessage(), null); throw new OAuth2AuthenticationException(invalidIdTokenError, invalidIdTokenError.toString(), ex); } OidcIdToken idToken = new OidcIdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims()); return idToken; } }
private Jwt jwt(Map<String, Object> claims) { Map<String, Object> headers = new HashMap<>(); headers.put("alg", JwsAlgorithms.RS256); return new Jwt("token", Instant.now(), Instant.now().plusSeconds(3600), headers, claims); } }
/** * Gets the scopes from a {@link Jwt} token * @param jwt The {@link Jwt} token * @return The scopes from the token */ private Collection<String> getScopes(Jwt jwt) { for ( String attributeName : WELL_KNOWN_SCOPE_ATTRIBUTE_NAMES ) { Object scopes = jwt.getClaims().get(attributeName); if (scopes instanceof String) { if (StringUtils.hasText((String) scopes)) { return Arrays.asList(((String) scopes).split(" ")); } else { return Collections.emptyList(); } } else if (scopes instanceof Collection) { return (Collection<String>) scopes; } } return Collections.emptyList(); } }
/** * {@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(maxClockSkew).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(maxClockSkew).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(); }
/** * The {@link Jwt}'s subject, if any */ @Override public String getName() { return this.getToken().getSubject(); } }
@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); } }
/** * {@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); } } }
private Mono<OidcIdToken> createOidcToken(ClientRegistration clientRegistration, OAuth2AccessTokenResponse accessTokenResponse) { ReactiveJwtDecoder jwtDecoder = this.decoderFactory.apply(clientRegistration); String rawIdToken = (String) accessTokenResponse.getAdditionalParameters().get(OidcParameterNames.ID_TOKEN); return jwtDecoder.decode(rawIdToken) .map(jwt -> new OidcIdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims())) .doOnNext(idToken -> OidcTokenValidator.validateIdToken(idToken, clientRegistration)); }
private Jwt jwt(Map<String, Object> claims) { Map<String, Object> headers = new HashMap<>(); headers.put("alg", JwsAlgorithms.RS256); return new Jwt("token", Instant.now(), Instant.now().plusSeconds(3600), headers, claims); } }