use of io.jsonwebtoken.security.SignatureException in project sonarqube by SonarSource.
the class JwtSerializer method decode.
Optional<Claims> decode(String token) {
checkIsStarted();
Claims claims = null;
try {
claims = Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(token).getBody();
requireNonNull(claims.getId(), "Token id hasn't been found");
requireNonNull(claims.getSubject(), "Token subject hasn't been found");
requireNonNull(claims.getExpiration(), "Token expiration date hasn't been found");
requireNonNull(claims.getIssuedAt(), "Token creation date hasn't been found");
return Optional.of(claims);
} catch (UnsupportedJwtException | ExpiredJwtException | SignatureException e) {
return Optional.empty();
} catch (Exception e) {
throw AuthenticationException.newBuilder().setSource(Source.jwt()).setLogin(claims == null ? null : claims.getSubject()).setMessage(e.getMessage()).build();
}
}
use of io.jsonwebtoken.security.SignatureException in project killbill by killbill.
the class KillBillAuth0Realm method loadPublicKey.
private PublicKey loadPublicKey(final String keyId) {
final BoundRequestBuilder builder = httpClient.prepareGet(securityConfig.getShiroAuth0Url() + "/.well-known/jwks.json");
final Response response;
try {
final ListenableFuture<Response> futureStatus = builder.execute(new AsyncCompletionHandler<Response>() {
@Override
public Response onCompleted(final Response response) throws Exception {
return response;
}
});
response = futureStatus.get(DEFAULT_TIMEOUT_SECS, TimeUnit.SECONDS);
} catch (final TimeoutException toe) {
throw new SignatureException("Timeout while connecting to Auth0 to fetch public keys", toe);
} catch (final Exception e) {
throw new SignatureException("Error while connecting to Auth0 to fetch public keys", e);
}
final Map<String, List<Map<String, Object>>> keysResponse;
try {
keysResponse = mapper.readValue(response.getResponseBodyAsStream(), new TypeReference<Map<String, List<Map<String, Object>>>>() {
});
} catch (final IOException e) {
throw new SignatureException("Unable to read public keys from Auth0", e);
}
if (keysResponse.get("keys") == null || keysResponse.get("keys").isEmpty()) {
throw new SignatureException("Auth0 returned no key");
}
final List<Map<String, Object>> newKeys = keysResponse.get("keys");
for (final Map<String, Object> newKey : newKeys) {
if (newKey.get("kid") == null || !newKey.get("kid").equals(keyId) || newKey.get("kty") == null) {
continue;
}
final String kty = (String) newKey.get("kty");
switch(kty) {
case "RSA":
final BigInteger modulus = getBigInteger(newKey.get("n"));
final BigInteger exponent = getBigInteger(newKey.get("e"));
if (modulus == null || exponent == null) {
continue;
}
return new RSAPublicKey() {
@Override
public BigInteger getPublicExponent() {
return exponent;
}
@Override
public String getAlgorithm() {
return "RSA";
}
@Override
public String getFormat() {
return "JWK";
}
@Override
public byte[] getEncoded() {
throw new UnsupportedOperationException();
}
@Override
public BigInteger getModulus() {
return modulus;
}
};
case "EC":
final String curveName = (String) newKey.get("crv");
final BigInteger x = getBigInteger(newKey.get("x"));
final BigInteger y = getBigInteger(newKey.get("y"));
if (curveName == null || x == null || y == null) {
continue;
}
final ECParameterSpec curve = EcCurve.tryGet(curveName);
if (curve == null) {
continue;
}
final ECPoint w = new ECPoint(x, y);
return new ECPublicKey() {
@Override
public ECPoint getW() {
return w;
}
@Override
public String getAlgorithm() {
return "EC";
}
@Override
public String getFormat() {
return "JWK";
}
@Override
public byte[] getEncoded() {
throw new UnsupportedOperationException();
}
@Override
public ECParameterSpec getParams() {
return curve;
}
};
default:
}
}
throw new SignatureException("Could not find Auth0 public key " + keyId);
}
use of io.jsonwebtoken.security.SignatureException in project jjwt by jwtk.
the class EllipticCurveSignatureValidator method isValid.
@Override
public boolean isValid(byte[] data, byte[] signature) {
Signature sig = createSignatureInstance();
PublicKey publicKey = (PublicKey) key;
try {
int expectedSize = getSignatureByteArrayLength(alg);
/**
* If the expected size is not valid for JOSE, fall back to ASN.1 DER signature.
* This fallback is for backwards compatibility ONLY (to support tokens generated by previous versions of jjwt)
* and backwards compatibility will possibly be removed in a future version of this library.
*
* *
*/
byte[] derSignature = expectedSize != signature.length && signature[0] == 0x30 ? signature : EllipticCurveProvider.transcodeSignatureToDER(signature);
return doVerify(sig, publicKey, data, derSignature);
} catch (Exception e) {
String msg = "Unable to verify Elliptic Curve signature using configured ECPublicKey. " + e.getMessage();
throw new SignatureException(msg, e);
}
}
use of io.jsonwebtoken.security.SignatureException 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);
}
}
use of io.jsonwebtoken.security.SignatureException in project jjwt by jwtk.
the class RsaSignatureValidator method isValid.
@Override
public boolean isValid(byte[] data, byte[] signature) {
if (key instanceof PublicKey) {
Signature sig = createSignatureInstance();
PublicKey publicKey = (PublicKey) key;
try {
return doVerify(sig, publicKey, data, signature);
} catch (Exception e) {
String msg = "Unable to verify RSA signature using configured PublicKey. " + e.getMessage();
throw new SignatureException(msg, e);
}
} else {
Assert.notNull(this.SIGNER, "RSA Signer instance cannot be null. This is a bug. Please report it.");
byte[] computed = this.SIGNER.sign(data);
return MessageDigest.isEqual(computed, signature);
}
}
Aggregations