Apache CXF 3.1.10对接WS-SecureConversation微软服务器证书校验问题求助
解决Apache CXF 3.1.10与WS-SecureConversation微软服务器通信的自签名证书校验问题
哦,这个问题我之前帮不少开发者踩过坑——WS-SecureConversation的特性就是它会发起两次独立的调用:一次是主客户端和目标服务器建立连接,另一次是通过内部的STSClient和安全令牌服务(STS)通信。你之前找不到禁用校验的方法,大概率是只配置了主客户端的证书信任,却漏掉了STSClient的配置,毕竟它是个单独的客户端实例,默认会走系统的证书校验规则。
下面给你两种可行的解决方式,分别适用于代码直接配置和Spring XML配置的场景:
代码层面手动配置(适合纯Java代码实现的客户端)
1. 先创建一个信任所有证书的SSL上下文
这个工具方法会生成一个不做任何证书校验的SSL上下文,测试环境用很方便:
import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.cert.X509Certificate; public static SSLContext getTrustAllSSLContext() throws Exception { // 创建一个信任所有证书的TrustManager TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) {} @Override public void checkServerTrusted(X509Certificate[] certs, String authType) {} } }; // 初始化SSL上下文 SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); return sslContext; }
2. 同时配置主客户端和STSClient的SSL属性
当你创建CXF客户端后,需要把刚才的SSL上下文同时应用到主客户端和内部的STSClient上:
// 初始化主客户端工厂 JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setServiceClass(YourServiceInterface.class); factory.setAddress("https://你的微软服务器地址"); // 获取主客户端实例 YourServiceInterface serviceClient = (YourServiceInterface) factory.create(); Client cxfClient = ClientProxy.getClient(serviceClient); // 获取内部的STSClient STSClient stsClient = (STSClient) cxfClient.getRequestContext().get(SecurityConstants.STS_CLIENT); if (stsClient != null) { SSLContext sslContext = getTrustAllSSLContext(); // 配置主客户端的HTTP Conduit HTTPConduit mainConduit = (HTTPConduit) cxfClient.getConduit(); TLSClientParameters mainTlsParams = new TLSClientParameters(); mainTlsParams.setSSLSocketFactory(sslContext.getSocketFactory()); mainTlsParams.setDisableCNCheck(true); // 可选:禁用主机名和证书CN的匹配校验 mainConduit.setTlsClientParameters(mainTlsParams); // 配置STSClient的HTTP Conduit(关键!之前你可能漏掉了这一步) HTTPConduit stsConduit = (HTTPConduit) stsClient.getConduit(); TLSClientParameters stsTlsParams = new TLSClientParameters(); stsTlsParams.setSSLSocketFactory(sslContext.getSocketFactory()); stsTlsParams.setDisableCNCheck(true); stsConduit.setTlsClientParameters(stsTlsParams); }
Spring XML配置方式(适合Spring项目)
如果你的项目用Spring管理CXF客户端,可以通过XML统一配置主客户端和STSClient的信任策略:
<!-- 定义信任所有证书的TLS参数 --> <bean id="trustAllTlsParams" class="org.apache.cxf.configuration.jsse.TLSClientParameters"> <property name="trustManagers"> <list> <bean class="org.apache.cxf.configuration.jsse.TrustManagerFactoryBean"> <!-- 测试环境下可直接使用默认配置,生产环境建议导入自签名证书到信任库并指定路径 --> <property name="algorithm" value="SunX509"/> </bean> </list> </property> <property name="disableCNCheck" value="true"/> </bean> <!-- 配置HTTP Conduit的全局配置器 --> <bean id="globalConduitConfigurer" class="org.apache.cxf.transport.http.HTTPConduitConfigurer"> <property name="tlsClientParameters" ref="trustAllTlsParams"/> </bean> <!-- 配置STSClient,关联全局配置器 --> <bean id="stsClientBean" class="org.apache.cxf.ws.security.trust.STSClient"> <property name="wsdlLocation" value="https://你的STS服务器地址/wsdl"/> <property name="serviceName" value="STS服务名称"/> <property name="endpointName" value="STS端点名称"/> <property name="conduitConfigurer" ref="globalConduitConfigurer"/> </bean> <!-- 主客户端配置,关联STSClient --> <jaxws:client id="yourServiceClient" serviceClass="com.yourpackage.YourServiceInterface" address="https://目标微软服务器地址"> <jaxws:properties> <entry key="ws-security.sts.client" value-ref="stsClientBean"/> <!-- 其他WS-SecureConversation相关配置 --> </jaxws:properties> </jaxws:client>
重要提醒:禁用证书校验只适合测试环境!生产环境绝对不能这么做,正确的做法是把微软服务器的自签名证书导入到客户端的JVM信任库或者项目自定义的信任库中,避免安全风险。
内容的提问来源于stack exchange,提问作者Myron Uecker
相关产品推荐
相关产品推荐

