Search in sources :

Example 6 with UnsupportedJwtException

use of io.jsonwebtoken.UnsupportedJwtException in project jjwt by jwtk.

the class DefaultJwtParser method parse.

@Override
public Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException {
    // remove this block in v1.0 (the equivalent is already in DefaultJwtParserBuilder)
    if (this.deserializer == null) {
        // try to find one based on the services available
        // TODO: This util class will throw a UnavailableImplementationException here to retain behavior of previous version, remove in v1.0
        this.deserializeJsonWith(LegacyServices.loadFirst(Deserializer.class));
    }
    Assert.hasText(jwt, "JWT String argument cannot be null or empty.");
    if ("..".equals(jwt)) {
        String msg = "JWT string '..' is missing a header.";
        throw new MalformedJwtException(msg);
    }
    String base64UrlEncodedHeader = null;
    String base64UrlEncodedPayload = null;
    String base64UrlEncodedDigest = null;
    int delimiterCount = 0;
    StringBuilder sb = new StringBuilder(128);
    for (char c : jwt.toCharArray()) {
        if (c == SEPARATOR_CHAR) {
            CharSequence tokenSeq = Strings.clean(sb);
            String token = tokenSeq != null ? tokenSeq.toString() : null;
            if (delimiterCount == 0) {
                base64UrlEncodedHeader = token;
            } else if (delimiterCount == 1) {
                base64UrlEncodedPayload = token;
            }
            delimiterCount++;
            sb.setLength(0);
        } else {
            sb.append(c);
        }
    }
    if (delimiterCount != 2) {
        String msg = "JWT strings must contain exactly 2 period characters. Found: " + delimiterCount;
        throw new MalformedJwtException(msg);
    }
    if (sb.length() > 0) {
        base64UrlEncodedDigest = sb.toString();
    }
    // =============== Header =================
    Header header = null;
    CompressionCodec compressionCodec = null;
    if (base64UrlEncodedHeader != null) {
        byte[] bytes = base64UrlDecoder.decode(base64UrlEncodedHeader);
        String origValue = new String(bytes, Strings.UTF_8);
        Map<String, Object> m = (Map<String, Object>) readValue(origValue);
        if (base64UrlEncodedDigest != null) {
            header = new DefaultJwsHeader(m);
        } else {
            header = new DefaultHeader(m);
        }
        compressionCodec = compressionCodecResolver.resolveCompressionCodec(header);
    }
    // =============== Body =================
    // https://github.com/jwtk/jjwt/pull/540
    String payload = "";
    if (base64UrlEncodedPayload != null) {
        byte[] bytes = base64UrlDecoder.decode(base64UrlEncodedPayload);
        if (compressionCodec != null) {
            bytes = compressionCodec.decompress(bytes);
        }
        payload = new String(bytes, Strings.UTF_8);
    }
    Claims claims = null;
    if (!payload.isEmpty() && payload.charAt(0) == '{' && payload.charAt(payload.length() - 1) == '}') {
        // likely to be json, parse it:
        Map<String, Object> claimsMap = (Map<String, Object>) readValue(payload);
        claims = new DefaultClaims(claimsMap);
    }
    // =============== Signature =================
    if (base64UrlEncodedDigest != null) {
        // it is signed - validate the signature
        JwsHeader jwsHeader = (JwsHeader) header;
        SignatureAlgorithm algorithm = null;
        if (header != null) {
            String alg = jwsHeader.getAlgorithm();
            if (Strings.hasText(alg)) {
                algorithm = SignatureAlgorithm.forName(alg);
            }
        }
        if (algorithm == null || algorithm == SignatureAlgorithm.NONE) {
            // it is plaintext, but it has a signature.  This is invalid:
            String msg = "JWT string has a digest/signature, but the header does not reference a valid signature " + "algorithm.";
            throw new MalformedJwtException(msg);
        }
        if (key != null && keyBytes != null) {
            throw new IllegalStateException("A key object and key bytes cannot both be specified. Choose either.");
        } else if ((key != null || keyBytes != null) && signingKeyResolver != null) {
            String object = key != null ? "a key object" : "key bytes";
            throw new IllegalStateException("A signing key resolver and " + object + " cannot both be specified. Choose either.");
        }
        // digitally signed, let's assert the signature:
        Key key = this.key;
        if (key == null) {
            // fall back to keyBytes
            byte[] keyBytes = this.keyBytes;
            if (Objects.isEmpty(keyBytes) && signingKeyResolver != null) {
                // use the signingKeyResolver
                if (claims != null) {
                    key = signingKeyResolver.resolveSigningKey(jwsHeader, claims);
                } else {
                    key = signingKeyResolver.resolveSigningKey(jwsHeader, payload);
                }
            }
            if (!Objects.isEmpty(keyBytes)) {
                Assert.isTrue(algorithm.isHmac(), "Key bytes can only be specified for HMAC signatures. Please specify a PublicKey or PrivateKey instance.");
                key = new SecretKeySpec(keyBytes, algorithm.getJcaName());
            }
        }
        Assert.notNull(key, "A signing key must be specified if the specified JWT is digitally signed.");
        // re-create the jwt part without the signature.  This is what needs to be signed for verification:
        String jwtWithoutSignature = base64UrlEncodedHeader + SEPARATOR_CHAR;
        if (base64UrlEncodedPayload != null) {
            jwtWithoutSignature += base64UrlEncodedPayload;
        }
        JwtSignatureValidator validator;
        try {
            // since 0.10.0: https://github.com/jwtk/jjwt/issues/334
            algorithm.assertValidVerificationKey(key);
            validator = createSignatureValidator(algorithm, key);
        } catch (WeakKeyException e) {
            throw e;
        } catch (InvalidKeyException | IllegalArgumentException e) {
            String algName = algorithm.getValue();
            String msg = "The parsed JWT indicates it was signed with the " + algName + " signature " + "algorithm, but the specified signing key of type " + key.getClass().getName() + " may not be used to validate " + algName + " signatures.  Because the specified " + "signing key reflects a specific and expected algorithm, and the JWT does not reflect " + "this algorithm, it is likely that the JWT was not expected and therefore should not be " + "trusted.  Another possibility is that the parser was configured with the incorrect " + "signing key, but this cannot be assumed for security reasons.";
            throw new UnsupportedJwtException(msg, e);
        }
        if (!validator.isValid(jwtWithoutSignature, base64UrlEncodedDigest)) {
            String msg = "JWT signature does not match locally computed signature. JWT validity cannot be " + "asserted and should not be trusted.";
            throw new SignatureException(msg);
        }
    }
    final boolean allowSkew = this.allowedClockSkewMillis > 0;
    // since 0.3:
    if (claims != null) {
        final Date now = this.clock.now();
        long nowTime = now.getTime();
        // https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-30#section-4.1.4
        // token MUST NOT be accepted on or after any specified exp time:
        Date exp = claims.getExpiration();
        if (exp != null) {
            long maxTime = nowTime - this.allowedClockSkewMillis;
            Date max = allowSkew ? new Date(maxTime) : now;
            if (max.after(exp)) {
                String expVal = DateFormats.formatIso8601(exp, false);
                String nowVal = DateFormats.formatIso8601(now, false);
                long differenceMillis = maxTime - exp.getTime();
                String msg = "JWT expired at " + expVal + ". Current time: " + nowVal + ", a difference of " + differenceMillis + " milliseconds.  Allowed clock skew: " + this.allowedClockSkewMillis + " milliseconds.";
                throw new ExpiredJwtException(header, claims, msg);
            }
        }
        // https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-30#section-4.1.5
        // token MUST NOT be accepted before any specified nbf time:
        Date nbf = claims.getNotBefore();
        if (nbf != null) {
            long minTime = nowTime + this.allowedClockSkewMillis;
            Date min = allowSkew ? new Date(minTime) : now;
            if (min.before(nbf)) {
                String nbfVal = DateFormats.formatIso8601(nbf, false);
                String nowVal = DateFormats.formatIso8601(now, false);
                long differenceMillis = nbf.getTime() - minTime;
                String msg = "JWT must not be accepted before " + nbfVal + ". Current time: " + nowVal + ", a difference of " + differenceMillis + " milliseconds.  Allowed clock skew: " + this.allowedClockSkewMillis + " milliseconds.";
                throw new PrematureJwtException(header, claims, msg);
            }
        }
        validateExpectedClaims(header, claims);
    }
    Object body = claims != null ? claims : payload;
    if (base64UrlEncodedDigest != null) {
        return new DefaultJws<>((JwsHeader) header, body, base64UrlEncodedDigest);
    } else {
        return new DefaultJwt<>(header, body);
    }
}
Also used : WeakKeyException(io.jsonwebtoken.security.WeakKeyException) SignatureAlgorithm(io.jsonwebtoken.SignatureAlgorithm) SignatureException(io.jsonwebtoken.security.SignatureException) DefaultJwtSignatureValidator(io.jsonwebtoken.impl.crypto.DefaultJwtSignatureValidator) JwtSignatureValidator(io.jsonwebtoken.impl.crypto.JwtSignatureValidator) SecretKeySpec(javax.crypto.spec.SecretKeySpec) CompressionCodec(io.jsonwebtoken.CompressionCodec) UnsupportedJwtException(io.jsonwebtoken.UnsupportedJwtException) Claims(io.jsonwebtoken.Claims) ExpiredJwtException(io.jsonwebtoken.ExpiredJwtException) JwsHeader(io.jsonwebtoken.JwsHeader) PrematureJwtException(io.jsonwebtoken.PrematureJwtException) InvalidKeyException(io.jsonwebtoken.security.InvalidKeyException) Date(java.util.Date) Header(io.jsonwebtoken.Header) JwsHeader(io.jsonwebtoken.JwsHeader) Deserializer(io.jsonwebtoken.io.Deserializer) MalformedJwtException(io.jsonwebtoken.MalformedJwtException) Map(java.util.Map) Key(java.security.Key)

