Search in sources :

Example 1 with NumericDate

use of org.jose4j.jwt.NumericDate in project blueocean-plugin by jenkinsci.

the class JwtAuthenticationToken method validate.

private static JwtClaims validate(StaplerRequest request) {
    String authHeader = request.getHeader("Authorization");
    if (authHeader == null || !authHeader.startsWith("Bearer ")) {
        throw new ServiceException.UnauthorizedException("JWT token not found");
    }
    String token = authHeader.substring("Bearer ".length());
    try {
        JsonWebStructure jws = JsonWebStructure.fromCompactSerialization(token);
        String alg = jws.getAlgorithmHeaderValue();
        if (alg == null || !alg.equals(RSA_USING_SHA256)) {
            logger.error(String.format("Invalid JWT token: unsupported algorithm in header, found %s, expected %s", alg, RSA_USING_SHA256));
            throw new ServiceException.UnauthorizedException("Invalid JWT token");
        }
        String kid = jws.getKeyIdHeaderValue();
        if (kid == null) {
            logger.error("Invalid JWT token: missing kid");
            throw new ServiceException.UnauthorizedException("Invalid JWT token");
        }
        JwtToken.JwtRsaDigitalSignatureKey key = new JwtToken.JwtRsaDigitalSignatureKey(kid);
        try {
            if (!key.exists()) {
                throw new ServiceException.NotFoundException(String.format("kid %s not found", kid));
            }
        } catch (IOException e) {
            logger.error(String.format("Error reading RSA key for id %s: %s", kid, e.getMessage()), e);
            throw new ServiceException.UnexpectedErrorException("Unexpected error: " + e.getMessage(), e);
        }
        JwtConsumer jwtConsumer = new JwtConsumerBuilder().setRequireExpirationTime().setRequireJwtId().setAllowedClockSkewInSeconds(// allow some leeway in validating time based claims to account for clock skew
        30).setRequireSubject().setVerificationKey(// verify the sign with the public key
        key.getPublicKey()).build();
        try {
            JwtContext context = jwtConsumer.process(token);
            JwtClaims claims = context.getJwtClaims();
            //check if token expired
            NumericDate expirationTime = claims.getExpirationTime();
            if (expirationTime.isBefore(NumericDate.now())) {
                throw new ServiceException.UnauthorizedException("Invalid JWT token: expired");
            }
            return claims;
        } catch (InvalidJwtException e) {
            logger.error("Invalid JWT token: " + e.getMessage(), e);
            throw new ServiceException.UnauthorizedException("Invalid JWT token");
        } catch (MalformedClaimException e) {
            logger.error(String.format("Error reading sub header for token %s", jws.getPayload()), e);
            throw new ServiceException.UnauthorizedException("Invalid JWT token: malformed claim");
        }
    } catch (JoseException e) {
        logger.error("Error parsing JWT token: " + e.getMessage(), e);
        throw new ServiceException.UnauthorizedException("Invalid JWT Token: " + e.getMessage());
    }
}
Also used : InvalidJwtException(org.jose4j.jwt.consumer.InvalidJwtException) NumericDate(org.jose4j.jwt.NumericDate) JwtClaims(org.jose4j.jwt.JwtClaims) JwtConsumerBuilder(org.jose4j.jwt.consumer.JwtConsumerBuilder) JoseException(org.jose4j.lang.JoseException) JwtContext(org.jose4j.jwt.consumer.JwtContext) IOException(java.io.IOException) JwtToken(io.jenkins.blueocean.auth.jwt.JwtToken) MalformedClaimException(org.jose4j.jwt.MalformedClaimException) ServiceException(io.jenkins.blueocean.commons.ServiceException) JwtConsumer(org.jose4j.jwt.consumer.JwtConsumer) JsonWebStructure(org.jose4j.jwx.JsonWebStructure)

Example 2 with NumericDate

use of org.jose4j.jwt.NumericDate in project cas by apereo.

the class OidcIdTokenGeneratorService method produceIdTokenClaims.

/**
 * Produce id token claims jwt claims.
 *
 * @param request       the request
 * @param accessTokenId the access token id
 * @param timeout       the timeout
 * @param service       the service
 * @param profile       the user profile
 * @param context       the context
 * @param responseType  the response type
 * @return the jwt claims
 */
