如何以编程方式设置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
和一个使用这个自定义KeyManager
的SSLSocketFactory
来访问分离的KeyStore
。 我在这个出色的博客文章中find了这个KeyStore
和SSLFactory
的基本代码: 如何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设置了两个参数…