Example 7 with UnsupportedJwtException

use of io.jsonwebtoken.UnsupportedJwtException in project zm-mailbox by Zimbra.

the class JWTUtil method getClaims.

private static Claims getClaims(String jwt) throws ServiceException {
    Claims claims = null;
    if (!StringUtil.isNullOrEmpty(jwt)) {
        claims = CLAIMS_CACHE.getIfPresent(jwt);
        if (claims == null) {
            int i = jwt.lastIndexOf('.');
            String untrustedJwtString = jwt.substring(0, i + 1);
            try {
                claims = Jwts.parser().parseClaimsJwt(untrustedJwtString).getBody();
                CLAIMS_CACHE.put(jwt, claims);
            } catch (ExpiredJwtException eje) {
                ZimbraLog.account.debug("jwt expired", eje);
                throw ServiceException.AUTH_EXPIRED(eje.getMessage());
            } catch (UnsupportedJwtException uje) {
                ZimbraLog.account.debug("unsupported jwt exception", uje);
                throw AuthFailedServiceException.AUTH_FAILED("Unsupported JWT received", uje);
            } catch (MalformedJwtException mje) {
                ZimbraLog.account.debug("malformed jwt exception", mje);
                throw AuthFailedServiceException.AUTH_FAILED("Malformed JWT received", mje);
            } catch (Exception e) {
                ZimbraLog.account.debug("exception during jwt validation", e);
                throw AuthFailedServiceException.AUTH_FAILED("Exception thrown while validating JWT", e);
            }
        }
    }
    return claims;
}
Also used : Claims(io.jsonwebtoken.Claims) ExpiredJwtException(io.jsonwebtoken.ExpiredJwtException) MalformedJwtException(io.jsonwebtoken.MalformedJwtException) AccountServiceException(com.zimbra.cs.account.AccountServiceException) UnsupportedJwtException(io.jsonwebtoken.UnsupportedJwtException) ServiceException(com.zimbra.common.service.ServiceException) SignatureException(io.jsonwebtoken.SignatureException) AuthFailedServiceException(com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException) MalformedJwtException(io.jsonwebtoken.MalformedJwtException) ExpiredJwtException(io.jsonwebtoken.ExpiredJwtException) UnsupportedJwtException(io.jsonwebtoken.UnsupportedJwtException)

