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

io.smallrye.jwt.build.impl.JwtSignatureImpl Maven / Gradle / Ivy

The newest version!
package io.smallrye.jwt.build.impl;

import java.io.InputStream;
import java.security.Key;
import java.security.PrivateKey;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.RSAPrivateKey;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.SecretKey;

import org.eclipse.microprofile.jwt.Claims;
import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwx.HeaderParameterNames;

import io.smallrye.jwt.algorithm.SignatureAlgorithm;
import io.smallrye.jwt.build.JwtEncryptionBuilder;
import io.smallrye.jwt.build.JwtSignature;
import io.smallrye.jwt.build.JwtSignatureException;
import io.smallrye.jwt.util.KeyUtils;
import io.smallrye.jwt.util.ResourceUtils;

/**
 * Default JWT Signature implementation
 */
class JwtSignatureImpl implements JwtSignature {
    private static final String ED_EC_PRIVATE_KEY_INTERFACE = "java.security.interfaces.EdECPrivateKey";

    JwtClaims claims = new JwtClaims();
    Map headers = new HashMap<>();
    Long tokenLifespan;
    Key configuredPemKey;

    JwtSignatureImpl() {
    }

    JwtSignatureImpl(JwtClaims claims) {
        this.claims = claims;
    }

    /**
     * {@inheritDoc}
     */
    public String sign(PrivateKey signingKey) throws JwtSignatureException {
        return signInternal(signingKey);
    }

    /**
     * {@inheritDoc}
     */
    public String sign(SecretKey signingKey) throws JwtSignatureException {
        return signInternal(signingKey);
    }

    /**
     * {@inheritDoc}
     */
    public String sign(String keyLocation) throws JwtSignatureException {
        try {
            return signInternal(getSigningKeyFromKeyContent(getKeyContentFromLocation(keyLocation)));
        } catch (JwtSignatureException ex) {
            throw ex;
        } catch (Exception ex) {
            throw ImplMessages.msg.signatureException(ex);
        }
    }

