How to programmatically install a JAX-WS SSLContext client?

I work on a server in a distributed application that has browser clients, and also participates in communication between the server and a third-party user. My server has a CA certificate, allowing my clients to connect using TLS (SSL) using HTTP / S and XMPP (secure). It all works fine.

Now I need to securely connect to a third-party server using JAX-WS over HTTPS / SSL. In this post, my server acts as a client in JAX-WS interation, and I have a client certificate signed by a third party.

I tried adding a new keystore through the standard system configuration ( -Djavax.net.ssl.keyStore=xyz ), but my other components are clearly affected by this. Although my other components use dedicated parameters for their SSL configuration ( my.xmpp.keystore=xxx, my.xmpp.truststore=xxy, ... ), it seems that they end up using the global SSLContext . (The configuration namespace my.xmpp. to indicate separation, but it is not)

I also tried adding my client certificate to my original keystore, but I don't think I like the other components either.

I think my only option is to programmatically connect to the JAX-WS HTTPS configuration to configure the keystore and trust store to interact with the JAX-WS client.

Any ideas / pointers on how to do this? All the information I find either uses the javax.net.ssl.keyStore method, or sets the global SSLContext , which, it seems to me, will end up in the same confilc. The closest I got to something useful is an old error report that requests the function I need: Add support for passing SSLContext to the JAX-WS client runtime

Anyone accept?

+53
java certificate ssl jax-ws
Jun 12 2018-12-12T00:
source share
10 answers

It was a tough nut to crack, so for the record:

To solve this problem, accessing the shared KeyStore required custom KeyManager and SSLSocketFactory that use this custom KeyManager . I found the base code for this KeyStore and SSLFactory in this wonderful blog entry: how-to-dynamically-select-a-certificate-alias-when-invoking-web-services

Then, the specialized SSLSocketFactory must be inserted into the WebService context:

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

Where getCustomSocketFactory() returns a SSLSocketFactory created using the method mentioned above. This will only work for JAX-WS RI from Sun-Oracle's built-in JDK, given that the line specifying the SSLSocketFactory property is the property of this implementation.

At this point, the JAX-WS service communication is SSL-secured, but if you download WSDL from the same secure server (), you will have a download problem, since the HTTPS request for collecting WSDL will not use the same credentials as the web -service. I worked on this issue by creating local WSDL availability (file: /// ...) and dynamically changing the endpoint of the web service: (you can find a good discussion of why this is necessary in this forum )

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

Now the WebService receives the boot load and can communicate via SSL using the server resolver using the named (alias) Client-Certificate and mutual authentication. ∎

+55
Jun 14 '12 at 11:50
source share

Here's how I solved it based on this post with some minor tricks. This solution does not require the creation of any additional classes.

 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() ); 
+21
Sep 17 '12 at 17:32
source share

I tried the following and it did not work in my environment:

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

But another property worked like a charm:

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

The rest of the code was taken from the first answer.

+19
Oct. 30 '12 at 13:30
source share

By combining Radek and l0co answers, you can access the WSDL in https:

 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 
+4
Jul 23 '15 at
source share

The above is fine (as I said in a comment) if your WSDL is not available with https: // too.

Here is my way to do this:

Set the default SSLSocketFactory:

 HttpsURLConnection.setDefaultSSLSocketFactory(...); 

For Apache CXF, which I use, you also need to add these lines to your configuration:

 <http-conf:conduit name="*.http-conduit"> <http-conf:tlsClientParameters useHttpsURLConnectionDefaultSslSocketFactory="true" /> <http-conf:conduit> 
+2
Oct 25 '13 at 10:40
source share

For those who are trying and still not working, this did it for me with Wildfly 8 using the dynamic Dispatcher :

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

Note that the internal part of the Property key is missing here.

0
Apr 14 '14 at 6:58
source share

I had trouble trusting a self-signed certificate when setting up the trust manager. I used the creator of SSLContexts apache httpclient to create a custom 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); 

and passed to new TrustSelfSignedStrategy() as an argument in the loadTrustMaterial method.

0
Jun 12 '17 at 21:00
source share

I tried the steps here:

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

And that fixed the problem. I made some small changes - I set two parameters using System.getProperty ...

0
Jun 23 '17 at 17:17
source share

You can move your ssl proxy authentication and staff to a soap handler

  port = new SomeService().getServicePort(); Binding binding = ((BindingProvider) port).getBinding(); binding.setHandlerChain(Collections.<Handler>singletonList(new ProxyHandler())); 

This is my example, all network operations

  class ProxyHandler implements SOAPHandler<SOAPMessageContext> { static class TrustAllHost implements HostnameVerifier { public boolean verify(String urlHostName, SSLSession session) { return true; } } static class TrustAllCert implements X509TrustManager { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { } public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { } } private SSLSocketFactory socketFactory; public SSLSocketFactory getSocketFactory() throws Exception { // just an example if (socketFactory == null) { SSLContext sc = SSLContext.getInstance("SSL"); TrustManager[] trustAllCerts = new TrustManager[] { new TrustAllCert() }; sc.init(null, trustAllCerts, new java.security.SecureRandom()); socketFactory = sc.getSocketFactory(); } return socketFactory; } @Override public boolean handleMessage(SOAPMessageContext msgCtx) { if (!Boolean.TRUE.equals(msgCtx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY))) return true; HttpURLConnection http = null; try { SOAPMessage outMessage = msgCtx.getMessage(); outMessage.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-8"); // outMessage.setProperty(SOAPMessage.WRITE_XML_DECLARATION, true); // Not working. WTF? ByteArrayOutputStream message = new ByteArrayOutputStream(2048); message.write("<?xml version='1.0' encoding='UTF-8'?>".getBytes("UTF-8")); outMessage.writeTo(message); String endpoint = (String) msgCtx.get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY); URL service = new URL(endpoint); Proxy proxy = Proxy.NO_PROXY; //Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("{proxy.url}", {proxy.port})); http = (HttpURLConnection) service.openConnection(proxy); http.setReadTimeout(60000); // set your timeout http.setConnectTimeout(5000); http.setUseCaches(false); http.setDoInput(true); http.setDoOutput(true); http.setRequestMethod("POST"); http.setInstanceFollowRedirects(false); if (http instanceof HttpsURLConnection) { HttpsURLConnection https = (HttpsURLConnection) http; https.setHostnameVerifier(new TrustAllHost()); https.setSSLSocketFactory(getSocketFactory()); } http.setRequestProperty("Content-Type", "application/soap+xml; charset=utf-8"); http.setRequestProperty("Content-Length", Integer.toString(message.size())); http.setRequestProperty("SOAPAction", ""); http.setRequestProperty("Host", service.getHost()); //http.setRequestProperty("Proxy-Authorization", "Basic {proxy_auth}"); InputStream in = null; OutputStream out = null; try { out = http.getOutputStream(); message.writeTo(out); } finally { if (out != null) { out.flush(); out.close(); } } int responseCode = http.getResponseCode(); MimeHeaders responseHeaders = new MimeHeaders(); message.reset(); try { in = http.getInputStream(); IOUtils.copy(in, message); } catch (final IOException e) { try { in = http.getErrorStream(); IOUtils.copy(in, message); } catch (IOException e1) { throw new RuntimeException("Unable to read error body", e); } } finally { if (in != null) in.close(); } for (Map.Entry<String, List<String>> header : http.getHeaderFields().entrySet()) { String name = header.getKey(); if (name != null) for (String value : header.getValue()) responseHeaders.addHeader(name, value); } SOAPMessage inMessage = MessageFactory.newInstance() .createMessage(responseHeaders, new ByteArrayInputStream(message.toByteArray())); if (inMessage == null) throw new RuntimeException("Unable to read server response code " + responseCode); msgCtx.setMessage(inMessage); return false; } catch (Exception e) { throw new RuntimeException("Proxy error", e); } finally { if (http != null) http.disconnect(); } } @Override public boolean handleFault(SOAPMessageContext context) { return false; } @Override public void close(MessageContext context) { } @Override public Set<QName> getHeaders() { return Collections.emptySet(); } } 

It uses UrlConnection, you can use any library you want in the handler. Have fun!

0
Nov 20 '18 at 21:20
source share

The following approach worked for me. This answer is for implementing JAX-WS Axis2. I would like to build an answer from maasg. I had the same boot problem that maasg mentioned, and I solved it by making the WSDL file locally available. Then I could not provide SSL contexts such as

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

And after I googled a lot, I got an answer from this blog . You need to add Apache httpclient jar to your project.

 Protocol authhttps = new Protocol ("https", new AuthSSLProtocolSocketFactory(new URL("file://location_to_your_keystore"), "keystorePassword", new URL("file://location_to_your_truststore"), "trustStorePassword"), 443); Protocol.registerProtocol("https", authhttps); 

Thank.

0
Sep 10 '19 at 10:35
source share



All Articles