Example 8 with UnsupportedJwtException

use of io.jsonwebtoken.UnsupportedJwtException in project nifi-registry by apache.

the class JwtService method parseTokenFromBase64EncodedString.

private Jws<Claims> parseTokenFromBase64EncodedString(final String base64EncodedToken) throws JwtException {
    try {
        return Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() {

            @Override
            public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
                final String identity = claims.getSubject();
                // Get the key based on the key id in the claims
                final String keyId = claims.get(KEY_ID_CLAIM, String.class);
                final Key key = keyService.getKey(keyId);
                // Ensure we were able to find a key that was previously issued by this key service for this user
                if (key == null || key.getKey() == null) {
                    throw new UnsupportedJwtException("Unable to determine signing key for " + identity + " [kid: " + keyId + "]");
                }
                return key.getKey().getBytes(StandardCharsets.UTF_8);
            }
        }).parseClaimsJws(base64EncodedToken);
    } catch (final MalformedJwtException | UnsupportedJwtException | SignatureException | ExpiredJwtException | IllegalArgumentException e) {
        // TODO: Exercise all exceptions to ensure none leak key material to logs
        final String errorMessage = "Unable to validate the access token.";
        throw new JwtException(errorMessage, e);
    }
}
Also used : Claims(io.jsonwebtoken.Claims) SigningKeyResolverAdapter(io.jsonwebtoken.SigningKeyResolverAdapter) ExpiredJwtException(io.jsonwebtoken.ExpiredJwtException) JwsHeader(io.jsonwebtoken.JwsHeader) UnsupportedJwtException(io.jsonwebtoken.UnsupportedJwtException) MalformedJwtException(io.jsonwebtoken.MalformedJwtException) ExpiredJwtException(io.jsonwebtoken.ExpiredJwtException) JwtException(io.jsonwebtoken.JwtException) SignatureException(io.jsonwebtoken.SignatureException) MalformedJwtException(io.jsonwebtoken.MalformedJwtException) Key(org.apache.nifi.registry.security.key.Key) UnsupportedJwtException(io.jsonwebtoken.UnsupportedJwtException)

