如何以编程方式设置JAX-WS客户端的SSLContext?

我正在使用具有浏览器客户端的分布式应用程序中的服务器,并且还参与与第三方的服务器到服务器通信。 我的服务器有一个CA签名证书,让我的客户端使用HTTP / S和XMPP(安全)使用TLS(SSL)通信进行连接。 这一切都很好。

现在,我需要通过HTTPS / SSL使用JAX-WS安全地连接到第三方服务器。 在此通信中,我的服务器在JAX-WS交互中充当客户端,并且我已经由第三方签署了客户端证书。

我尝试通过标准系统配置( -Djavax.net.ssl.keyStore=xyz )添加新的密钥库,但我的其他组件明显受此影响。 虽然我的其他组件使用专用参数进行SSL配置( my.xmpp.keystore=xxx, my.xmpp.truststore=xxy, ... ),但似乎他们最终使用全局SSLContext 。 (配置命名空间my.xmpp.似乎表示分离,但事实并非如此)

我也尝试将我的客户端证书添加到我的原始密钥库中,但是 – 我的其他组件似乎也不喜欢它。

我认为我唯一的选择是以编程方式挂钩到JAX-WS HTTPS配置,以便为客户端JAX-WS交互设置密钥库和信任库。

有关如何做到这一点的任何想法/指示? 我找到的所有信息都使用了javax.net.ssl.keyStore方法,或者设置了全局SSLContext ,我想这将最终出现在同一个confilc中。 我得到的最接近的东西是这个旧的错误报告请求我需要的function: 添加支持将SSLContext传递给JAX-WS客户端运行时

任何需要?

这个是一个难以破解的难题,所以为了记录:

为了解决这个问题,它需要一个自定义KeyManager和一个SSLSocketFactory ,它使用这个自定义KeyManager来访问分离的KeyStore 。 我在这个优秀的博客文章中找到了这个KeyStoreSSLFactory的基本代码: how-to- SSLFactory -select-a-certificate-alias-when-invoking-web-services

然后,需要将专门的SSLSocketFactory插入到WebService上下文中:

 service = getWebServicePort(getWSDLLocation()); BindingProvider bindingProvider = (BindingProvider) service; bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", getCustomSocketFactory()); 

getCustomSocketFactory()返回使用上述方法创建的SSLSocketFactory 。 这只适用于内置于JDK中的Sun-Oracle impl的JAX-WS RI,因为指示SSLSocketFactory属性的字符串对于此实现是专有的。

在此阶段,JAX-WS服务通信通过SSL加以保护,但如果您从同一个安全服务器()加载WSDL,那么您将遇到引导问题,因为收集WSDL的HTTPS请求将不会使用与Web服务相同的凭据。 我通过使WSDL在本地可用(file:/// …)并动态更改Web服务端点来解决这个问题:( 在这个论坛中可以找到关于为什么需要这个的好讨论)

 bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, webServiceLocation); 

现在,WebService被引导,并且能够使用命名(别名)客户端证书和相互身份validation通过SSL与服务器对应方进行通信。 ∎

这是我根据这篇文章通过一些小调整解决它的方法。 此解决方案不需要创建任何其他类。

 SSLContext sc = SSLContext.getInstance("SSLv3"); KeyManagerFactory kmf = KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm() ); KeyStore ks = KeyStore.getInstance( KeyStore.getDefaultType() ); ks.load(new FileInputStream( certPath ), certPasswd.toCharArray() ); kmf.init( ks, certPasswd.toCharArray() ); sc.init( kmf.getKeyManagers(), null, null ); ((BindingProvider) webservicePort).getRequestContext() .put( "com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", sc.getSocketFactory() ); 

我尝试了以下内容,但它对我的环境无效:

 bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", getCustomSocketFactory()); 

但不同的财产就像一个魅力:

 bindingProvider.getRequestContext().put(JAXWSProperties.SSL_SOCKET_FACTORY, getCustomSocketFactory()); 

其余代码取自第一个回复。

通过结合Radek和l0co的答案,您可以访问https后面的WSDL:

 SSLContext sc = SSLContext.getInstance("TLS"); KeyManagerFactory kmf = KeyManagerFactory .getInstance(KeyManagerFactory.getDefaultAlgorithm()); KeyStore ks = KeyStore.getInstance("JKS"); ks.load(getClass().getResourceAsStream(keystore), password.toCharArray()); kmf.init(ks, password.toCharArray()); sc.init(kmf.getKeyManagers(), null, null); HttpsURLConnection .setDefaultSSLSocketFactory(sc.getSocketFactory()); yourService = new YourService(url); //Handshake should succeed 

除非您的WSDL也可以通过https://访问,否则以上情况很好(正如我在评论中所述)。

这是我的解决方法:

将SSLSocketFactory设置为默认值:

 HttpsURLConnection.setDefaultSSLSocketFactory(...); 

对于我使用的Apache CXF,您还需要将这些行添加到您的配置中:

    

对于那些尝试但仍未使用它的人来说,这是使用动态Dispatcher为Wildfly 8做的:

bindingProvider.getRequestContext().put("com.sun.xml.ws.transport.https.client.SSLSocketFactory", yourSslSocketFactory);

请注意,Property键的internal部分已消失。

在设置信任管理器时,我在信任自签名证书时遇到了问题。 我使用apache httpclient的SSLContexts构建器来创建自定义SSLSocketFactory

 SSLContext sslcontext = SSLContexts.custom() .loadKeyMaterial(keyStoreFile, "keystorePassword.toCharArray(), keyPassword.toCharArray()) .loadTrustMaterial(trustStoreFile, "password".toCharArray(), new TrustSelfSignedStrategy()) .build(); SSLSocketFactory customSslFactory = sslcontext.getSocketFactory() bindingProvider.getRequestContext().put(JAXWSProperties.SSL_SOCKET_FACTORY, customSslFactory); 

并将new TrustSelfSignedStrategy()作为loadTrustMaterial方法中的参数loadTrustMaterial

我试过这里的步骤:

http://jyotirbhandari.blogspot.com/2011/09/java-error-invalidalgorithmparameterexc.html

而且,这解决了这个问题。 我做了一些小调整 – 我使用System.getProperty设置了两个参数…