/** * 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; }
jwtProcessor.setJWTClaimsSetVerifier((claimsSet, context) -> { jwtProcessor.setJWSKeySelector(authContextKeySelector); jwtProcessor.process(signedJWT, null);
/** * Parses a token */ protected JWTClaimsSet parseToken(String token) { try { return jwtProcessor.process(token, null); } catch (ParseException | BadJOSEException | JOSEException e) { throw new BadCredentialsException(e.getMessage()); } } }
public NimbusJwtDecoderJwkSupport(String jwkSetUrl, String jwsAlgorithm) { Assert.hasText(jwkSetUrl, "jwkSetUrl cannot be empty"); Assert.hasText(jwsAlgorithm, "jwsAlgorithm cannot be empty"); try { this.jwkSetUrl = new URL(jwkSetUrl); } catch (MalformedURLException ex) { throw new IllegalArgumentException("Invalid JWK Set URL: " + ex.getMessage(), ex); } this.jwsAlgorithm = JWSAlgorithm.parse(jwsAlgorithm); ResourceRetriever jwkSetRetriever = new DefaultResourceRetriever(30000, 30000); JWKSource jwkSource = new RemoteJWKSet(this.jwkSetUrl, jwkSetRetriever); JWSKeySelector<SecurityContext> jwsKeySelector = new JWSVerificationKeySelector<SecurityContext>(this.jwsAlgorithm, jwkSource); this.jwtProcessor = new DefaultJWTProcessor<>(); this.jwtProcessor.setJWSKeySelector(jwsKeySelector); }
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 LemonJweService(String secret) throws KeyLengthException { byte[] secretKey = secret.getBytes(); encrypter = new DirectEncrypter(secretKey); jwtProcessor = new DefaultJWTProcessor<SimpleSecurityContext>(); // The JWE key source JWKSource<SimpleSecurityContext> jweKeySource = new ImmutableSecret<SimpleSecurityContext>(secretKey); // Configure a key selector to handle the decryption phase JWEKeySelector<SimpleSecurityContext> jweKeySelector = new JWEDecryptionKeySelector<SimpleSecurityContext>(JWEAlgorithm.DIR, EncryptionMethod.A128CBC_HS256, jweKeySource); jwtProcessor.setJWEKeySelector(jweKeySelector); }
@Override public JsonObject process(String jwt) throws JWTException { try { String rawJwt = delegate.process(jwt, null).toString(); return Json.createReader(new StringReader(rawJwt)).readObject(); } catch (ParseException | BadJOSEException | JOSEException e) { throw new JWTException("Unable to parse jwt", e); } }
@PostConstruct public void init() { try { JWKSource<SecurityContext> keySource = lookupJWKSource(); JWSAlgorithm expectedJWSAlg = jwtConfiguration.getAlgorithm(); JWSKeySelector<SecurityContext> keySelector = new JWSVerificationKeySelector<>(expectedJWSAlg, keySource); delegate.setJWSKeySelector(keySelector); } catch (IOException | ParseException e) { throw new JWTException("Unable to read JWT Configuration",e); } }
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); }
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; } }
jwtProcessor.process((PlainJWT)jwt, securityContext); } else if (jwt instanceof SignedJWT) { jwtProcessor.process((SignedJWT)jwt, securityContext); } else if (jwt instanceof EncryptedJWT) { jwtProcessor.process((EncryptedJWT)jwt, securityContext); } else { jwtProcessor.process(jwt, securityContext);
@Bean public ConfigurableJWTProcessor configurableJWTProcessor() throws MalformedURLException { ResourceRetriever resourceRetriever = new DefaultResourceRetriever(jwtConfiguration.getConnectionTimeout(), jwtConfiguration.getReadTimeout()); URL jwkSetURL = new URL(jwtConfiguration.getJwkUrl()); JWKSource keySource = new RemoteJWKSet(jwkSetURL, resourceRetriever); ConfigurableJWTProcessor jwtProcessor = new DefaultJWTProcessor(); JWSKeySelector keySelector = new JWSVerificationKeySelector(RS256, keySource); jwtProcessor.setJWSKeySelector(keySelector); return jwtProcessor; }
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 AuthenticationResult validate(String token) { try { JWTClaimsSet claimsSet = processor.process(token, null); return AuthenticationResult.valid(claimsSet.getClaims()); } catch(RemoteKeySourceException ex) { return AuthenticationResult.failed(ex.getMessage()); } catch (ParseException | JOSEException | BadJOSEException ex) { return AuthenticationResult.invalid(ex.getMessage()); } } }
private void setJWKeySelector(String jwksUri, String algorithm) throws MalformedURLException { /* The public RSA keys to validate the signatures will be sourced from the OAuth 2.0 server's JWK set, published at a well-known URL. The RemoteJWKSet object caches the retrieved keys to speed up subsequent look-ups and can also gracefully handle key-rollover. */ JWKSource<SecurityContext> keySource = JWKSourceDataProvider.getInstance().getJWKSource(jwksUri); // The expected JWS algorithm of the access tokens (agreed out-of-band). JWSAlgorithm expectedJWSAlg = JWSAlgorithm.parse(algorithm); /* Configure the JWT processor with a key selector to feed matching public RSA keys sourced from the JWK set URL. */ JWSKeySelector<SecurityContext> keySelector = new JWSVerificationKeySelector<>(expectedJWSAlg, keySource); jwtProcessor.setJWSKeySelector(keySelector); } }
/** * Constructs a {@code NimbusJwtDecoderJwkSupport} using the provided parameters. * * @param jwkSetUrl the JSON Web Key (JWK) Set {@code URL} * @param jwsAlgorithm the JSON Web Algorithm (JWA) used for verifying the digital signatures */ public NimbusJwtDecoderJwkSupport(String jwkSetUrl, String jwsAlgorithm) { Assert.hasText(jwkSetUrl, "jwkSetUrl cannot be empty"); Assert.hasText(jwsAlgorithm, "jwsAlgorithm cannot be empty"); JWKSource jwkSource; try { jwkSource = new RemoteJWKSet(new URL(jwkSetUrl), this.jwkSetRetriever); } catch (MalformedURLException ex) { throw new IllegalArgumentException("Invalid JWK Set URL \"" + jwkSetUrl + "\" : " + ex.getMessage(), ex); } this.jwsAlgorithm = JWSAlgorithm.parse(jwsAlgorithm); JWSKeySelector<SecurityContext> jwsKeySelector = new JWSVerificationKeySelector<>(this.jwsAlgorithm, jwkSource); this.jwtProcessor = new DefaultJWTProcessor<>(); this.jwtProcessor.setJWSKeySelector(jwsKeySelector); // Spring Security validates the claim set independent from Nimbus this.jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {}); }
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; }
jwtProcessor.setJWSKeySelector(keySelector); jwtProcessor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier<SecurityContext>() { @Override public void verify(JWTClaimsSet claimsSet, SecurityContext context)
public Authentication getAuthentication(HttpServletRequest request) throws Exception { String idToken = request.getHeader(jwtConfiguration.getHttpHeader()); if (idToken != null) { JWTClaimsSet claimsSet = null; claimsSet = configurableJWTProcessor.process(stripBearerToken(idToken), null); if (!isIssuedCorrectly(claimsSet)) { throw new Exception(String.format("Issuer %s in JWT token doesn't match cognito idp %s", claimsSet.getIssuer(), jwtConfiguration.getCognitoIdentityPoolUrl())); } if (!isIdToken(claimsSet)) { throw new Exception("JWT Token doesn't seem to be an ID Token"); } String username = claimsSet.getClaims().get(jwtConfiguration.getUserNameField()).toString(); if (username != null) { List<String> groups = (List<String>) claimsSet.getClaims().get(jwtConfiguration.getGroupsField()); List<GrantedAuthority> grantedAuthorities = convertList(groups, group -> new SimpleGrantedAuthority(ROLE_PREFIX + group.toUpperCase())); User user = new User(username, EMPTY_PWD, grantedAuthorities); jwtIdTokenCredentialsHolder.setIdToken(stripBearerToken(idToken)); return new JwtAuthentication(user, claimsSet, grantedAuthorities); } } logger.trace("No idToken found in HTTP Header"); return null; }
@Override public Jwt decode(String token) throws JwtException { Jwt jwt; try { JWT parsedJwt = JWTParser.parse(token); // Verify the signature JWTClaimsSet jwtClaimsSet = this.jwtProcessor.process(parsedJwt, null); Instant expiresAt = jwtClaimsSet.getExpirationTime().toInstant(); Instant issuedAt; if (jwtClaimsSet.getIssueTime() != null) { issuedAt = jwtClaimsSet.getIssueTime().toInstant(); } else { // issuedAt is required in SecurityToken so let's default to expiresAt - 1 second issuedAt = Instant.from(expiresAt).minusSeconds(1); } Map<String, Object> headers = new LinkedHashMap<>(parsedJwt.getHeader().toJSONObject()); jwt = new Jwt(token, issuedAt, expiresAt, headers, jwtClaimsSet.getClaims()); } catch (Exception ex) { throw new JwtException("An error occurred while attempting to decode the Jwt: " + ex.getMessage(), ex); } return jwt; } }