protected JwtClaims produceIdTokenClaims(final HttpServletRequest request, final AccessToken accessTokenId, final long timeout, final OidcRegisteredService service, final UserProfile profile, final J2EContext context, final OAuth20ResponseTypes responseType) {
    final Authentication authentication = accessTokenId.getAuthentication();
    final Principal principal = authentication.getPrincipal();
    final OidcProperties oidc = casProperties.getAuthn().getOidc();
    final JwtClaims claims = new JwtClaims();
    claims.setJwtId(getOAuthServiceTicket(accessTokenId.getTicketGrantingTicket()).getKey());
    claims.setIssuer(oidc.getIssuer());
    claims.setAudience(service.getClientId());
    final NumericDate expirationDate = NumericDate.now();
    expirationDate.addSeconds(timeout);
    claims.setExpirationTime(expirationDate);
    claims.setIssuedAtToNow();
    claims.setNotBeforeMinutesInThePast(oidc.getSkew());
    claims.setSubject(principal.getId());
    final MultifactorAuthenticationProperties mfa = casProperties.getAuthn().getMfa();
    final Map<String, Object> attributes = authentication.getAttributes();
    if (attributes.containsKey(mfa.getAuthenticationContextAttribute())) {
        final Collection<Object> val = CollectionUtils.toCollection(attributes.get(mfa.getAuthenticationContextAttribute()));
        claims.setStringClaim(OidcConstants.ACR, val.iterator().next().toString());
    }
    if (attributes.containsKey(AuthenticationHandler.SUCCESSFUL_AUTHENTICATION_HANDLERS)) {
        final Collection<Object> val = CollectionUtils.toCollection(attributes.get(AuthenticationHandler.SUCCESSFUL_AUTHENTICATION_HANDLERS));
        claims.setStringListClaim(OidcConstants.AMR, val.toArray(new String[] {}));
    }
    claims.setClaim(OAuth20Constants.STATE, attributes.get(OAuth20Constants.STATE));
    claims.setClaim(OAuth20Constants.NONCE, attributes.get(OAuth20Constants.NONCE));
    claims.setClaim(OidcConstants.CLAIM_AT_HASH, generateAccessTokenHash(accessTokenId, service));
    principal.getAttributes().entrySet().stream().filter(entry -> oidc.getClaims().contains(entry.getKey())).forEach(entry -> claims.setClaim(entry.getKey(), entry.getValue()));
    if (!claims.hasClaim(OidcConstants.CLAIM_PREFERRED_USERNAME)) {
        claims.setClaim(OidcConstants.CLAIM_PREFERRED_USERNAME, profile.getId());
    }
    return claims;
}
Also used : CasConfigurationProperties(org.apereo.cas.configuration.CasConfigurationProperties) Arrays(java.util.Arrays) AlgorithmIdentifiers(org.jose4j.jws.AlgorithmIdentifiers) DigestUtils(org.apereo.cas.util.DigestUtils) HttpServletRequest(javax.servlet.http.HttpServletRequest) AuthenticationHandler(org.apereo.cas.authentication.AuthenticationHandler) MultifactorAuthenticationProperties(org.apereo.cas.configuration.model.support.mfa.MultifactorAuthenticationProperties) Authentication(org.apereo.cas.authentication.Authentication) OidcProperties(org.apereo.cas.configuration.model.support.oidc.OidcProperties) Map(java.util.Map) CollectionUtils(org.apereo.cas.util.CollectionUtils) TicketGrantingTicket(org.apereo.cas.ticket.TicketGrantingTicket) AccessToken(org.apereo.cas.ticket.accesstoken.AccessToken) ServicesManager(org.apereo.cas.services.ServicesManager) OAuth20Constants(org.apereo.cas.support.oauth.OAuth20Constants) OAuth20ResponseTypes(org.apereo.cas.support.oauth.OAuth20ResponseTypes) OidcConstants(org.apereo.cas.oidc.OidcConstants) Collection(java.util.Collection) HttpServletResponse(javax.servlet.http.HttpServletResponse) OAuthRegisteredService(org.apereo.cas.support.oauth.services.OAuthRegisteredService) ProfileManager(org.pac4j.core.profile.ProfileManager) StandardCharsets(java.nio.charset.StandardCharsets) Pac4jUtils(org.apereo.cas.util.Pac4jUtils) Slf4j(lombok.extern.slf4j.Slf4j) MessageDigestAlgorithms(org.apache.commons.codec.digest.MessageDigestAlgorithms) NumericDate(org.jose4j.jwt.NumericDate) OidcRegisteredService(org.apereo.cas.services.OidcRegisteredService) Stream(java.util.stream.Stream) JwtClaims(org.jose4j.jwt.JwtClaims) Service(org.apereo.cas.authentication.principal.Service) Entry(java.util.Map.Entry) J2EContext(org.pac4j.core.context.J2EContext) Optional(java.util.Optional) Preconditions(com.google.common.base.Preconditions) Principal(org.apereo.cas.authentication.principal.Principal) EncodingUtils(org.apereo.cas.util.EncodingUtils) UserProfile(org.pac4j.core.profile.UserProfile) NumericDate(org.jose4j.jwt.NumericDate) JwtClaims(org.jose4j.jwt.JwtClaims) Authentication(org.apereo.cas.authentication.Authentication) OidcProperties(org.apereo.cas.configuration.model.support.oidc.OidcProperties) MultifactorAuthenticationProperties(org.apereo.cas.configuration.model.support.mfa.MultifactorAuthenticationProperties) Principal(org.apereo.cas.authentication.principal.Principal)

