我的环境是Maven Project和Wildfly(8.2.1)作为Application Server。我需要的是使用SOAP将传入的REST调用连接到第三方服务器。我需要SSL客户端身份验证;因此,我有自己的KeyStore和TrustStore。因此,我创建了自己的SSLContext,并且需要让WebService使用此SSLContext。
所有看起来像这样:
// 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);
如果我从JUnit测试中调用此代码,则一切正常。它使用JRE中的JAXWS-RI。
如果我从Wildfly调用此代码,即来自我的传入REST调用,我最终需要触发此请求,它不起作用,因为它不使用自己的SSLContext。它使用默认的SSLContext,当然这被第三方SOAP服务器拒绝。我看到的是它不使用JAXWS-RI而是使用Apache CXF作为JAXWS实现。所以我猜测bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", sc.getSocketFactory());
被忽略[Why?]并且无效。 (我也尝试过属性名称com.sun.xml.ws.transport.https.client.SSLSocketFactory
[没有internal
] - 也没有运气。)
我知道我可以使用HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
甚至使用JVM参数javax.net.ssl.trustStore
,javax.net.ssl.keyStore
(及其相应的密码属性)。由于这会影响所有连接,因此不再讨论使用此解决方案;但是,如果我仍然使用它,让我们看看有什么问题:
JUnit用例:它也有效
Wildfly用例:似乎JAXWS采用了SSLContext,但是存在SSL异常(来自服务器的警报,CA未知)。这表明在如何建立连接方面甚至存在差异。如果使用JUnit执行代码,为什么它可以工作?这证明KeyStore / TrustStore已使用正确的证书正确设置。不是吗?
修改 还有一个证明,问题是Wildfly使用的JAXWS实现:如果我只是执行一个简单的HttpsConnection,它甚至可以在Wildfly中使用我自己的KeyStore / TrustStore:
url = new URL("https://hostname:443/.../...");
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
System.out.println(Utils.inputStreamToString(con.getInputStream()));
那么最好的做法是什么? - >作为问题标题,我想尝试使Wildfly也使用JAXWS-RI而不是Apache CXF。但是直到现在我才开始工作。我试图将以下依赖项放在pom中:
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.2.10</version>
</dependency>
但这给了我以下例外:
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]
有什么问题?如何使Wildfly以相同的方式工作,就像代码是从同一个项目执行但“作为JUnit测试”一样?
修改 如果您有一个提示如何以不同的方式实现目标(使用带有客户端身份验证的SOAP在Wildfly 8.2.1上发送SOAP请求)(前提是它是一个干净的Java EE解决方案 - 即不发送自己的XML主体:-)和不是像Axis 1)那样过于古老的framworks,也欢迎! 我确实需要一个解决方案 - 我已经好几天了......
答案 0 :(得分:2)
好的,最后,我放弃了尝试替换使用的JAX-WS实现。我得到了正确设置Apache CXF。
答案 1 :(得分:1)
这解决了问题:https://stackoverflow.com/a/46894256/8190026。 Wildfly将使用sun实现而不是apache.cxf
答案 2 :(得分:0)
我觉得很难。有一些关于此的评论。顺便说一句,我认为WildFly使用RESTEasy而不是CXF