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

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

Go to download

The official Docusign eSignature JAVA client is based on version 2.1 of the Docusign REST API and provides libraries for JAVA application integration. It is recommended that you use this version of the library for new development.

There is a newer version: 6.0.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 {
    return generateJWTAssertion(
        publicKeyFilename,
        privateKeyFilename,
        oAuthBasePath,
        clientId,
        userId,
        expiresIn,
        "signature");
  }

  /**
   * 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
   * @param scopes space-separated string that represents the list of scopes to grant to the OAuth
   *     token.
   * @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,
      String scopes)
      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", scopes)
              .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