Example 3 with NumericDate

use of org.jose4j.jwt.NumericDate in project kafka by apache.

the class ValidatorAccessTokenValidator method validate.

/**
 * Accepts an OAuth JWT access token in base-64 encoded format, validates, and returns an
 * OAuthBearerToken.
 *
 * @param accessToken Non-<code>null</code> JWT access token
 * @return {@link OAuthBearerToken}
 * @throws ValidateException Thrown on errors performing validation of given token
 */
@SuppressWarnings("unchecked")
public OAuthBearerToken validate(String accessToken) throws ValidateException {
    SerializedJwt serializedJwt = new SerializedJwt(accessToken);
    JwtContext jwt;
    try {
        jwt = jwtConsumer.process(serializedJwt.getToken());
    } catch (InvalidJwtException e) {
        throw new ValidateException(String.format("Could not validate the access token: %s", e.getMessage()), e);
    }
    JwtClaims claims = jwt.getJwtClaims();
    Object scopeRaw = getClaim(() -> claims.getClaimValue(scopeClaimName), scopeClaimName);
    Collection<String> scopeRawCollection;
    if (scopeRaw instanceof String)
        scopeRawCollection = Collections.singletonList((String) scopeRaw);
    else if (scopeRaw instanceof Collection)
        scopeRawCollection = (Collection<String>) scopeRaw;
    else
        scopeRawCollection = Collections.emptySet();
    NumericDate expirationRaw = getClaim(claims::getExpirationTime, ReservedClaimNames.EXPIRATION_TIME);
    String subRaw = getClaim(() -> claims.getStringClaimValue(subClaimName), subClaimName);
    NumericDate issuedAtRaw = getClaim(claims::getIssuedAt, ReservedClaimNames.ISSUED_AT);
    Set<String> scopes = ClaimValidationUtils.validateScopes(scopeClaimName, scopeRawCollection);
    long expiration = ClaimValidationUtils.validateExpiration(ReservedClaimNames.EXPIRATION_TIME, expirationRaw != null ? expirationRaw.getValueInMillis() : null);
    String sub = ClaimValidationUtils.validateSubject(subClaimName, subRaw);
    Long issuedAt = ClaimValidationUtils.validateIssuedAt(ReservedClaimNames.ISSUED_AT, issuedAtRaw != null ? issuedAtRaw.getValueInMillis() : null);
    OAuthBearerToken token = new BasicOAuthBearerToken(accessToken, scopes, expiration, sub, issuedAt);
    return token;
}
Also used : InvalidJwtException(org.jose4j.jwt.consumer.InvalidJwtException) NumericDate(org.jose4j.jwt.NumericDate) JwtClaims(org.jose4j.jwt.JwtClaims) JwtContext(org.jose4j.jwt.consumer.JwtContext) OAuthBearerToken(org.apache.kafka.common.security.oauthbearer.OAuthBearerToken) Collection(java.util.Collection)

Example 4 with NumericDate

use of org.jose4j.jwt.NumericDate in project blueocean-plugin by jenkinsci.

the class JwtTokenVerifierImpl method validate.

/**
 * @return
 *      null if the JWT token is not present
 * @throws Exception
 *      if the JWT token is present but invalid
 */
