如何为CXF客户端支持多个证书

时间:2019-06-25 07:16:12

标签: java ssl-certificate cxf soap-client ws-security

我有一个调用第三方SOAP端点的SOAP客户端应用程序,我们使用SSL来访问它。现在该证书将在几个月后到期,并且我们收到了第三方的新证书。现在,我们使用Apache CXF客户端连接到端点。我们使用私钥和证书在自己的Keystore中以Java代码创建密钥条目。

请注意,服务器端的第三方尚未使用新证书,希望我的客户端同时支持这两个证书,以便他们可以无缝进行迁移。

现在,我修改了代码,将新证书添加到该现有密钥条目中。因为在密钥库中的代码中,您可以为一个密钥条目定义一个别名和多个证书(证书链)。唯一的事情是,客户端在发送SOAP请求时始终使用第一个证书。

根据我对此link的理解 默认密钥管理器始终选择证书链中的第一个

我们的密钥库实现:

    @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);
    }

我了解到您可以根据您的自定义要求动态选择证书。还是有其他方法可以在运行时安全地迁移到新证书而又不会失去正常运行时间?

0 个答案:

没有答案