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

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

现在我需要通过HTTPS / SSL使用JAX-WS安全地连接到第三方服务器。 在这个通信中,我的服务器充当JAX-WS interation中的客户端,并且我有一个由第三方签名的客户端证书。

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

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

我认为我剩下的唯一select是以编程方式挂接到JAX-WS HTTPSconfiguration,为客户端JAX-WS交互设置密钥库和信任库。

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

任何需要?

这是一个很难破解的logging:

为了解决这个问题,它需要一个自定义KeyManager和一个使用这个自定义KeyManagerSSLSocketFactory来访问分离的KeyStore 。 我在这个出色的博客文章中find了这个KeyStoreSSLFactory的基本代码: 如何dynamicselect一个证书别名什么时候调用web服务

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

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

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

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

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

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

这就是我如何根据这个post解决它的一些小的调整。 这个解决scheme不需要创build任何额外的类。

 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,您还需要将这些行添加到您的configuration中:

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

对于那些尝试,但仍然没有得到它的工作,这使用蜻蜓8,使用dynamicDispatcher

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

请注意,属性键的internal部分已经消失。

设置信任pipe理器时,我遇到了信任自签名证书的问题。 我使用apache httpclient的SSLContexts构build器来创build一个自定义的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); 

并在loadTrustMaterial方法中传入new TrustSelfSignedStrategy()作为参数。

我试过这里的步骤:

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

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