@CheckForNull
private Authentication validate(HttpServletRequest request) {
    String authHeader = request.getHeader("Authorization");
    if (authHeader == null || !authHeader.startsWith("Bearer ")) {
        return null;
    }
    String token = authHeader.substring("Bearer ".length());
    JsonWebStructure jws = parse(token);
    if (jws == null) {
        return null;
    }
    try {
        String alg = jws.getAlgorithmHeaderValue();
        if (alg == null || !alg.equals(RSA_USING_SHA256)) {
            logger.error(String.format("Invalid JWT token: unsupported algorithm in header, found %s, expected %s", alg, RSA_USING_SHA256));
            throw new ServiceException.UnauthorizedException("Invalid JWT token");
        }
        String kid = jws.getKeyIdHeaderValue();
        if (kid == null) {
            logger.error("Invalid JWT token: missing kid");
            throw new ServiceException.UnauthorizedException("Invalid JWT token");
        }
        SigningPublicKey publicKey = JwtSigningKeyProvider.toPublicKey(kid);
        if (publicKey == null) {
            throw new ServiceException.UnexpectedErrorException("Invalid kid=" + kid);
        }
        JwtConsumer jwtConsumer = new JwtConsumerBuilder().setRequireExpirationTime().setRequireJwtId().setAllowedClockSkewInSeconds(// allow some leeway in validating time based claims to account for clock skew
        30).setRequireSubject().setVerificationKey(// verify the sign with the public key
        publicKey.getKey()).build();
        try {
            JwtContext context = jwtConsumer.process(token);
            JwtClaims claims = context.getJwtClaims();
            String subject = claims.getSubject();
            if (subject.equals("anonymous")) {
                // if anonymous, we do not bother checking expiration
                return Jenkins.ANONYMOUS2;
            } else {
                // If not anonymous user, get Authentication object associated with this claim
                // We give a change to the authentication store to inspect the claims and if expired it might
                // do cleanup of associated Authentication object for example.
                JwtAuthenticationStore authenticationStore = getJwtStore(claims.getClaimsMap());
                Authentication authentication = authenticationStore.getAuthentication(claims.getClaimsMap());
                // Now check if token expired
                NumericDate expirationTime = claims.getExpirationTime();
                if (expirationTime.isBefore(NumericDate.now())) {
                    throw new ServiceException.UnauthorizedException("Invalid JWT token: expired");
                }
                return authentication;
            }
        } catch (InvalidJwtException e) {
            logger.error("Invalid JWT token: " + e.getMessage(), e);
            throw new ServiceException.UnauthorizedException("Invalid JWT token");
        } catch (MalformedClaimException e) {
            logger.error(String.format("Error reading sub header for token %s", jws.getPayload()), e);
            throw new ServiceException.UnauthorizedException("Invalid JWT token: malformed claim");
        }
    } catch (JoseException e) {
        logger.error("Error parsing JWT token: " + e.getMessage(), e);
        throw new ServiceException.UnauthorizedException("Invalid JWT Token: " + e.getMessage());
    }
}
Also used : InvalidJwtException(org.jose4j.jwt.consumer.InvalidJwtException) SigningPublicKey(io.jenkins.blueocean.auth.jwt.SigningPublicKey) NumericDate(org.jose4j.jwt.NumericDate) JwtClaims(org.jose4j.jwt.JwtClaims) JwtConsumerBuilder(org.jose4j.jwt.consumer.JwtConsumerBuilder) JoseException(org.jose4j.lang.JoseException) JwtContext(org.jose4j.jwt.consumer.JwtContext) JwtAuthenticationStore(io.jenkins.blueocean.auth.jwt.JwtAuthenticationStore) MalformedClaimException(org.jose4j.jwt.MalformedClaimException) ServiceException(io.jenkins.blueocean.commons.ServiceException) Authentication(org.springframework.security.core.Authentication) JwtConsumer(org.jose4j.jwt.consumer.JwtConsumer) JsonWebStructure(org.jose4j.jwx.JsonWebStructure) CheckForNull(javax.annotation.CheckForNull)

Example 5 with NumericDate

use of org.jose4j.jwt.NumericDate in project box-java-sdk by box.

the class BoxDeveloperEditionAPIConnection method authenticate.

/**
 * Authenticates the API connection for Box Developer Edition.
 */
