use of io.gravitee.am.common.exception.jwt.ExpiredJWTException in project gravitee-access-management by gravitee-io.
the class DefaultJWTParser method parse.
@Override
public JWT parse(String payload) {
try {
// verify format
SignedJWT signedJWT = SignedJWT.parse(payload);
// verify signature
boolean verified = signedJWT.verify(verifier);
if (!verified) {
throw new JOSEException("The signature was not verified");
}
Map<String, Object> claims = signedJWT.getPayload().toJSONObject().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
JWT jwt = new JWT(claims);
// verify exp and nbf values
// 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
Instant now = Instant.now();
evaluateExp(jwt.getExp(), now, this.allowedClockSkewMillis);
// 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
evaluateNbf(jwt.getNbf(), now, this.allowedClockSkewMillis);
return jwt;
} catch (ParseException ex) {
logger.debug("The following JWT token : {} is malformed", payload);
throw new MalformedJWTException("Token is malformed", ex);
} catch (ExpiredJWTException ex) {
logger.debug("The following JWT token : {} is expired", payload);
throw new ExpiredJWTException("Token is expired", ex);
} catch (PrematureJWTException ex) {
logger.debug("The following JWT token : {} must not be accepted (nbf)", payload);
throw new PrematureJWTException("Token must not be accepted (nbf)", ex);
} catch (JOSEException ex) {
logger.debug("Verifying JWT token signature : {} has failed", payload);
throw new SignatureException("Token's signature is invalid", ex);
} catch (Exception ex) {
logger.error("An error occurs while parsing JWT token : {}", payload, ex);
throw ex;
}
}
use of io.gravitee.am.common.exception.jwt.ExpiredJWTException in project gravitee-access-management by gravitee-io.
the class AuthenticationRequestParseRequestObjectHandler method validateRequestObjectClaims.
private Single<JWT> validateRequestObjectClaims(RoutingContext context, JWT jwt) {
try {
OpenIDProviderMetadata oidcMeta = context.get(PROVIDER_METADATA_CONTEXT_KEY);
Client client = context.get(CLIENT_CONTEXT_KEY);
final JWTClaimsSet claims = jwt.getJWTClaimsSet();
// aud : The Audience claim MUST contain the value of the Issuer Identifier for the OP, which identifies the Authorization Server as an intended audience.
final Object aud = claims.getClaim(Claims.aud);
if (aud == null || (aud instanceof String && !oidcMeta.getIssuer().equals(aud)) || (aud instanceof Collection && (((Collection) aud).isEmpty() || !((Collection) aud).stream().anyMatch(oidcMeta.getIssuer()::equals)))) {
return Single.error(new InvalidRequestException("aud is missing or invalid"));
}
// iss : The Issuer claim MUST be the client_id of the OAuth Client.
final String iss = claims.getStringClaim(Claims.iss);
if (iss == null || !client.getClientId().equals(iss)) {
return Single.error(new InvalidRequestException("iss is missing or invalid"));
}
// exp : An expiration time that limits the validity lifetime of the signed authentication request.
final Date exp = claims.getDateClaim(Claims.exp);
if (exp == null) {
return Single.error(new InvalidRequestException("exp is missing"));
}
DefaultJWTParser.evaluateExp(exp.getTime() / 1000, Instant.now(), 0);
// iat : The time at which the signed authentication request was created.
final Date iat = claims.getDateClaim(Claims.iat);
if (iat == null) {
return Single.error(new InvalidRequestException("iat is missing"));
}
// nbf : The time before which the signed authentication request is unacceptable.
final Date nbf = claims.getDateClaim(Claims.nbf);
if (nbf == null) {
return Single.error(new InvalidRequestException("nbf is missing"));
}
DefaultJWTParser.evaluateNbf(nbf.getTime() / 1000, Instant.now(), 0);
// jti : A unique identifier for the signed authentication request.
if (claims.getStringClaim(Claims.jti) == null) {
return Single.error(new InvalidRequestException("jti is missing"));
}
} catch (ParseException e) {
return Single.error(new InvalidRequestException("Unable to read claims in the request parameter"));
} catch (PrematureJWTException e) {
return Single.error(new InvalidRequestException("nbf is invalid"));
} catch (ExpiredJWTException e) {
return Single.error(new InvalidRequestException("jwt has expired"));
}
return Single.just(jwt);
}
use of io.gravitee.am.common.exception.jwt.ExpiredJWTException in project gravitee-access-management by gravitee-io.
the class DefaultJWTParser method evaluateExp.
/**
* Throw {@link ExpiredJWTException} if exp is after now
*
* @param exp
* @param now
*/
public static void evaluateExp(long exp, Instant now, long clockSkew) {
if (exp > 0) {
Instant expInstant = Instant.ofEpochSecond(exp);
if (now.isAfter(expInstant)) {
long differenceMillis = now.toEpochMilli() - expInstant.toEpochMilli();
String msg = "JWT expired at " + expInstant + ". Current time: " + now + ", a difference of " + differenceMillis + " milliseconds. Allowed clock skew: " + clockSkew + " milliseconds.";
throw new ExpiredJWTException(msg);
}
}
}
use of io.gravitee.am.common.exception.jwt.ExpiredJWTException in project gravitee-access-management by gravitee-io.
the class CibaAuthenticationRequestResolver method validateLoginHintToken.
private Single<CibaAuthenticationRequest> validateLoginHintToken(CibaAuthenticationRequest authRequest, JWT jwt) {
try {
final Date expirationTime = jwt.getJWTClaimsSet().getExpirationTime();
if (expirationTime != null) {
evaluateExp(expirationTime.toInstant().getEpochSecond(), Instant.now(), 0);
}
final JSONObject subIdObject = jwt.getJWTClaimsSet().getJSONObjectClaim("sub_id");
/*
sub_id is an object specifying the field identifying the user (through format entry)
Supported format : email and username
{
"sub_id": {
"format": "email",
"email": "user@acme.fr"
}
}
*/
final FilterCriteria criteria = new FilterCriteria();
criteria.setQuoteFilterValue(false);
final String field = subIdObject.getAsString("format");
if (!"email".equals(field) && !"username".equals(field)) {
return Single.error(new InvalidRequestException("Invalid hint, only email and username are supported"));
}
criteria.setFilterName(field);
criteria.setFilterValue(subIdObject.getAsString(field));
return userService.findByDomainAndCriteria(domain.getId(), criteria).flatMap(users -> {
if (users.size() != 1) {
LOGGER.warn("login_hint_token match multiple users or no one");
return Single.error(new InvalidRequestException("Invalid hint"));
}
authRequest.setSubject(users.get(0).getId());
return Single.just(authRequest);
});
} catch (ExpiredJWTException e) {
return Single.error(new ExpiredLoginHintTokenException("login_token_hint expired"));
} catch (ParseException e) {
// should never happen
LOGGER.warn("login_hint_token can't be read", e);
return Single.error(new ExpiredLoginHintTokenException("invalid login_token_hint"));
}
}
Aggregations