Как поддерживать несколько сертификатов для клиента CXF - PullRequest
4 голосов
/ 25 июня 2019

У меня есть клиентское приложение SOAP, которое вызывает стороннюю конечную точку SOAP, и мы используем SSL для доступа к ней. Сейчас срок действия сертификата истекает через несколько месяцев, и мы получили новый сертификат нашей третьей стороны. Теперь мы используем клиент Apache CXF для подключения к конечной точке. Мы используем закрытый ключ и сертификат для создания ключевой записи в собственном хранилище ключей в коде Java.

Обратите внимание, что сторонняя сторона на стороне сервера еще не использовала новый сертификат и ожидает, что клиент поддержит оба одновременно, чтобы они могли легко выполнить миграцию.

Теперь я адаптировал наш код, чтобы добавить новый сертификат к этой существующей записи ключа. Потому что в коде в Keystore вы можете иметь один псевдоним и несколько сертификатов (цепочку сертификатов), определенных для записи ключа. Единственное, что клиент всегда использует первый сертификат при отправке SOAP-запроса.

Из моего понимания этой ссылки Менеджер ключей по умолчанию всегда выбирает первый в цепочке сертификатов

Наша реализация Keystore:

    @Bean
    public Merlin merlin(KeyStore keyStore) throws WSSecurityException, IOException {
        return new KeyStoreMerlin(keyStore);
    }

    @Bean
    public KeyStore keyStore(SSLConnectionProperties sslConnectionProperties,
                             RandomPasswordCallbackHandler randomPasswordCallbackHandler) throws Exception {
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

        X509Certificate[] x509Certificates = sslConnectionProperties.getCertifcates().stream()
                .map(crt -> createX509Certificate(certificateFactory, crt.getCertificate()))
                .toArray(X509Certificate[]::new);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PemReader pemReader = new PemReader(new StringReader(sslConnectionProperties.getKey()));
        PemObject pemObject = pemReader.readPemObject();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(new PKCS8EncodedKeySpec(pemObject.getContent()));

        keyStore.load(null);
        keyStore.setKeyEntry(CERTIFICATE_ALIAS, privateKey, randomPasswordCallbackHandler.getPassword().toCharArray(), x509Certificates);
        return keyStore;
    }

Создать заголовок аутентификации для клиента CXF:

    private WSS4JOutInterceptor createAuthenticationInterceptor(Merlin merlin, RandomPasswordCallbackHandler randomPasswordCallbackHandler) {
        return new WSS4JOutInterceptor(new HashMap<String, Object>() {
            {
                put(WSHandlerConstants.ACTION, "Signature");
                put(WSHandlerConstants.USER, CERTIFICATE_ALIAS);
                put(WSHandlerConstants.PW_CALLBACK_REF, randomPasswordCallbackHandler);
                put(WSHandlerConstants.SIG_KEY_ID, "DirectReference");
                put(ConfigurationConstants.SIG_PROP_REF_ID, SIGNATURE_PROPERTIES);
                put(SIGNATURE_PROPERTIES, merlin);
            }
        });
    }

    @Bean
    public TLSClientParameters tlsClientParameters(KeyStore keyStore, RandomPasswordCallbackHandler randomPasswordCallbackHandler) throws Exception {
        String defaultAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(defaultAlgorithm);
        keyManagerFactory.init(keyStore, randomPasswordCallbackHandler.getPassword().toCharArray());

        final TLSClientParameters tlsClientParameters = new TLSClientParameters();
        tlsClientParameters.setKeyManagers(keyManagerFactory.getKeyManagers());

        return tlsClientParameters;
    }

Включение HTTPS на клиенте:

    private void enableHttpsOnClient(Client client) {
        HTTPConduit conduit = (HTTPConduit) client.getConduit();
        conduit.setTlsClientParameters(tlsClientParameters);
    }

Я прочитал, что вы можете динамически выбирать сертификат в соответствии с вашими требованиями. Или есть другой способ безопасного перехода на новый сертификат во время выполнения без потери времени работы?

...