/** * Build the configured {@link JwtDecoder}. * * @return the configured {@link JwtDecoder} */ public JWTProcessor<SecurityContext> build() { ResourceRetriever jwkSetRetriever = new RestOperationsResourceRetriever(this.restOperations); JWKSource<SecurityContext> jwkSource = new RemoteJWKSet<>(toURL(this.jwkSetUri), jwkSetRetriever); JWSKeySelector<SecurityContext> jwsKeySelector = new JWSVerificationKeySelector<>(this.jwsAlgorithm, jwkSource); ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>(); jwtProcessor.setJWSKeySelector(jwsKeySelector); // Spring Security validates the claim set independent from Nimbus jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> { }); return jwtProcessor; }
private JWTClaimsSet createClaimsSet(JWT parsedToken, List<JWK> jwkList) { try { return this.jwtProcessor.process(parsedToken, new JWKContext(jwkList)); } catch (BadJOSEException | JOSEException e) { throw new JwtException("Failed to validate the token", e); } }
@Override public JWTClaimsSet process(SignedJWT signedJWT, SecurityContext context) throws BadJOSEException, JOSEException { try { return signedJWT.getJWTClaimsSet(); } catch (ParseException e) { // Payload not a JSON object throw new BadJWTException(e.getMessage(), e); } } }
/** * Build the configured {@link JWTProcessor}. *mzRC * @return the configured {@link JWTProcessor} */ public JWTProcessor<SecurityContext> build() { if (!JWSAlgorithm.Family.RSA.contains(this.jwsAlgorithm)) { throw new IllegalStateException("The provided key is of type RSA; " + "however the signature algorithm is of some other type: " + this.jwsAlgorithm + ". Please indicate one of RS256, RS384, or RS512."); } JWKSet jwkSet = new JWKSet(this.key); JWKSource<SecurityContext> jwkSource = new ImmutableJWKSet<>(jwkSet); JWSKeySelector<SecurityContext> jwsKeySelector = new JWSVerificationKeySelector<>(this.jwsAlgorithm, jwkSource); DefaultJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>(); jwtProcessor.setJWSKeySelector(jwsKeySelector); // Spring Security validates the claim set independent from Nimbus jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> { }); return jwtProcessor; } }
@Override public void verify(JWTClaimsSet claimsSet, SecurityContext ctx) throws BadJWTException { super.verify(claimsSet, ctx); final String issuer = claimsSet.getIssuer(); if (issuer == null || !issuer.contains("https://sts.windows.net/") && !issuer.contains("https://sts.chinacloudapi.cn/")) { throw new BadJWTException("Invalid token issuer"); } } });
public UserPrincipal buildUserPrincipal(String idToken) throws ParseException, JOSEException, BadJOSEException { final JWSObject jwsObject = JWSObject.parse(idToken); final ConfigurableJWTProcessor<SecurityContext> validator = getAadJwtTokenValidator(jwsObject.getHeader().getAlgorithm()); final JWTClaimsSet jwtClaimsSet = validator.process(idToken, null); final JWTClaimsSetVerifier<SecurityContext> verifier = validator.getJWTClaimsSetVerifier(); verifier.verify(jwtClaimsSet, null); return new UserPrincipal(jwsObject, jwtClaimsSet); }
public JWKSBasedJWTValidator() { /* Set up a JWT processor to parse the tokens and then check their signature and validity time window (bounded by the "iat", "nbf" and "exp" claims). */ this.jwtProcessor = new DefaultJWTProcessor<>(); }
@Override public void verify(final JWTClaimsSet claimsSet) throws BadJWTException { verify(claimsSet, null); }
@Override public JWTClaimsSet process(final PlainJWT plainJWT, final C context) throws BadJOSEException, JOSEException { verifyAndReturnClaims(plainJWT, context); // just check claims, no return throw PLAIN_JWT_REJECTED_EXCEPTION; }
@Override public JWTClaimsSet process(final String jwtString, final C context) throws ParseException, BadJOSEException, JOSEException { return process(JWTParser.parse(jwtString), context); }
private ConfigurableJWTProcessor<SecurityContext> getAadJwtTokenValidator(JWSAlgorithm jwsAlgorithm) { final ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>(); final JWSKeySelector<SecurityContext> keySelector = new JWSVerificationKeySelector<>(jwsAlgorithm, keySource); jwtProcessor.setJWSKeySelector(keySelector); jwtProcessor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier<SecurityContext>() { @Override public void verify(JWTClaimsSet claimsSet, SecurityContext ctx) throws BadJWTException { super.verify(claimsSet, ctx); final String issuer = claimsSet.getIssuer(); if (issuer == null || !issuer.contains("https://sts.windows.net/") && !issuer.contains("https://sts.chinacloudapi.cn/")) { throw new BadJWTException("Invalid token issuer"); } } }); return jwtProcessor; } }
/** * Constructs a {@code NimbusJwtDecoderJwkSupport} using the provided parameters. * * @param jwkSetUrl the JSON Web Key (JWK) Set {@code URL} */ public NimbusReactiveJwtDecoder(String jwkSetUrl) { Assert.hasText(jwkSetUrl, "jwkSetUrl cannot be empty"); String jwsAlgorithm = JwsAlgorithms.RS256; JWSAlgorithm algorithm = JWSAlgorithm.parse(jwsAlgorithm); JWKSource jwkSource = new JWKContextJWKSource(); JWSKeySelector<JWKContext> jwsKeySelector = new JWSVerificationKeySelector<>(algorithm, jwkSource); DefaultJWTProcessor<JWKContext> jwtProcessor = new DefaultJWTProcessor<>(); jwtProcessor.setJWSKeySelector(jwsKeySelector); jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {}); this.jwtProcessor = jwtProcessor; this.reactiveJwkSource = new ReactiveRemoteJWKSource(jwkSetUrl); this.jwkSelectorFactory = new JWKSelectorFactory(algorithm); }
@Override public void verify(JWTClaimsSet claimsSet, SecurityContext ctx) throws BadJWTException { super.verify(claimsSet, ctx); final String issuer = claimsSet.getIssuer(); if (issuer == null || !issuer.contains("https://sts.windows.net/") && !issuer.contains("https://sts.chinacloudapi.cn/")) { throw new BadJWTException("Invalid token issuer"); } } });
private Jwt createJwt(String token, JWT parsedJwt) { Jwt jwt; try { // Verify the signature JWTClaimsSet jwtClaimsSet = this.jwtProcessor.process(parsedJwt, null); 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); jwt = new Jwt(token, issuedAt, expiresAt, headers, claims); } catch (RemoteKeySourceException ex) { if (ex.getCause() instanceof ParseException) { throw new JwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, "Malformed Jwk set")); } else { throw new JwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, ex.getMessage()), ex); } } catch (Exception ex) { if (ex.getCause() instanceof ParseException) { throw new JwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, "Malformed payload")); } else { throw new JwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, ex.getMessage()), ex); } } return jwt; }
private ConfigurableJWTProcessor<SecurityContext> getAadJwtTokenValidator(JWSAlgorithm jwsAlgorithm) { final ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>(); final JWSKeySelector<SecurityContext> keySelector = new JWSVerificationKeySelector<>(jwsAlgorithm, keySource); jwtProcessor.setJWSKeySelector(keySelector); jwtProcessor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier<SecurityContext>() { @Override public void verify(JWTClaimsSet claimsSet, SecurityContext ctx) throws BadJWTException { super.verify(claimsSet, ctx); final String issuer = claimsSet.getIssuer(); if (issuer == null || !issuer.contains("https://sts.windows.net/") && !issuer.contains("https://sts.chinacloudapi.cn/")) { throw new BadJWTException("Invalid token issuer"); } } }); return jwtProcessor; } }
public NimbusReactiveJwtDecoder(RSAPublicKey publicKey) { JWSAlgorithm algorithm = JWSAlgorithm.parse(JwsAlgorithms.RS256); RSAKey rsaKey = rsaKey(publicKey); JWKSet jwkSet = new JWKSet(rsaKey); JWKSource jwkSource = new ImmutableJWKSet<>(jwkSet); JWSKeySelector<JWKContext> jwsKeySelector = new JWSVerificationKeySelector<>(algorithm, jwkSource); DefaultJWTProcessor jwtProcessor = new DefaultJWTProcessor<>(); jwtProcessor.setJWSKeySelector(jwsKeySelector); jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {}); this.jwtProcessor = jwtProcessor; this.reactiveJwkSource = new ReactiveJWKSourceAdapter(jwkSource); this.jwkSelectorFactory = new JWKSelectorFactory(algorithm); }
@Test public void processWhenUsingPublicKeyThenSuccessfullyDecodes() throws Exception { JWTProcessor<SecurityContext> processor = JwtProcessors.withPublicKey(key()).build(); assertThat(processor.process(RS256_SIGNED_JWT, null)) .extracting(JWTClaimsSet::getSubject) .isEqualTo("test-subject"); }
@Test public void processWhenUsingPublicKeyWithRs512ThenSuccessfullyDecodes() throws Exception { JWTProcessor<SecurityContext> processor = JwtProcessors .withPublicKey(key()).jwsAlgorithm(JwsAlgorithms.RS512).build(); assertThat(processor.process(RS512_SIGNED_JWT, null)) .extracting(JWTClaimsSet::getSubject) .isEqualTo("test-subject"); }
@Test public void processWhenSignedThenOk() throws Exception { RestOperations restOperations = mockJwkSetResponse(JWK_SET); JWTProcessor<SecurityContext> processor = withJwkSetUri(JWK_SET_URI).restOperations(restOperations).build(); assertThat(processor.process(RS256_SIGNED_JWT, null)) .extracting(JWTClaimsSet::getExpirationTime) .isNotNull(); verify(restOperations).exchange(any(RequestEntity.class), eq(String.class)); }
@Test public void processWhenSignatureMismatchesAlgorithmThenThrowsException() throws Exception { JWTProcessor<SecurityContext> processor = JwtProcessors .withPublicKey(key()).jwsAlgorithm(JwsAlgorithms.RS512).build(); assertThatCode(() -> processor.process(RS256_SIGNED_JWT, null)) .isInstanceOf(BadJOSEException.class); }