Search in sources :

Example 1 with ExpiredTokenException

use of com.networknt.exception.ExpiredTokenException in project light-4j by networknt.

the class JwtHelper method verifyJwt.

/**
 * Verify JWT token signature as well as expiry.
 *
 * @param jwt String of Json web token
 * @return JwtClaims object
 * @throws InvalidJwtException InvalidJwtException
 * @throws ExpiredTokenException ExpiredTokenException
 */
public static JwtClaims verifyJwt(String jwt) throws InvalidJwtException, ExpiredTokenException {
    JwtClaims claims;
    if (Boolean.TRUE.equals(enableJwtCache)) {
        claims = cache.getIfPresent(jwt);
        if (claims != null) {
            try {
                // and it will never expired here. However, we need to handle other clients.
                if ((NumericDate.now().getValue() - secondsOfAllowedClockSkew) >= claims.getExpirationTime().getValue()) {
                    logger.info("Cached jwt token is expired!");
                    throw new ExpiredTokenException("Token is expired");
                }
            } catch (MalformedClaimException e) {
                // This is cached token and it is impossible to have this exception
                logger.error("MalformedClaimException:", e);
            }
            return claims;
        }
    }
    JwtConsumer consumer = new JwtConsumerBuilder().setSkipAllValidators().setDisableRequireSignature().setSkipSignatureVerification().build();
    JwtContext jwtContext = consumer.process(jwt);
    JwtClaims jwtClaims = jwtContext.getJwtClaims();
    JsonWebStructure structure = jwtContext.getJoseObjects().get(0);
    String kid = structure.getKeyIdHeaderValue();
    // so we do expiration check here manually as we have the claim already for kid
    try {
        if ((NumericDate.now().getValue() - secondsOfAllowedClockSkew) >= jwtClaims.getExpirationTime().getValue()) {
            logger.info("jwt token is expired!");
            throw new ExpiredTokenException("Token is expired");
        }
    } catch (MalformedClaimException e) {
        logger.error("MalformedClaimException:", e);
        throw new InvalidJwtException("MalformedClaimException", new ErrorCodeValidator.Error(ErrorCodes.MALFORMED_CLAIM, "Invalid ExpirationTime Format"), e, jwtContext);
    }
    // get the public key certificate from the cache that is loaded from security.yml if it is not there,
    // go to OAuth2 server /oauth2/key endpoint to get the public key certificate with kid as parameter.
    X509Certificate certificate = certMap == null ? null : certMap.get(kid);
    if (certificate == null) {
        certificate = getCertFromOauth(kid);
        // null if bootstrapFromKeyService is true
        if (certMap == null)
            certMap = new HashMap<>();
        certMap.put(kid, certificate);
    }
    X509VerificationKeyResolver x509VerificationKeyResolver = new X509VerificationKeyResolver(certificate);
    x509VerificationKeyResolver.setTryAllOnNoThumbHeader(true);
    consumer = new JwtConsumerBuilder().setRequireExpirationTime().setAllowedClockSkewInSeconds(secondsOfAllowedClockSkew).setSkipDefaultAudienceValidation().setVerificationKeyResolver(x509VerificationKeyResolver).build();
    // Validate the JWT and process it to the Claims
    jwtContext = consumer.process(jwt);
    claims = jwtContext.getJwtClaims();
    if (Boolean.TRUE.equals(enableJwtCache)) {
        cache.put(jwt, claims);
    }
    return claims;
}
Also used : ExpiredTokenException(com.networknt.exception.ExpiredTokenException) JwtClaims(org.jose4j.jwt.JwtClaims) HashMap(java.util.HashMap) X509Certificate(java.security.cert.X509Certificate) MalformedClaimException(org.jose4j.jwt.MalformedClaimException) X509VerificationKeyResolver(org.jose4j.keys.resolvers.X509VerificationKeyResolver) JsonWebStructure(org.jose4j.jwx.JsonWebStructure)

Example 2 with ExpiredTokenException

use of com.networknt.exception.ExpiredTokenException in project light-rest-4j by networknt.

the class JwtVerifyHandler method handleRequest.

@Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {
    HeaderMap headerMap = exchange.getRequestHeaders();
    String authorization = headerMap.getFirst(Headers.AUTHORIZATION);
    String jwt = JwtHelper.getJwtFromAuthorization(authorization);
    if (jwt != null) {
        try {
            JwtClaims claims = JwtHelper.verifyJwt(jwt);
            Map<String, Object> auditInfo = exchange.getAttachment(AuditHandler.AUDIT_INFO);
            // endpoint and swaggerOperation available. This handler will enrich the auditInfo.
            if (auditInfo == null) {
                auditInfo = new HashMap<>();
                exchange.putAttachment(AuditHandler.AUDIT_INFO, auditInfo);
            }
            auditInfo.put(Constants.CLIENT_ID_STRING, claims.getStringClaimValue(Constants.CLIENT_ID_STRING));
            auditInfo.put(Constants.USER_ID_STRING, claims.getStringClaimValue(Constants.USER_ID_STRING));
            if (config != null && (Boolean) config.get(ENABLE_VERIFY_SCOPE) && OpenApiHelper.openApi3 != null) {
                Operation operation = null;
                OpenApiOperation openApiOperation = (OpenApiOperation) auditInfo.get(Constants.OPENAPI_OPERATION_STRING);
                if (openApiOperation == null) {
                    final NormalisedPath requestPath = new ApiNormalisedPath(exchange.getRequestURI());
                    final Optional<NormalisedPath> maybeApiPath = OpenApiHelper.findMatchingApiPath(requestPath);
                    if (!maybeApiPath.isPresent()) {
                        Status status = new Status(STATUS_INVALID_REQUEST_PATH);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    }
                    final NormalisedPath swaggerPathString = maybeApiPath.get();
                    final Path swaggerPath = OpenApiHelper.openApi3.getPath(swaggerPathString.original());
                    final String httpMethod = exchange.getRequestMethod().toString().toLowerCase();
                    operation = swaggerPath.getOperation(httpMethod);
                    if (operation == null) {
                        Status status = new Status(STATUS_METHOD_NOT_ALLOWED);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    }
                    openApiOperation = new OpenApiOperation(swaggerPathString, swaggerPath, httpMethod, operation);
                    auditInfo.put(Constants.OPENAPI_OPERATION_STRING, openApiOperation);
                    auditInfo.put(Constants.ENDPOINT_STRING, swaggerPathString.normalised() + "@" + httpMethod);
                } else {
                    operation = openApiOperation.getOperation();
                }
                // is there a scope token
                String scopeHeader = headerMap.getFirst(Constants.SCOPE_TOKEN);
                String scopeJwt = JwtHelper.getJwtFromAuthorization(scopeHeader);
                List<String> secondaryScopes = null;
                if (scopeJwt != null) {
                    try {
                        JwtClaims scopeClaims = JwtHelper.verifyJwt(scopeJwt);
                        secondaryScopes = scopeClaims.getStringListClaimValue("scope");
                        auditInfo.put(Constants.SCOPE_CLIENT_ID_STRING, scopeClaims.getStringClaimValue(Constants.CLIENT_ID_STRING));
                    } catch (InvalidJwtException | MalformedClaimException e) {
                        logger.error("InvalidJwtException", e);
                        Status status = new Status(STATUS_INVALID_SCOPE_TOKEN);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    } catch (ExpiredTokenException e) {
                        Status status = new Status(STATUS_SCOPE_TOKEN_EXPIRED);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    }
                }
                // get scope defined in swagger spec for this endpoint.
                Collection<String> specScopes = null;
                Collection<SecurityRequirement> securityRequirements = operation.getSecurityRequirements();
                if (securityRequirements != null) {
                    for (SecurityRequirement requirement : securityRequirements) {
                        SecurityParameter securityParameter = requirement.getRequirement(OpenApiHelper.oauth2Name);
                        specScopes = securityParameter.getParameters();
                        if (specScopes != null)
                            break;
                    }
                }
                // validate scope
                if (scopeHeader != null) {
                    if (secondaryScopes == null || !matchedScopes(secondaryScopes, specScopes)) {
                        Status status = new Status(STATUS_SCOPE_TOKEN_SCOPE_MISMATCH, secondaryScopes, specScopes);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    }
                } else {
                    // no scope token, verify scope from auth token.
                    List<String> primaryScopes;
                    try {
                        primaryScopes = claims.getStringListClaimValue("scope");
                    } catch (MalformedClaimException e) {
                        logger.error("MalformedClaimException", e);
                        Status status = new Status(STATUS_INVALID_AUTH_TOKEN);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    }
                    if (!matchedScopes(primaryScopes, specScopes)) {
                        Status status = new Status(STATUS_AUTH_TOKEN_SCOPE_MISMATCH, primaryScopes, specScopes);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    }
                }
            }
            next.handleRequest(exchange);
        } catch (InvalidJwtException e) {
            // only log it and unauthorized is returned.
            logger.error("Exception: ", e);
            Status status = new Status(STATUS_INVALID_AUTH_TOKEN);
            exchange.setStatusCode(status.getStatusCode());
            logger.error("Error in JwtVerifyHandler: " + status.toString());
            exchange.getResponseSender().send(status.toString());
        } catch (ExpiredTokenException e) {
            Status status = new Status(STATUS_AUTH_TOKEN_EXPIRED);
            exchange.setStatusCode(status.getStatusCode());
            logger.error("Error in JwtVerifyHandler: " + status.toString());
            exchange.getResponseSender().send(status.toString());
        }
    } else {
        Status status = new Status(STATUS_MISSING_AUTH_TOKEN);
        exchange.setStatusCode(status.getStatusCode());
        logger.error("Error in JwtVerifyHandler: " + status.toString());
        exchange.getResponseSender().send(status.toString());
    }
}
Also used : Status(com.networknt.status.Status) Path(com.networknt.oas.model.Path) InvalidJwtException(org.jose4j.jwt.consumer.InvalidJwtException) ExpiredTokenException(com.networknt.exception.ExpiredTokenException) JwtClaims(org.jose4j.jwt.JwtClaims) Operation(com.networknt.oas.model.Operation) MalformedClaimException(org.jose4j.jwt.MalformedClaimException) HeaderMap(io.undertow.util.HeaderMap) SecurityParameter(com.networknt.oas.model.SecurityParameter) SecurityRequirement(com.networknt.oas.model.SecurityRequirement)