    /**
     * {@inheritDoc}
     */
    public String sign() throws JwtSignatureException {
        try {
            Key key = configuredPemKey;
            if (key == null) {
                String keyLocation = JwtBuildUtils.getConfigProperty(JwtBuildUtils.SIGN_KEY_LOCATION_PROPERTY, String.class);
                if (keyLocation != null) {
                    key = JwtBuildUtils.readPrivateKeyFromKeystore(keyLocation.trim());
                    if (key == null) {
                        InputStream is = ResourceUtils.getResourceStream(keyLocation.trim());
                        if (is != null) {
                            try (InputStream keyStream = is) {
                                key = getSigningKeyFromKeyContent(new String(ResourceUtils.readBytes(keyStream)));
                            }
                        }
                    }
                } else {
                    key = JwtBuildUtils.readPrivateKeyFromKeystore(null);
                    if (key == null) {
                        String keyContent = JwtBuildUtils.getConfigProperty(JwtBuildUtils.SIGN_KEY_PROPERTY, String.class);
                        if (keyContent != null) {
                            key = getSigningKeyFromKeyContent(keyContent);
                        } else {
                            throw ImplMessages.msg.signKeyNotConfigured();
                        }
                    }
                }
            }
            if (key == null) {
                throw ImplMessages.msg.signingKeyCanNotBeCreatedFromContent();
            }

            return signInternal(key);
        } catch (JwtSignatureException ex) {
            throw ex;
        } catch (Exception ex) {
            throw ImplMessages.msg.signatureException(ex);
        } finally {
            removeJti();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String signWithSecret(String secret) throws JwtSignatureException {
        return sign(KeyUtils.createSecretKeyFromSecret(secret));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public JwtEncryptionBuilder innerSign(PrivateKey signingKey) throws JwtSignatureException {
        return new JwtEncryptionImpl(sign(signingKey), true);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public JwtEncryptionBuilder innerSign(SecretKey signingKey) throws JwtSignatureException {
        return new JwtEncryptionImpl(sign(signingKey), true);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public JwtEncryptionBuilder innerSign(String keyLocation) throws JwtSignatureException {
        return new JwtEncryptionImpl(sign(keyLocation), true);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public JwtEncryptionBuilder innerSign() throws JwtSignatureException {
        try {
            return new JwtEncryptionImpl(sign(), true);
        } finally {
            removeJti();
        }
    }

    @Override
    public JwtEncryptionBuilder innerSignWithSecret(String secret) throws JwtSignatureException {
        return innerSign(KeyUtils.createSecretKeyFromSecret(secret));
    }

    private String signInternal(Key signingKey) {
        if (signingKey == null) {
            throw ImplMessages.msg.signingKeyIsNull();
        }
        JwtBuildUtils.setDefaultJwtClaims(claims, tokenLifespan);
        JsonWebSignature jws = new JsonWebSignature();
        for (Map.Entry entry : headers.entrySet()) {
            jws.setHeader(entry.getKey(), entry.getValue());
        }
        if (!headers.containsKey(HeaderParameterNames.TYPE)) {
            jws.setHeader(HeaderParameterNames.TYPE, "JWT");
        }

        String algorithm = getSignatureAlgorithm(signingKey);

        jws.setAlgorithmHeaderValue(algorithm);

        jws.setPayload(claims.toJson());
        jws.setKey(signingKey);
        if (isRelaxKeyValidation()) {
            jws.setDoKeyValidation(false);
        }
        try {
            return jws.getCompactSerialization();
        } catch (Exception ex) {
            throw ImplMessages.msg.signJwtTokenFailed(ex.getMessage(), ex);
        }
    }

    private boolean isRelaxKeyValidation() {
        return JwtBuildUtils.getConfigProperty(JwtBuildUtils.SIGN_KEY_RELAX_VALIDATION_PROPERTY, Boolean.class, false);
    }

    private String getConfiguredSignatureAlgorithm() {
        String alg = (String) headers.get(HeaderParameterNames.ALGORITHM);
        if (alg == null) {
            try {
                alg = JwtBuildUtils.getConfigProperty(JwtBuildUtils.NEW_TOKEN_SIGNATURE_ALG_PROPERTY, String.class);
                if (alg != null) {
                    alg = SignatureAlgorithm.fromAlgorithm(alg).getAlgorithm();
                    headers.put(HeaderParameterNames.ALGORITHM, alg);
                }
            } catch (Exception ex) {
                throw ImplMessages.msg.unsupportedSignatureAlgorithm(alg, ex);
            }
        }
        return alg;
    }

    private String getSignatureAlgorithm(Key signingKey) {
        String alg = getConfiguredSignatureAlgorithm();
        if ("none".equals(alg)) {
            throw ImplMessages.msg.noneSignatureAlgorithmUnsupported();
        }
        if (signingKey instanceof RSAPrivateKey) {
            if (alg == null) {
                return SignatureAlgorithm.RS256.name();
            } else if (alg.startsWith("RS") || alg.startsWith("PS")) {
                return alg;
            }
        } else if (signingKey instanceof ECPrivateKey) {
            if (alg == null) {
                return SignatureAlgorithm.ES256.name();
            } else if (alg.startsWith("ES")) {
                return alg;
            }
        } else if (signingKey instanceof SecretKey) {
            if (alg == null) {
                return SignatureAlgorithm.HS256.name();
            } else if (alg.startsWith("HS")) {
                return alg;
            }
        } else if (signingKey instanceof PrivateKey) {
            // for example, sun.security.pkcs11.P11Key$P11PrivateKey
            if (isEdECPrivateKey(signingKey)) {
                if (alg == null || alg.equals(SignatureAlgorithm.EDDSA.getAlgorithm())) {
                    return SignatureAlgorithm.EDDSA.getAlgorithm();
                }
            }
            if (alg == null) {
                return SignatureAlgorithm.RS256.name();
            } else if (alg.startsWith("RS") || alg.startsWith("PS") || alg.startsWith("ES")) {
                return alg;
            }
        }
        throw ImplMessages.msg.unsupportedSignatureAlgorithm(signingKey.getAlgorithm());
    }

    private static boolean isEdECPrivateKey(Key signingKey) {
        return KeyUtils.isSupportedKey(signingKey, ED_EC_PRIVATE_KEY_INTERFACE);
    }

    static String getKeyContentFromLocation(String keyLocation) {
        try {
            return KeyUtils.readKeyContent(keyLocation);
        } catch (Exception ex) {
            throw ImplMessages.msg.signingKeyCanNotBeLoadedFromLocation(keyLocation, ex);
        }
    }

    Key getSigningKeyFromKeyContent(String keyContent) {
        String kid = (String) headers.get(HeaderParameterNames.KEY_ID);
        String alg = getConfiguredSignatureAlgorithm();

        SignatureAlgorithm algorithm;
        try {
            algorithm = (alg == null ? null : SignatureAlgorithm.fromAlgorithm(alg));
        } catch (IllegalArgumentException ex) {
            throw ImplMessages.msg.unsupportedSignatureAlgorithm(alg, ex);
        }

        // Try PEM format first - default to RS256 if the algorithm is unknown
        Key key = KeyUtils.tryAsPemSigningPrivateKey(keyContent, algorithm == null ? SignatureAlgorithm.RS256 : algorithm);
        if (key == null) {
            if (kid == null) {
                kid = JwtBuildUtils.getConfigProperty(JwtBuildUtils.SIGN_KEY_ID_PROPERTY, String.class);
                if (kid != null) {
                    headers.put(HeaderParameterNames.KEY_ID, kid);
                }
            }

            // Try to load JWK from a single JWK resource or JWK set resource
            JsonWebKey jwk = KeyUtils.getJwkKeyFromJwkSet(kid, keyContent);
            if (jwk != null) {
                key = KeyUtils.getPrivateOrSecretSigningKey(jwk, algorithm);
                if (key != null) {
                    // if the algorithm header is not set then use JWK `alg`
                    if (algorithm == null && jwk.getAlgorithm() != null) {
                        headers.put(HeaderParameterNames.ALGORITHM, jwk.getAlgorithm());
                    }
                    // if 'kid' header is not set then use JWK `kid`
                    if (kid == null && jwk.getKeyId() != null) {
                        headers.put(HeaderParameterNames.KEY_ID, jwk.getKeyId());
                    }
                }
            }
        } else {
            configuredPemKey = key;
        }
        return key;
    }

    void removeJti() {
        claims.unsetClaim(Claims.jti.name());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy