【问题标题】:Apache CXF JaxWsProxyFactoryBean SSL Configuration call to external https failsApache CXF JaxWsProxyFactoryBean SSL 配置调用外部 https 失败
【发布时间】:2021-06-28 11:53:23
【问题描述】:

我部署了一个 spring 微服务 docker。 我使用 JaxWsProxyFactoryBean 调用外部服务器(soap/wsdl),使用 http://externalServer 一切顺利:

JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
jaxWsProxyFactoryBean.setAddress("http://externalServer");
...

当我在 setAddress 中调用 https 时出现问题。

我使用 keytool 在密钥库中注册了被调用服务器的密钥/证书,并将其保存到 /root/.keystore(标准)从 pfx 导入。 当我尝试调用 https 时,我收到此错误:

org.apache.cxf.transport.https.SSLUtils  : Default key managers cannot be initialized: Password must not be null

好的,我缺少密码。但是这个恶意密码放在哪里?在 application.yml?在系统属性中? [keystore中使用的密码是标准的(changeit)]

已编辑

这里是日志的快照:

DEBUG 1 --- [  XNIO-1 task-1] org.apache.cxf.transport.https.SSLUtils  : The location of the key store has not been set via a system parameter or through configuration so the default value of /root/.keystore will be used.
DEBUG 1 --- [  XNIO-1 task-1] org.apache.cxf.transport.https.SSLUtils  : The key store password has not been set via a system property or through configuration, reading data from the keystore will fail.
DEBUG 1 --- [  XNIO-1 task-1] org.apache.cxf.transport.https.SSLUtils  : The key password has not been set via a system property or through configuration, reading data from the keystore will fail.
DEBUG 1 --- [  XNIO-1 task-1] org.apache.cxf.transport.https.SSLUtils  : The keystore type has not been set in configuration so the default value of JKS will be used.
WARN 1 --- [  XNIO-1 task-1] org.apache.cxf.transport.https.SSLUtils  : Default key managers cannot be initialized: Password must not be null

使用标准密钥库,但没有密码。

【问题讨论】:

  • 您是如何为您的 Apache CXF 客户端配置 SSL 配置的?你能分享一个例子吗?
  • 我使用springboot全部运行,没有特别配置。我在哪里可以找到这个配置?

标签: spring docker ssl cxf keytool


【解决方案1】:

从您的问题的评论部分查看我们的对话,我可以得出结论,您的 Apache CXF 没有配置 ssl。您需要做的是读取包含受信任证书的密钥库,并使用 TrustManagerFactory 和 TrustManager 将其加载到您的 SSLContext。

以下是您可以尝试的示例配置:

import org.apache.cxf.bus.CXFBusFactory;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.transport.http.HTTPConduitConfigurer;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import java.security.KeyStore;

public class App {

    public static void main(String[] args) throws Exception {
        InputStream identityAsInputStream = Files.newInputStream(Paths.get("/path/to/your/identity.jks"));
        KeyStore identity = KeyStore.getInstance(KeyStore.getDefaultType());
        identity.load(identityAsInputStream, "keystore-password".toCharArray());

        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(identity, "key-password".toCharArray());
        KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();

        InputStream trustStoreInputStream = Files.newInputStream(Paths.get("/path/to/your/truststore.jks"));
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(trustStoreInputStream, "truststore-password".toCharArray());

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(trustStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(keyManagers, trustManagers, null);

        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setAddress("https://some-secure-server.com/");

        factory.setBus(new CXFBusFactory().createBus());
        factory.getBus().setExtension((name, address, httpConduit) -> {
            TLSClientParameters tls = new TLSClientParameters();
            tls.setSSLSocketFactory(sslContext.getSocketFactory());
            httpConduit.setTlsClientParameters(tls);
        }, HTTPConduitConfigurer.class);

        WebClient webClient = factory.createWebClient();
    }
}

我这里还有一个 cxf 客户端的工作示例,用于基于 ssl 的单向和双向身份验证:GitHub - Example Apache CXF client ssl configuration

【讨论】:

  • 谢谢@Hakan54 我有 JaxWsProxyFactoryBean 而不是 JAXRSClientFactoryBean。 (我的电话转到网络服务器)从日志消息中,我看到一个密钥库已加载(标准 /root/.keystore),但密码为空。我的问题是如何传递这个密码(最终是密钥库的不同位置)。
  • 啊,我已经监督过了。我的错。我已经调整了我的代码 sn-p 附加示例,用于从不同的路径加载密钥库以及自定义密码选项。请让我知道这是否适合您
  • 在我的调查中,我尝试了 System.setProperty("javax.net.ssl.keyStore", keyStore); System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword);似乎以这种方式可以看到密码,但现在我有 java.security.UnrecoverableKeyException:无法恢复密钥。但是我从 pfx 文件(pkcs12 chrypto)中使用 keytool 导入证书。
  • 默认密钥库中可能包含具有不同密码的密钥......这可能是它仍然失败的原因。我不建议为这种用例传递系统参数,因为我认为它不安全。您的密码可以很容易地从终端中提取。但是,您可以使用此工具轻松验证 keystore-explorer.org 如果您的密钥库中的密钥条目具有不同的密码
  • keystore-explorer.org 真的很好!我在 .keystore 中看到登录密码没问题并看到公钥,但是如果我尝试查看私钥,则会出现相同的错误“不可恢复...”。所以我明白我的电话尝试使用私有证书,但必须使用公共证书!
猜你喜欢
  • 1970-01-01
  • 2018-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-11
  • 1970-01-01
  • 2019-04-26
  • 2015-12-13
相关资源
最近更新 更多