Example 3 with ExpiredTokenException

use of com.networknt.exception.ExpiredTokenException in project light-rest-4j by networknt.

the class JwtVerifyHandler method handleRequest.

@Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {
    HeaderMap headerMap = exchange.getRequestHeaders();
    String authorization = headerMap.getFirst(Headers.AUTHORIZATION);
    String jwt = JwtHelper.getJwtFromAuthorization(authorization);
    if (jwt != null) {
        try {
            JwtClaims claims = JwtHelper.verifyJwt(jwt);
            Map<String, Object> auditInfo = exchange.getAttachment(AuditHandler.AUDIT_INFO);
            // endpoint and swaggerOperation available. This handler will enrich the auditInfo.
            if (auditInfo == null) {
                auditInfo = new HashMap<>();
                exchange.putAttachment(AuditHandler.AUDIT_INFO, auditInfo);
            }
            auditInfo.put(Constants.CLIENT_ID_STRING, claims.getStringClaimValue(Constants.CLIENT_ID_STRING));
            auditInfo.put(Constants.USER_ID_STRING, claims.getStringClaimValue(Constants.USER_ID_STRING));
            auditInfo.put(Constants.SUBJECT_CLAIMS, claims);
            if (config != null && (Boolean) config.get(ENABLE_VERIFY_SCOPE) && SwaggerHelper.swagger != null) {
                Operation operation = null;
                SwaggerOperation swaggerOperation = (SwaggerOperation) auditInfo.get(Constants.SWAGGER_OPERATION_STRING);
                if (swaggerOperation == null) {
                    final NormalisedPath requestPath = new ApiNormalisedPath(exchange.getRequestURI());
                    final Optional<NormalisedPath> maybeApiPath = SwaggerHelper.findMatchingApiPath(requestPath);
                    if (!maybeApiPath.isPresent()) {
                        Status status = new Status(STATUS_INVALID_REQUEST_PATH);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    }
                    final NormalisedPath swaggerPathString = maybeApiPath.get();
                    final Path swaggerPath = SwaggerHelper.swagger.getPath(swaggerPathString.original());
                    final HttpMethod httpMethod = HttpMethod.valueOf(exchange.getRequestMethod().toString());
                    operation = swaggerPath.getOperationMap().get(httpMethod);
                    if (operation == null) {
                        Status status = new Status(STATUS_METHOD_NOT_ALLOWED);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    }
                    swaggerOperation = new SwaggerOperation(swaggerPathString, swaggerPath, httpMethod, operation);
                    auditInfo.put(Constants.SWAGGER_OPERATION_STRING, swaggerOperation);
                    auditInfo.put(Constants.ENDPOINT_STRING, swaggerPathString.normalised() + "@" + httpMethod);
                } else {
                    operation = swaggerOperation.getOperation();
                }
                // is there a scope token
                String scopeHeader = headerMap.getFirst(Constants.SCOPE_TOKEN);
                String scopeJwt = JwtHelper.getJwtFromAuthorization(scopeHeader);
                List<String> secondaryScopes = null;
                if (scopeJwt != null) {
                    try {
                        JwtClaims scopeClaims = JwtHelper.verifyJwt(scopeJwt);
                        secondaryScopes = scopeClaims.getStringListClaimValue("scope");
                        auditInfo.put(Constants.SCOPE_CLIENT_ID_STRING, scopeClaims.getStringClaimValue(Constants.CLIENT_ID_STRING));
                        auditInfo.put(Constants.ACCESS_CLAIMS, scopeClaims);
                    } catch (InvalidJwtException | MalformedClaimException e) {
                        logger.error("InvalidJwtException", e);
                        Status status = new Status(STATUS_INVALID_SCOPE_TOKEN);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    } catch (ExpiredTokenException e) {
                        Status status = new Status(STATUS_SCOPE_TOKEN_EXPIRED);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    }
                }
                // get scope defined in swagger spec for this endpoint.
                List<String> specScopes = null;
                List<Map<String, List<String>>> security = operation.getSecurity();
                if (security != null) {
                    for (Map<String, List<String>> requirement : security) {
                        specScopes = requirement.get(SwaggerHelper.oauth2Name);
                        if (specScopes != null)
                            break;
                    }
                }
                // validate scope
                if (scopeHeader != null) {
                    if (secondaryScopes == null || !matchedScopes(secondaryScopes, specScopes)) {
                        Status status = new Status(STATUS_SCOPE_TOKEN_SCOPE_MISMATCH, secondaryScopes, specScopes);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    }
                } else {
                    // no scope token, verify scope from auth token.
                    List<String> primaryScopes;
                    try {
                        primaryScopes = claims.getStringListClaimValue("scope");
                    } catch (MalformedClaimException e) {
                        logger.error("MalformedClaimException", e);
                        Status status = new Status(STATUS_INVALID_AUTH_TOKEN);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    }
                    if (!matchedScopes(primaryScopes, specScopes)) {
                        Status status = new Status(STATUS_AUTH_TOKEN_SCOPE_MISMATCH, primaryScopes, specScopes);
                        exchange.setStatusCode(status.getStatusCode());
                        logger.error("Error in JwtVerifyHandler: " + status.toString());
                        exchange.getResponseSender().send(status.toString());
                        return;
                    }
                }
            }
            next.handleRequest(exchange);
        } catch (InvalidJwtException e) {
            // only log it and unauthorized is returned.
            logger.error("Exception: ", e);
            Status status = new Status(STATUS_INVALID_AUTH_TOKEN);
            exchange.setStatusCode(status.getStatusCode());
            logger.error("Error in JwtVerifyHandler: " + status.toString());
            exchange.getResponseSender().send(status.toString());
        } catch (ExpiredTokenException e) {
            Status status = new Status(STATUS_AUTH_TOKEN_EXPIRED);
            exchange.setStatusCode(status.getStatusCode());
            logger.error("Error in JwtVerifyHandler: " + status.toString());
            exchange.getResponseSender().send(status.toString());
        }
    } else {
        Status status = new Status(STATUS_MISSING_AUTH_TOKEN);
        exchange.setStatusCode(status.getStatusCode());
        logger.error("Error in JwtVerifyHandler: " + status.toString());
        exchange.getResponseSender().send(status.toString());
    }
}
Also used : Status(com.networknt.status.Status) InvalidJwtException(org.jose4j.jwt.consumer.InvalidJwtException) ExpiredTokenException(com.networknt.exception.ExpiredTokenException) JwtClaims(org.jose4j.jwt.JwtClaims) HttpString(io.undertow.util.HttpString) MalformedClaimException(org.jose4j.jwt.MalformedClaimException) HeaderMap(io.undertow.util.HeaderMap) List(java.util.List) HashMap(java.util.HashMap) HeaderMap(io.undertow.util.HeaderMap) Map(java.util.Map)

Aggregations

ExpiredTokenException (com.networknt.exception.ExpiredTokenException)3 JwtClaims (org.jose4j.jwt.JwtClaims)3 MalformedClaimException (org.jose4j.jwt.MalformedClaimException)3 Status (com.networknt.status.Status)2 HeaderMap (io.undertow.util.HeaderMap)2 HashMap (java.util.HashMap)2 InvalidJwtException (org.jose4j.jwt.consumer.InvalidJwtException)2 Operation (com.networknt.oas.model.Operation)1 Path (com.networknt.oas.model.Path)1 SecurityParameter (com.networknt.oas.model.SecurityParameter)1 SecurityRequirement (com.networknt.oas.model.SecurityRequirement)1 HttpString (io.undertow.util.HttpString)1 X509Certificate (java.security.cert.X509Certificate)1 List (java.util.List)1 Map (java.util.Map)1 JsonWebStructure (org.jose4j.jwx.JsonWebStructure)1 X509VerificationKeyResolver (org.jose4j.keys.resolvers.X509VerificationKeyResolver)1