All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.docusign.esign.client.auth.JWTUtils Maven / Gradle / Ivy

There is a newer version: 3.20.0
Show newest version
package com.docusign.esign.client.auth;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;

/** JWTUtils class. */
public class JWTUtils {

  /**
   * Helper method to create a JWT token for the JWT flow.
   *
   * @param rsaPrivateKey the byte contents of the RSA private key
   * @param oAuthBasePath DocuSign OAuth base path (account-d.docusign.com for the developer sandbox
   *     and account.docusign.com for the production platform)
   * @param clientId DocuSign OAuth Client Id (AKA Integrator Key)
   * @param userId DocuSign user Id to be impersonated (This is a UUID)
   * @param expiresIn number of seconds remaining before the JWT assertion is considered as invalid
   * @param scopes space-separated string that represents the list of scopes to grant to the OAuth
   *     token.
   * @return a fresh JWT token
   * @throws IllegalArgumentException if one of the arguments is invalid
   * @throws JWTCreationException if not able to create a JWT token from the input parameters
   * @throws IOException if there is an issue with either the public or private file
   */
  public static String generateJWTAssertionFromByteArray(
      byte[] rsaPrivateKey,
      String oAuthBasePath,
      String clientId,
      String userId,
      long expiresIn,
      String scopes)
      throws IllegalArgumentException, JWTCreationException, IOException {
    if (expiresIn <= 0L) {
      throw new IllegalArgumentException("expiresIn should be a non-negative value");
    }
    if (rsaPrivateKey == null || rsaPrivateKey.length == 0) {
      throw new IllegalArgumentException("rsaPrivateKey byte array is empty");
    }
    if (oAuthBasePath == null
        || "".equals(oAuthBasePath)
        || clientId == null
        || "".equals(clientId)) {
      throw new IllegalArgumentException("One of the arguments is null or empty");
    }

    RSAPrivateKey privateKey = readPrivateKeyFromByteArray(rsaPrivateKey, "RSA");
    Algorithm algorithm = Algorithm.RSA256(null, privateKey);
    long now = System.currentTimeMillis();
    JWTCreator.Builder builder =
        JWT.create()
            .withIssuer(clientId)
            .withAudience(oAuthBasePath)
            .withIssuedAt(new Date(now))
            .withClaim("scope", scopes)
            .withExpiresAt(new Date(now + expiresIn * 1000));
    if (userId != null && userId != "") {
      builder = builder.withSubject(userId);
    }
    return builder.sign(algorithm);
  }

  /**
   * Helper method to create a JWT token for the JWT flow.
   *
   * @param publicKeyFilename the filename of the RSA public key
   * @param privateKeyFilename the filename of the RSA private key
   * @param oAuthBasePath DocuSign OAuth base path (account-d.docusign.com for the developer sandbox
   *     and account.docusign.com for the production platform)
   * @param clientId DocuSign OAuth Client Id (AKA Integrator Key)
   * @param userId DocuSign user Id to be impersonated (This is a UUID)
   * @param expiresIn number of seconds remaining before the JWT assertion is considered as invalid
   * @return a fresh JWT token
   * @throws JWTCreationException if not able to create a JWT token from the input parameters
   * @throws IOException if there is an issue with either the public or private file
   */
  public static String generateJWTAssertion(
      String publicKeyFilename,
      String privateKeyFilename,
      String oAuthBasePath,
      String clientId,
      String userId,
      long expiresIn)
      throws JWTCreationException, IOException {
    String token = null;
    if (expiresIn <= 0L) {
      throw new IllegalArgumentException("expiresIn should be a non-negative value");
    }
    if (publicKeyFilename == null
        || "".equals(publicKeyFilename)
        || privateKeyFilename == null
        || "".equals(privateKeyFilename)
        || oAuthBasePath == null
        || "".equals(oAuthBasePath)
        || clientId == null
        || "".equals(clientId)
        || userId == null
        || "".equals(userId)) {
      throw new IllegalArgumentException("One of the arguments is null or empty");
    }

    try {
      RSAPublicKey publicKey = readPublicKeyFromFile(publicKeyFilename, "RSA");
      RSAPrivateKey privateKey = readPrivateKeyFromFile(privateKeyFilename, "RSA");
      Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
      long now = System.currentTimeMillis();
      token =
          JWT.create()
              .withIssuer(clientId)
              .withSubject(userId)
              .withAudience(oAuthBasePath)
              .withNotBefore(new Date(now))
              .withExpiresAt(new Date(now + expiresIn * 1000))
              .withClaim("scope", "signature")
              .sign(algorithm);
    } catch (JWTCreationException e) {
      throw e;
    } catch (IOException e) {
      throw e;
    }

    return token;
  }

