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

info.setmy.jwt.services.JWTService Maven / Gradle / Ivy

package info.setmy.jwt.services;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import info.setmy.jwt.exceptions.UncheckedException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import org.apache.commons.io.IOUtils;

/**
 *
 * @author Imre Tabur
 */
public class JWTService {

    private static final Map SERVICES_MAP = new HashMap<>();

    private final String serviceName;

    private final String issuer;

    private final String key;

    private final Integer expirationMinutes;

    private final String algorithmName;

    private final String publicKeyFileName;

    private final String privateKeyFileName;

    private Algorithm algorithm;

    private RSAPublicKey rsaPublicKey;

    private RSAPrivateKey rsaPrivateKey;

    public JWTService(
            final String serviceName,
            final String issuer,
            final String key,
            final String algorithmName,
            final Integer expirationMinutes
    ) {
        this.serviceName = serviceName;
        this.issuer = issuer;
        this.key = key;
        this.expirationMinutes = expirationMinutes;
        this.algorithmName = algorithmName;
        this.publicKeyFileName = null;
        this.privateKeyFileName = null;
    }

    public JWTService(
            final String serviceName,
            final String issuer,
            final String privateKeyFileName,
            final String publicKeyFileName,
            final String algorithmName,
            final Integer expirationMinutes
    ) {
        this.serviceName = serviceName;
        this.issuer = issuer;
        this.key = null;
        this.expirationMinutes = expirationMinutes;
        this.algorithmName = algorithmName;
        this.privateKeyFileName = privateKeyFileName;
        this.publicKeyFileName = publicKeyFileName;
    }

    public void init() {
        final JWTService instance = SERVICES_MAP.get(getServiceName());
        if (instance != null) {
            throw new UncheckedException(String.format("Instance of service by name \"%s\" exists!", getServiceName()));
        }
        try {
            algorithm = findAlgorithm();
        } catch (IllegalArgumentException ex) {
            throw new UncheckedException("Illegal arguments for HMAC256 algorithm key", ex);
        } catch (UnsupportedEncodingException ex) {
            throw new UncheckedException("Un supported encoding", ex);
        } catch (NoSuchAlgorithmException ex) {
            throw new UncheckedException("Algorithm is not supported", ex);
        } catch (NoSuchPaddingException ex) {
            throw new UncheckedException("Padding is not supported", ex);
        } catch (InvalidKeySpecException ex) {
            throw new UncheckedException("Invalid key spec", ex);
        } catch (InvalidKeyException ex) {
            throw new UncheckedException("Invalid key", ex);
        }
        SERVICES_MAP.put(getServiceName(), this);
    }

    Algorithm findAlgorithm() throws IllegalArgumentException, UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException {
        if (algorithmName == null) {
            throw new UncheckedException("Algorithm name should be set");
        }
        switch (algorithmName) {
            case "HS256":
                return Algorithm.HMAC256(this.getKey());
            case "RS256":
                this.rsaPublicKey = readPublicKey();
                this.rsaPrivateKey = readPrivateKey();
                return Algorithm.RSA256(rsaPublicKey, rsaPrivateKey);
            default:
        }
        throw new UncheckedException(String.format("Algorithm \"%s\" is not supported!", algorithmName));
    }

    RSAPublicKey readPublicKey() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException {
        try {
            final String publicKey = IOUtils.toString(new FileInputStream(publicKeyFileName), Charset.forName("UTF-8"));
            final String cleanedPublicKey = cleanPublicKeyParts(publicKey);
            final byte[] data = decodePEMToBytes(cleanedPublicKey);
            final Cipher cipher = Cipher.getInstance("RSA");
            final RSAPublicKey resultKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(data));
            cipher.init(Cipher.ENCRYPT_MODE, resultKey);
            return resultKey;
        } catch (FileNotFoundException ex) {
            throw new UncheckedException(String.format("Can't read keyfle \"%s\".", publicKeyFileName), ex);
        } catch (IOException ex) {
            throw new UncheckedException(String.format("Can't read keyfle \"%s\".", publicKeyFileName), ex);
        }
    }

    RSAPrivateKey readPrivateKey() {
        try {
            final PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(IOUtils.toByteArray(new FileInputStream(privateKeyFileName)));
            return (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(pkcs8EncodedKeySpec);
        } catch (NoSuchAlgorithmException | IOException | InvalidKeySpecException ex) {
            throw new UncheckedException(String.format("Can't read keyfle \"%s\".", privateKeyFileName), ex);
        }
    }

    String cleanPublicKeyParts(final String pemDataString) {
        final String cleanData = pemDataString
                .replace("-----BEGIN PUBLIC KEY-----\n", "")
                .replace("\n", "")
                .replace("-----END PUBLIC KEY-----", "");
        return cleanData;
    }

    byte[] decodePEMToBytes(final String cleanedKey) {
        final byte[] bytes = Base64.getDecoder().decode(cleanedKey);
        return bytes;
    }

    public static JWTService instance(final String serviceName) {
        return SERVICES_MAP.get(serviceName);
    }

    public Algorithm getAlgorithm() {
        return algorithm;
    }

    public String getIssuer() {
        return issuer;
    }

    public JWTCreator.Builder create() {
        return JWT.create();
    }

    public String getKey() {
        return key;
    }

    public Integer getExpirationMinutes() {
        return expirationMinutes;
    }

    public String getServiceName() {
        return serviceName;
    }

    public String getAlgorithmName() {
        return algorithmName;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy