Ssl 如何设置Apache CXF客户端以使用WebSphere truststore?(收到“未找到可信证书”异常。)

Ssl 如何设置Apache CXF客户端以使用WebSphere truststore?(收到“未找到可信证书”异常。),ssl,websphere,cxf,websphere-6.1,Ssl,Websphere,Cxf,Websphere 6.1,首先,我将从总结开始。我使用ApacheCXF客户端通过SSL与使用自签名证书的ApacheCXF服务提供商通信。我将证书导入到客户端服务器上的WebSphere truststore中,但仍然收到“javax.net.ssl.SSLHandshakeException:SSLHandshakeException调用:com.ibm.jsse2.util.h:未找到可信证书”异常 现在,详细情况如下: 我有一个apachecxfweb服务客户端,我正在使用Spring配置该客户端,该客户端被部署

首先,我将从总结开始。我使用ApacheCXF客户端通过SSL与使用自签名证书的ApacheCXF服务提供商通信。我将证书导入到客户端服务器上的WebSphere truststore中,但仍然收到“javax.net.ssl.SSLHandshakeException:SSLHandshakeException调用:com.ibm.jsse2.util.h:未找到可信证书”异常

现在,详细情况如下:

我有一个apachecxfweb服务客户端,我正在使用Spring配置该客户端,该客户端被部署到websphere6.1应用服务器。CXF客户端与不同WebSphere服务器上的Apache CXF服务提供商通信。通信使用SSL

服务提供商正在使用自签名证书。我已经通过管理控制台将提供者的证书导入到客户机服务器上的WebSphereTrustStore中。我通过进入SSL证书和密钥管理>SSL配置>NodeDefaultSSLSettings>密钥存储和证书>NodeDefaultTrustStore>签名者证书来实现这一点;然后,我使用“从端口检索”工具导入证书

但是,我在尝试联系服务提供商时仍然收到此错误:“javax.net.ssl.SSLHandshakeException:SSLHandshakeException调用:com.ibm.jsse2.util.h:未找到受信任的证书”

Spring配置文件如下所示:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:sec="http://cxf.apache.org/configuration/security"
  xmlns:http="http://cxf.apache.org/transports/http/configuration"
  xmlns:jaxws="http://cxf.apache.org/jaxws"
  xsi:schemaLocation="
      http://cxf.apache.org/configuration/security
      http://cxf.apache.org/schemas/configuration/security.xsd
      http://cxf.apache.org/transports/http/configuration
      http://cxf.apache.org/schemas/configuration/http-conf.xsd
      http://cxf.apache.org/jaxws
      http://cxf.apache.org/schemas/jaxws.xsd
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd">
    <http:conduit name="*.http-conduit">
        <!-- deactivate HTTPS url hostname verification (localhost, etc) -->
        <!-- WARNING ! disableCNcheck=true should not used in production. -->
        <http:tlsClientParameters disableCNCheck="true" />
    </http:conduit>
    <!-- Read properties from property file(s). -->
    <bean id="propertyPlaceholderConfigurer"
            class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <!-- The *.spring.properties files are prefixed with a system property
                    that is set on the WebSphere server. -->
                <value>classpath:spring.${my.env}.properties</value>
            </list>
        </property>
    </bean>
    <jaxws:client id="myServiceClient"
        serviceClass="com.client.stub.cxf.IMyService"
        address="${my.svc.url}" />
    <bean id="myReport" class="com.client.MyReportRequestor">
        <property name="client" ref="myServiceClient"/>
    </bean>
</beans>
为了让Apache CXF客户端信任自签名证书,我还需要做什么

我宁愿不必在配置文件中指定信任库的路径和密码


谢谢大家!

我认为您不能像使用外部组件(apachecxf)那样使用WAS密钥库。您可能必须构建和使用。这方面似乎有很多工作要做。

看看CXF和WAS是如何工作的,访问Websphere的
SSLSocketFactory
并使用出站拦截器将其传递给CXF是相当简单的

如果使用以下类:

public class WebsphereSslOutInterceptor extends AbstractPhaseInterceptor<Message> {

  private String sslAlias = null;

  public WebsphereSslOutInterceptor() {
    super(Phase.SETUP);
  }