Example 9 with UnsupportedJwtException

use of io.jsonwebtoken.UnsupportedJwtException in project spring-security-jwt-csrf by alexatiks.

the class JWTAuthenticationFilter method doFilterInternal.

@Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException {
    try {
        Authentication authentication = TokenAuthenticationHelper.getAuthentication(request);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        filterChain.doFilter(request, response);
    } catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | SignatureException | IllegalArgumentException e) {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token expired");
    }
}
Also used : ExpiredJwtException(io.jsonwebtoken.ExpiredJwtException) Authentication(org.springframework.security.core.Authentication) SignatureException(io.jsonwebtoken.SignatureException) MalformedJwtException(io.jsonwebtoken.MalformedJwtException) UnsupportedJwtException(io.jsonwebtoken.UnsupportedJwtException)

Aggregations

ExpiredJwtException (io.jsonwebtoken.ExpiredJwtException)9 UnsupportedJwtException (io.jsonwebtoken.UnsupportedJwtException)9 Claims (io.jsonwebtoken.Claims)8 MalformedJwtException (io.jsonwebtoken.MalformedJwtException)8 SignatureException (io.jsonwebtoken.SignatureException)7 JwsHeader (io.jsonwebtoken.JwsHeader)3 ServiceException (com.zimbra.common.service.ServiceException)2 AccountServiceException (com.zimbra.cs.account.AccountServiceException)2 AuthFailedServiceException (com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException)2 JwtException (io.jsonwebtoken.JwtException)2 SigningKeyResolverAdapter (io.jsonwebtoken.SigningKeyResolverAdapter)2 SignatureException (io.jsonwebtoken.security.SignatureException)2 Key (java.security.Key)2 Date (java.util.Date)2 SecretKeySpec (javax.crypto.spec.SecretKeySpec)2 User (com.serotonin.m2m2.vo.User)1 NotFoundException (com.serotonin.m2m2.vo.exception.NotFoundException)1 Account (com.zimbra.cs.account.Account)1 AuthTokenKey (com.zimbra.cs.account.AuthTokenKey)1 CompressionCodec (io.jsonwebtoken.CompressionCodec)1