My environment is a Maven Project and Wildfly (8.2.1) as Application Server. What I need is to connect wihin a incoming REST call to a third party server using SOAP. I need SSL Client Authentication; therefore, I have my own KeyStore and TrustStore. I create therefore my own SSLContext and need to let the WebService use this SSLContext.
All looks like this:
// Build SSL context with own KeyManager / TrustManager
SSLContext sc = SSLContext.getInstance("TLS");
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("JKS");
String password = "changeit";
ks.load(getClass().getResourceAsStream("/keystore"), password.toCharArray());
kmf.init(ks, password.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
// Now build webservice client
MyWS_Service service = new MyWS_Service(null, new QName("http://...", "MyWS"));
MyWS port = service.getMyWSSOAP();
BindingProvider bindingProvider = (BindingProvider) port;
// set to use own SSLContext
bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", sc.getSocketFactory());
// set endpoint
bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://hostname:443/.../...");
// perform request
respObj = port.myRequest(myRequestObj);
If I call this code from a JUnit test, all works fine. It uses JAXWS-RI from the JRE.
If I call this code from Wildfly, i.e. from my incoming REST call, where I finally need to fire this request, it does not work because it does not use the own SSLContext. It uses the default SSLContext, which of course is rejected by the third party SOAP server. What I see is that it does not use JAXWS-RI but Apache CXF as JAXWS implementation. So I do guess that bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", sc.getSocketFactory());
is simply ignored [Why?] and has no effect. (I also tried the property name com.sun.xml.ws.transport.https.client.SSLSocketFactory
[without internal
] - also with no luck.)
I know that I could use HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
or even use the JVM parameters javax.net.ssl.trustStore
, javax.net.ssl.keyStore
(and their corresponding password properties). Since this affects all connections, it is out of discussion to use this solution; however, lets look what hapens, if I use it anyway:
JUnit use case: It also works
Wildfly use case: It seems that JAXWS takes the SSLContext, but there is a SSL exception (alert from Server that CA is unknown). This shows that there is even a difference in how to establish the connection. Why is it working, if the code is executed with JUnit? This proofes that the KeyStore / TrustStore is correctly set up with the correct certificates. Isn't it?
Edit: There is one more proof, that the problem is the JAXWS implementation Wildfly uses: If I just perform a simple HttpsConnection, it even works with my own KeyStore / TrustStore in Wildfly:
url = new URL("https://hostname:443/.../...");
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
System.out.println(Utils.inputStreamToString(con.getInputStream()));
So what is the best to do? -> As the question titles, I would like to try to bring Wildfly to also use JAXWS-RI rather than Apache CXF. But I got it not to work until now. I tried to put the following dependency in the pom:
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.2.10</version>
</dependency>
But this gives me the following exception:
java.util.ServiceConfigurationError: javax.xml.ws.spi.Provider: Provider com.sun.xml.ws.spi.ProviderImpl could not be instantiated
at java.util.ServiceLoader.fail(ServiceLoader.java:232) ~[?:1.8.0_92]
What is wrong? How can I bring Wildfly to work the same way, as if the code is executed from the same project but "as a JUnit Test"?
Edit: If you have a tip how to reach the goal (sending SOAP requests using SSL with client auth on Wildfly 8.2.1) in a different way (provided that it is a clean Java EE solution - i.e. not sending own XML bodies :-) and not with too old framworks like Axis 1), it is also welcome! I do need a solution soon - I am fighting for days already...
com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory
. WildFly uses CXF for JAX-WS and that points to some internal RI class. Maybe there's something in here that will help. cxf.apache.org/docs/… – Cyprio