  public void handleMessage(Message message) throws Fault {
    Conduit conduit = message.getExchange().getConduit(message);
    if (conduit instanceof HTTPConduit) {
      HTTPConduit httpConduit = (HTTPConduit)conduit;
      String endpoint = (String) message.get(Message.ENDPOINT_ADDRESS);
      if (endpoint != null) {
        try {
          URL endpointUrl = new URL(endpoint);
          Map<String, String> connectionInfo = new HashMap<String, String>();

          connectionInfo.put(
            JSSEHelper.CONNECTION_INFO_REMOTE_HOST, 
            endpointUrl.getHost());
          connectionInfo.put(
            JSSEHelper.CONNECTION_INFO_REMOTE_PORT, 
            Integer.toString(endpointUrl.getPort()));
          connectionInfo.put(
            JSSEHelper.CONNECTION_INFO_DIRECTION, 
            JSSEHelper.DIRECTION_OUTBOUND);
          SSLSocketFactory factory = 
            JSSEHelper.getInstance().getSSLSocketFactory(
              sslAlias, 
              connectionInfo, 
              null);

          TLSClientParameters tlsClientParameters = httpConduit.getTlsClientParameters();
          if (tlsClientParameters != null) {
            tlsClientParameters.setSSLSocketFactory(factory);
          }
        } catch (MalformedURLException e) {
          throw new Fault(e);
        } catch (SSLException e) {
          throw new Fault(e);
        }
      }
    }
  }

  public void setSslAlias(String sslAlias) {
    this.sslAlias = sslAlias;
  }
}
另一方面,如果
webspheresLoutinterCeptor
中声明了
sslAlias
属性,则可以根据其别名选择客户端证书

因为这是使用Websphere中的
SSLSocketFactory
,所以信任存储也将从Websphere中使用

编辑:


我使用了CXF 2.3.6和Websphere 6.1,CXF可能使用了错误的SSL套接字工厂

尝试将其添加到Spring配置中:

<http-conf:conduit name="*.http-conduit">
    <http-conf:tlsClientParameters useHttpsURLConnectionDefaultSslSocketFactory="true"/>
</http-conf:conduit>

beny23的解决方案在WAS7上非常适合我,但做了以下修改(原因:httpconductor.getTlsClientParameters()可能为空):

替换此部分:

    TLSClientParameters tlsClientParameters = httpConduit.getTlsClientParameters();
    if (tlsClientParameters != null) {
      tlsClientParameters.setSSLSocketFactory(factory);
    }
为此:

    TLSClientParameters tlsClientParameters = httpConduit.getTlsClientParameters();
    if (tlsClientParameters == null) {
      tlsClientParameters = new TLSClientParameters();
      httpConduit.setTlsClientParameters(tlsClientParameters);
    }
    tlsClientParameters.setSSLSocketFactory(factory);

我也找不到使用WAS信任库的方法,因此我假设您必须在配置文件中指定您提到的信任库。我发现@kjetil解决方案更可行,因为它不需要自定义开发只要我在端点配置中保留拦截器定义,此解决方案对我有效。但是,如果我把它放到总线上,handleMessage方法就不会被调用。有人知道为什么吗?我不希望为每个端点指定相同的拦截器。@beny23如果我使用的是Websphere Dynamic Endpoints,我还需要所有拦截器和SSLSocketFactory吗?我的理解是,我可以从代码中进行简单的SSL调用,动态端点应该根据URL匹配拦截所有传出请求。对吗?对我也有用。。。甚至在使用ProxyFactoryBean以友好方式创建客户端时[WAS 8.5][CXF 3.1.8]
<http-conf:conduit name="*.http-conduit">
    <http-conf:tlsClientParameters useHttpsURLConnectionDefaultSslSocketFactory="true"/>
</http-conf:conduit>
    TLSClientParameters tlsClientParameters = httpConduit.getTlsClientParameters();
    if (tlsClientParameters != null) {
      tlsClientParameters.setSSLSocketFactory(factory);
    }
    TLSClientParameters tlsClientParameters = httpConduit.getTlsClientParameters();
    if (tlsClientParameters == null) {
      tlsClientParameters = new TLSClientParameters();
      httpConduit.setTlsClientParameters(tlsClientParameters);
    }
    tlsClientParameters.setSSLSocketFactory(factory);