public void authenticate() {
    URL url;
    try {
        url = new URL(this.getTokenURL());
    } catch (MalformedURLException e) {
        assert false : "An invalid token URL indicates a bug in the SDK.";
        throw new RuntimeException("An invalid token URL indicates a bug in the SDK.", e);
    }
    this.backoffCounter.reset(this.getMaxRetryAttempts() + 1);
    NumericDate jwtTime = null;
    String jwtAssertion;
    String urlParameters;
    BoxAPIRequest request;
    String json = null;
    final BoxLogger logger = BoxLogger.defaultLogger();
    while (this.backoffCounter.getAttemptsRemaining() > 0) {
        // Reconstruct the JWT assertion, which regenerates the jti claim, with the new "current" time
        jwtAssertion = this.constructJWTAssertion(jwtTime);
        urlParameters = String.format(JWT_GRANT_TYPE, this.getClientID(), this.getClientSecret(), jwtAssertion);
        request = new BoxAPIRequest(this, url, "POST");
        request.shouldAuthenticate(false);
        request.setBody(urlParameters);
        try {
            BoxJSONResponse response = (BoxJSONResponse) request.sendWithoutRetry();
            json = response.getJSON();
            break;
        } catch (BoxAPIException apiException) {
            long responseReceivedTime = System.currentTimeMillis();
            if (!this.backoffCounter.decrement() || (!BoxAPIRequest.isRequestRetryable(apiException) && !BoxAPIRequest.isResponseRetryable(apiException.getResponseCode(), apiException))) {
                throw apiException;
            }
            logger.warn(String.format("Retrying authentication request due to transient error status=%d body=%s", apiException.getResponseCode(), apiException.getResponse()));
            try {
                List<String> retryAfterHeader = apiException.getHeaders().get("Retry-After");
                if (retryAfterHeader == null) {
                    this.backoffCounter.waitBackoff();
                } else {
                    int retryAfterDelay = Integer.parseInt(retryAfterHeader.get(0)) * 1000;
                    this.backoffCounter.waitBackoff(retryAfterDelay);
                }
            } catch (InterruptedException interruptedException) {
                Thread.currentThread().interrupt();
                throw apiException;
            }
            long endWaitTime = System.currentTimeMillis();
            long secondsSinceResponseReceived = (endWaitTime - responseReceivedTime) / 1000;
            try {
                // Use the Date advertised by the Box server in the exception
                // as the current time to synchronize clocks
                jwtTime = this.getDateForJWTConstruction(apiException, secondsSinceResponseReceived);
            } catch (Exception e) {
                throw apiException;
            }
        }
    }
    if (json == null) {
        throw new RuntimeException("Unable to read authentication response in SDK.");
    }
    JsonObject jsonObject = Json.parse(json).asObject();
    this.setAccessToken(jsonObject.get("access_token").asString());
    this.setLastRefresh(System.currentTimeMillis());
    this.setExpires(jsonObject.get("expires_in").asLong() * 1000);
    // if token cache is specified, save to cache
    if (this.accessTokenCache != null) {
        String key = this.getAccessTokenCacheKey();
        JsonObject accessTokenCacheInfo = new JsonObject().add("accessToken", this.getAccessToken()).add("lastRefresh", this.getLastRefresh()).add("expires", this.getExpires());
        this.accessTokenCache.put(key, accessTokenCacheInfo.toString());
    }
}
Also used : MalformedURLException(java.net.MalformedURLException) NumericDate(org.jose4j.jwt.NumericDate) JsonObject(com.eclipsesource.json.JsonObject) URL(java.net.URL) OperatorCreationException(org.bouncycastle.operator.OperatorCreationException) ParseException(java.text.ParseException) PKCSException(org.bouncycastle.pkcs.PKCSException) MalformedURLException(java.net.MalformedURLException) IOException(java.io.IOException) JoseException(org.jose4j.lang.JoseException) List(java.util.List)

Aggregations

NumericDate (org.jose4j.jwt.NumericDate)7 JwtClaims (org.jose4j.jwt.JwtClaims)5 JoseException (org.jose4j.lang.JoseException)4 InvalidJwtException (org.jose4j.jwt.consumer.InvalidJwtException)3 JwtContext (org.jose4j.jwt.consumer.JwtContext)3 ServiceException (io.jenkins.blueocean.commons.ServiceException)2 IOException (java.io.IOException)2 ParseException (java.text.ParseException)2 Collection (java.util.Collection)2 MalformedClaimException (org.jose4j.jwt.MalformedClaimException)2 JwtConsumer (org.jose4j.jwt.consumer.JwtConsumer)2 JwtConsumerBuilder (org.jose4j.jwt.consumer.JwtConsumerBuilder)2 JsonWebStructure (org.jose4j.jwx.JsonWebStructure)2 JsonObject (com.eclipsesource.json.JsonObject)1 Preconditions (com.google.common.base.Preconditions)1 JwtAuthenticationStore (io.jenkins.blueocean.auth.jwt.JwtAuthenticationStore)1 JwtToken (io.jenkins.blueocean.auth.jwt.JwtToken)1 SigningPublicKey (io.jenkins.blueocean.auth.jwt.SigningPublicKey)1 MalformedURLException (java.net.MalformedURLException)1 URL (java.net.URL)1