  private static RSAPublicKey readPublicKeyFromFile(String filepath, String algorithm)
      throws IOException {
    File pemFile = new File(filepath);
    if (!pemFile.isFile() || !pemFile.exists()) {
      throw new FileNotFoundException(
          String.format("The file '%s' doesn't exist.", pemFile.getAbsolutePath()));
    }
    PemReader reader = new PemReader(new FileReader(pemFile));
    try {
      PemObject pemObject = reader.readPemObject();
      byte[] bytes = pemObject.getContent();
      RSAPublicKey publicKey = null;
      try {
        KeyFactory kf = KeyFactory.getInstance(algorithm);
        EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
        publicKey = (RSAPublicKey) kf.generatePublic(keySpec);
      } catch (NoSuchAlgorithmException e) {
        System.out.println(
            "Could not reconstruct the public key, the given algorithm could not be found.");
      } catch (InvalidKeySpecException e) {
        System.out.println("Could not reconstruct the public key");
      }

      return publicKey;
    } finally {
      reader.close();
    }
  }

  private static RSAPrivateKey readPrivateKeyFromFile(String filepath, String algorithm)
      throws IOException {
    File pemFile = new File(filepath);
    if (!pemFile.isFile() || !pemFile.exists()) {
      throw new FileNotFoundException(
          String.format("The file '%s' doesn't exist.", pemFile.getAbsolutePath()));
    }
    PemReader reader = new PemReader(new FileReader(pemFile));
    try {
      PemObject pemObject = reader.readPemObject();
      byte[] bytes = pemObject.getContent();
      RSAPrivateKey privateKey = null;
      try {
        Security.addProvider(new BouncyCastleProvider());
        KeyFactory kf = KeyFactory.getInstance(algorithm, "BC");
        EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
        privateKey = (RSAPrivateKey) kf.generatePrivate(keySpec);
      } catch (NoSuchAlgorithmException e) {
        System.out.println(
            "Could not reconstruct the private key, the given algorithm could not be found.");
      } catch (InvalidKeySpecException e) {
        System.out.println("Could not reconstruct the private key");
      } catch (NoSuchProviderException e) {
        System.out.println("Could not reconstruct the private key, invalid provider.");
      }

      return privateKey;
    } finally {
      reader.close();
    }
  }

  private static RSAPrivateKey readPrivateKeyFromByteArray(byte[] privateKeyBytes, String algorithm)
      throws IOException {
    PemReader reader = new PemReader(new StringReader(new String(privateKeyBytes)));
    try {
      PemObject pemObject = reader.readPemObject();
      byte[] bytes = pemObject.getContent();
      RSAPrivateKey privateKey = null;
      try {
        Security.addProvider(new BouncyCastleProvider());
        KeyFactory kf = KeyFactory.getInstance(algorithm, "BC");
        EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
        privateKey = (RSAPrivateKey) kf.generatePrivate(keySpec);
      } catch (NoSuchAlgorithmException e) {
        System.out.println(
            "Could not reconstruct the private key, the given algorithm could not be found.");
      } catch (InvalidKeySpecException e) {
        System.out.println("Could not reconstruct the private key");
      } catch (NoSuchProviderException e) {
        System.out.println("Could not reconstruct the private key, invalid provider.");
      }

      return privateKey;
    } finally {
      reader.close();
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy