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

io.gravitee.am.certificate.api.AbstractCertificateProvider Maven / Gradle / Ivy

There is a newer version: 4.6.0-alpha.3
Show newest version
/**
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.gravitee.am.certificate.api;

import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.KeyOperation;
import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.util.Base64;
import io.gravitee.am.certificate.api.jwk.JwkNimbusConverter;
import io.gravitee.am.common.jwt.SignatureAlgorithm;
import io.gravitee.am.model.jose.ECKey;
import io.gravitee.am.model.jose.JWK;
import io.gravitee.am.model.jose.RSAKey;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.core.Single;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static io.gravitee.am.certificate.api.jwk.JwkNimbusConverter.converter;

public abstract class AbstractCertificateProvider implements CertificateProvider {
    public static final String RSA = "RSA";
    public static final String EC = "EC";
    @Autowired
    protected CertificateMetadata certificateMetadata;

    @Autowired
    protected ConfigurableApplicationContext context;

    private Date expirationDate;
    private Certificate cert;
    private JWKSet jwkSet;
    private Set keys;
    private SignatureAlgorithm signature = SignatureAlgorithm.RS256;
    private io.gravitee.am.certificate.api.Key certificateKey;
    private List certificateKeys;

    public void createCertificateKeys(CertificateMetadata certificateMetadata) throws Exception {
        Object file = getCertificateContent(certificateMetadata);
        Objects.requireNonNull(file, invalidCertificateFileMessage());

        try (InputStream is = new ByteArrayInputStream((byte[]) file)) {
            KeyStore keystore = keyStore();
            keystore.load(is, getStorepass().toCharArray());
            // generate JWK set
            // TODO : should be moved to the gravitee-am-jwt module
            jwkSet = JWKSet.load(keystore, name -> getKeypass().toCharArray());
            keys = getKeys();
            // generate Key pair
            java.security.Key key = keystore.getKey(getAlias(), getKeypass().toCharArray());
            if (key instanceof PrivateKey) {
                // Get certificate of public key
                cert = keystore.getCertificate(getAlias());
                // create key pair
                KeyPair keyPair = new KeyPair(cert.getPublicKey(), (PrivateKey) key);
                // create key
                certificateKey = new DefaultKey(getAlias(), keyPair);
                // update metadata
                certificateMetadata.getMetadata().put(CertificateMetadata.DIGEST_ALGORITHM_NAME, signature.getDigestName());
                // generate public certificate keys
                certificateKeys = new ArrayList<>();
                // get Signing Algorithm name
                if (cert instanceof X509Certificate x509Certificate) {
                    signature = getSignature(x509Certificate.getSigAlgName());
                    String pem = X509CertUtils.toPEMString(x509Certificate);
                    certificateKeys.add(new CertificateKey(CertificateFormat.PEM, pem));
                    expirationDate = x509Certificate.getNotAfter();
                }
                PublicKey publicKey = keyPair.getPublic();
                if (publicKey.getAlgorithm().equals(RSA)){
                    certificateKeys.add(new CertificateKey(CertificateFormat.SSH_RSA, KeyUtils.toSSHRSAString((RSAPublicKey) publicKey)));
                } else if (publicKey.getAlgorithm().equals(EC)){
                    certificateKeys.add(new CertificateKey(CertificateFormat.ECDSA, KeyUtils.toEcdsaString((ECPublicKey) publicKey)));
                }
            } else {
                throw new IllegalArgumentException("An ECSDA or RSA Signer must be supplied");
            }
        }
    }

    protected Object getCertificateContent(CertificateMetadata certificateMetadata) {
        return certificateMetadata.getMetadata().get(CertificateMetadata.FILE);
    }

    protected abstract String getStorepass();

    protected abstract String getAlias();

    protected abstract String getKeypass();

    protected abstract Set getUse();

    protected abstract String getAlgorithm();

    protected abstract String invalidCertificateFileMessage();

    protected abstract KeyStore keyStore() throws KeyStoreException;

    @Override
    public Optional getExpirationDate() {
        return Optional.ofNullable(this.expirationDate);
    }

    @Override
    public Flowable privateKey() {
        // CertificateProvider only manage RSA key.
        com.nimbusds.jose.jwk.JWK nimbusJwk = new com.nimbusds.jose.jwk.RSAKey.Builder((RSAPublicKey) ((KeyPair) certificateKey.getValue()).getPublic())
                .privateKey((RSAPrivateKey) ((KeyPair) certificateKey.getValue()).getPrivate())
                .keyID(getAlias())
                .build();
        List jwks = converter(nimbusJwk, true, getUse(), signatureAlgorithm()).createJwk().toList();
        return Flowable.fromIterable(jwks);
    }

    @Override
    public Single key() {
        return Single.just(certificateKey);
    }

    @Override
    public Single publicKey() {
        // fallback to ssh-rsa
        return Single.just(
                certificateKeys
                        .stream()
                        .filter(c -> c.getFmt().equals(CertificateFormat.SSH_RSA))
                        .map(CertificateKey::getPayload)
                        .findFirst()
                        .orElseThrow());
    }

    @Override
    public Single> publicKeys() {
        return Single.just(certificateKeys);
    }

    @Override
    public Flowable keys() {
        return Flowable.fromIterable(keys);
    }

    @Override
    public Certificate certificate() {
        return cert;
    }

    @Override
    public String signatureAlgorithm() {
        if (getAlgorithm() != null) {
            return getAlgorithm();
        }
        return signature.getValue();
    }

    private Set getKeys() {
        return jwkSet.toPublicJWKSet().getKeys().stream()
                .map(nimbusJwk -> converter(nimbusJwk, false, getUse(), getAlgorithm()))
                .flatMap(JwkNimbusConverter::createJwk)
                .collect(Collectors.toSet());
    }


    private SignatureAlgorithm getSignature(String signingAlgorithm) {
        return Stream.of(SignatureAlgorithm.values())
                .filter(signatureAlgorithm -> signatureAlgorithm.getJcaName() != null)
                .filter(signatureAlgorithm -> signatureAlgorithm.getJcaName().equals(signingAlgorithm))
                .findFirst()
                .orElse(SignatureAlgorithm.RS256);
    }

    @Override
    public void unregister() {
        context.close();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy