How to programmatically set the SSLContext of a JAX-WS client?
This one was a hard nut to crack, so for the record:
To solve this, it required a custom KeyManager
and a SSLSocketFactory
that uses this custom KeyManager
to access the separated KeyStore
.
I found the base code for this KeyStore
and SSLFactory
on this excellent blog entry:
how-to-dynamically-select-a-certificate-alias-when-invoking-web-services
Then, the specialized SSLSocketFactory
needs to 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 the getCustomSocketFactory()
returns a SSLSocketFactory
created using the method mentioned above. This would only work for JAX-WS RI from the Sun-Oracle impl built into the JDK, given that the string indicating the SSLSocketFactory
property is proprietary for this implementation.
At this stage, the JAX-WS service communication is secured through SSL, but if you are loading the WSDL from the same secure server () then you'll have a bootstrap problem, as the HTTPS request to gather the WSDL will not be using the same credentials than the Web Service. I worked around this problem by making the WSDL locally available (file:///...) and dynamically changing the web service endpoint: (a good discussion on why this is needed can be found in this forum)
bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, webServiceLocation);
Now the WebService gets bootstrapped and is able to communicate through SSL with the server counterpart using a named (alias) Client-Certificate and mutual authentication. ∎
JAX-WS client in websphere with custom ssl socket factory
Not even IBM can help me. So I just implemented my own JAX-WS -> SOAP conversion. That took 2 days and supports everything I need.
How to programmatically set the SSL context of a Axis client?
Ok, googling a little I've found the answer to my question. The answer is that using solely Axis 1.4 it is not possible to specify a different keystore/truststore for each service invocation. We need an external library, called axistools.
The library implements a particular kind of EngineConfiguration
that allows you to specify for each service call a keystore and/or a truststore.
The following example will be explicative:
// Setting up the configuration
SSLClientAxisEngineConfig config = new SSLClientAxisEngineConfig();
config.setKeystore("path/to/your/keystore");
config.setKeystoreType("JKS");
config.setKeystorePassword("password");
config.setTruststore("path/to/your/truststore");
config.setTruststoreType("JKS");
config.setTruststorePassword("password");
// Very important: without this method invocation
// the client won't work at all
config.initialize();
// Calling the web service
URL url = new URL("https://localhost:8443/someService");
WebServiceLocator locator = new WebServiceLocator (config);
WebServiceSoap port = locator.getWebServiceSoap(url);
WebServiceSoapStub stub = (WebServiceSoapStub) port;
stub.serviceMethod();
And that's all, folks!!!
Wildfly's JAXWS implementation seems to ignore bindingProvider property com.sun.xml.ws.transport.https.client.SSLSocketFactory
The problem is definitifely that Apache CXF ignores
bindingProvider.getRequestContext().put(
"com.sun.xml.[internal.]ws.transport.https.client.SSLSocketFactory", mySslSocketFactory);
in oposite to some comments some where.
So my final solution is to programmatically setup the HTTPConduit
used (rather than set a config in a cxf.xml
file).
// Set custom SSLContext.
HTTPConduit conduit = (HTTPConduit) ClientProxy.getClient(port).getConduit();
TLSClientParameters tlsClientParameters = new TLSClientParameters();
tlsClientParameters.setSSLSocketFactory(customSSLContext.getSocketFactory());
conduit.setTlsClientParameters(tlsClientParameters);
I hope that this helps someone having similar issues...
How to make 'simple SSL' thru Web Services?
Java Runtime Environment does come with a lots (most widely used) Certificate Authorities in cacerts file. If the certificate you used to secure your service is signed by one of those root CAs, then you need not worry about sharing any certificate with clients.
However if you used self-signed certificate, and you don't want to pass/import certificate in truststore then you can implement custom X509TrustManager and create custom SSLContext for your connections. More details in this blog.
Self-signed certificate are useful for development and test environments but you really should consider getting your server certificate signed from a recognized Certificate Authority like Verisign, Thwate etc.
Related Topics
How to Disable Jsessionid in Tomcat Servlet
How to Combine Two Hashmap Objects Containing the Same Types
Calculating Difference in Dates in Java
Should You Report the Message Text of Exceptions
Why Java.Util.Optional Is Not Serializable, How to Serialize the Object with Such Fields
How to Properly Express Jpql "Join Fetch" with "Where" Clause as JPA 2 Criteriaquery
In What Order Do Static Blocks and Initialization Blocks Execute When Using Inheritance
How to Perform a Java Callback Between Classes
Why Jscrollpane in Joptionpane Not Showing All Its Content
Eclipse Windowbuilder, Overlapping JPAnels
How to Install the Jdk on Ubuntu Linux
How to Print Line Numbers to the Log in Java
Flutter Doctor --Android-Licenses Gives a Java Error
Immutable VS Unmodifiable Collection
Text-Mouseover Popups Over a Swing Jtextarea
Differencebetween the Float and Integer Data Type When the Size Is the Same