Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
* one or more contributor license agreements. Licensed under a proprietary license. See the
* License.txt file for more information. You may not use this file except in compliance with the
* proprietary license.
*/
package io.camunda.identity.sdk.authentication;
import static io.camunda.identity.sdk.utility.UrlUtility.combinePaths;
import static org.apache.commons.lang3.StringUtils.isNoneBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import com.auth0.jwk.InvalidPublicKeyException;
import com.auth0.jwk.Jwk;
import com.auth0.jwk.JwkException;
import com.auth0.jwk.JwkProvider;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import io.camunda.identity.sdk.IdentityConfiguration;
import io.camunda.identity.sdk.authentication.exception.InvalidClaimException;
import io.camunda.identity.sdk.authentication.exception.InvalidSignatureException;
import io.camunda.identity.sdk.authentication.exception.JsonWebKeyException;
import io.camunda.identity.sdk.authentication.exception.TokenDecodeException;
import io.camunda.identity.sdk.authentication.exception.TokenExpiredException;
import io.camunda.identity.sdk.authentication.exception.TokenVerificationException;
import io.camunda.identity.sdk.cache.ClientTokenCache;
import io.camunda.identity.sdk.exception.IdentityException;
import io.camunda.identity.sdk.impl.GenericSingleSignOutBuilder;
import io.camunda.identity.sdk.impl.dto.WellKnownConfiguration;
import io.camunda.identity.sdk.impl.rest.RestClient;
import io.camunda.identity.sdk.impl.rest.request.GroupRequest;
import java.net.URI;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.apache.commons.lang3.NotImplementedException;
import org.ehcache.Cache;
/**
* The Authentication class provides functionality to authenticate a user with Identity
* and verify access tokens.
*/
public abstract class AbstractAuthentication implements Authentication {
public static final long JWKS_CACHE_SIZE = 5L;
public static final long JWKS_CACHE_LIFETIME_DAYS = 7L;
public static final String WELL_KNOWN_PATH = "/.well-known/openid-configuration";
static final String GROUPS_PATH = "/api/groups";
static final String FOR_TOKEN_PATH = "/for-token";
protected final IdentityConfiguration configuration;
protected final Cache tokenCache = new ClientTokenCache().getCache();
protected final RestClient restClient;
protected AbstractAuthentication(final IdentityConfiguration configuration,
final RestClient restClient) {
this.configuration = configuration;
this.restClient = restClient;
}
@Override
public boolean isAvailable() {
return isNoneBlank(
configuration.getIssuer(),
configuration.getIssuerBackendUrl(),
configuration.getClientId(),
configuration.getClientSecret()
);
}
/**
* Requests a client token from the cache if available. If
* no token is found with the required audience, a new token
* will be requested from the authentication provider and stored.
*
* @param audience the audience of the resource server
* @return the tokens
* @throws IdentityException if case of a failure
*/
@Override
public Tokens requestToken(final String audience) {
if (!tokenCache.containsKey(audience)) {
tokenCache.put(audience, requestFreshToken(audience));
}
return tokenCache.get(audience);
}
/**
* Decodes a token. Can be used to access tokens data without validation
*
* @param token token in JWT format
* @return decoded token
* @throws TokenDecodeException the token can not be decoded
*/
@Override
public DecodedJWT decodeJWT(final String token) {
try {
return JWT.decode(token);
} catch (final com.auth0.jwt.exceptions.JWTDecodeException e) {
throw new TokenDecodeException(e);
}
}
@Override
public AccessToken verifyTokenIgnoringAudience(final String token) {
return verifyToken(token, null, null);
}
/**
* Logs out from Identity backend based on the configuration, one of these cases is possible:
* 1. The refresh token is not empty and OAuth Provider (OP) has provided a revoke endpoint,
* then see {@link #revokeToken}, in this case the method return an empty Optional.
* 2. end-session endpoint is available, so in this case the url for logout is returned and
* client should handle the redirection
* 3. otherwise this method will throw exception
*
* @param refreshToken refresh token used for the request
* @param callbackUrl the URL to redirect to post-SSO if supported by SSO provider
* @throws IdentityException if token revocation has failed or neither revoke
* @throws NotImplementedException if case 3 happens
*/
@Override
public Optional singleSignOut(final String refreshToken, final String callbackUrl) {
if (isRevokeAvailable() && isNotBlank(refreshToken)) {
revokeToken(refreshToken);
return Optional.empty();
} else if (isSingleSignOutAvailable()) {
return Optional.of(generateSingleSignOutUri(callbackUrl));
}
throw new NotImplementedException(
"single sign out is not implemented for this case");
}
/**
* Verifies the validity of the passed token. Following checks will be performed:
*
*
* @param token the token
* @return the decoded jwt
* @throws TokenDecodeException the token can not be decoded
* @throws InvalidSignatureException the token's signature is invalid
* @throws TokenExpiredException the token has expired
* @throws InvalidClaimException the provided claim is invalid
* @throws JsonWebKeyException the JWK needed to verify token's signature can not be
* retrieved
*/
@Override
public AccessToken verifyToken(final String token) {
return verifyToken(token, configuration.getAudience(), null);
}
/**
* Verifies the validity of the passed token and organisation. Following checks will be performed:
*
*
* @param token the token
* @param organizationId the organisation of the token
* @return the decoded jwt
* @throws TokenDecodeException the token can not be decoded
* @throws InvalidSignatureException the token's signature is invalid
* @throws TokenExpiredException the token has expired
* @throws InvalidClaimException the provided claim is invalid
* @throws JsonWebKeyException the JWK needed to verify token's signature can not be
* retrieved
*/
@Override
public AccessToken verifyToken(final String token, final String organizationId) {
return verifyToken(token, configuration.getAudience(), organizationId);
}
/**
* Verifies the validity of the passed token. Following checks will be performed:
*