Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm working on a server in a distributed application that has browser clients and also participates in server-to-server communication with a 3rd party. My server has a CA-signed certificate to let my clients connect using TLS (SSL) communication using HTTP/S and XMPP(secure). That's all working fine.

Now I need to securely connect to a 3rd party server using JAX-WS over HTTPS/SSL. In this communication, my server acts as client in the JAX-WS interation and I've a client certificate signed by the 3rd 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 are using 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. seemed to indicate separation, but it's not the case)

I also tried adding my client certificate into my original keystore, but -again- my other components don't seem to like it either.

I think that my only option left is to programmatically hook into the JAX-WS HTTPS configuration to setup the keystore and truststore for the client JAX-WS interaction.

Any ideas/pointers on how to do this? All information I find either uses the javax.net.ssl.keyStore method or is setting the global SSLContext that -I guess- will end up in the same confilc. The closest I got to something helpful was this old bug report that requests the feature I need: Add support for passing an SSLContext to the JAX-WS client runtime

Any takes?

@EJP That bug report is rather a feature request and does not mention how it should/will be done. maasg Jun 14, 2012 at 11:12

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. ∎

This looks only useful if your WSDL is accessible under http://, but what if it's also under https://? The client fails on the first step (getting WSDL). – Lukasz Frankowski Oct 25, 2013 at 10:04 We had the same situation and ended up having a copy of the wsdl's locally. Otherwise you have precisely this bootstrap problem. – maasg Oct 25, 2013 at 10:22 FYI: if your application is using JAXWS-RI then you should use a slightly different property: com.sun.xml.ws.transport.https.client.SSLSocketFactory. I specify both to satisfy different stacks in unit testing and actual application environment (don't ask). – mvreijn Aug 15, 2016 at 14:46 @mvreijn, man you saved my life.... i know there are constants that represent these literal strings... do you know what are they? – Rafael Lima Aug 1, 2020 at 2:32 @RafaelLima I checked my source code documentation (it exists!) and I had documented a link to jax-ws.java.net/nonav/2.2.8/javadocs/rt/constant-values.html. Unfortunately the project has moved so the list of constants is in a different place so it seems. – mvreijn Aug 10, 2020 at 21:27

This is how I solved it based on this post with some minor tweaks. This solution does not require 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() );
                Where is webservicePort defined in the above code (it's used on last line of code after the (BindingProvider) cast?
– John
                Mar 14, 2018 at 0:44
                @Radek, mind stating what is the type of webservicePort? It looks like to be javax.xml.ws.Service but not sure.
– user6490459
                Dec 15, 2018 at 20:49
                Guys, I posted this back in 2012. I honestly don't remember where I defined that port. Sorry that it's not explained but I don't have access to that code anymore to actually check and let you know. I might have taken it from an injected parameter and not had to define it myself, not sure. It should not be that hard to figure it out I suppose if you do some research on BindingProvider and what instantiates it. If I made it work back then, so can you. Good luck!
– Radek
                Dec 19, 2018 at 21:59

I tried the following and it didn't work on my environment:

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

But different property worked like a charm:

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

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

What version of everything? It looks like different versions of wsimport generate different kinds of code... it's possible that they require different property-names as well. – Christopher Schultz Sep 12, 2013 at 19:18 When you explicitly add jaxws-rt JARs to your application you need to use the property names that DON'T contain .internal.. If you use the JAXWS-RT included in the JDK you need to use the ones containing ".internal.". JAXWSProperties.SSL_SOCKET_FACTORY resolved to "com.sun.xml.ws.transport.https.client.SSLSocketFactory" – Philip Helger Jan 28, 2016 at 8:49

By combining Radek and l0co's answers you can access the WSDL behind 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
                Does keystore in getResourceAsStream(keystore) refer to the path of the certificate file?
– swifthorseman
                Dec 4, 2015 at 11:01
                In this case, it's the path within the class path. You can use a File instead of getClass().getResourceAsStream() if you need absolute file path.
– cidus
                Dec 5, 2015 at 20:40
                not great for me because I make other calls that I want to use the default ssl socket factory and this would stuff them up
– Dave Moten
                Jul 4, 2018 at 3:33
                This worked perfectly for me as I my usecase required the context to be switched based off a parameter in the header. Thank you
– adot
                Jun 15, 2022 at 23:11

The above is fine (as I said in comment) unless your WSDL is accessible with https:// too.

Here is my workaround for this:

Set you SSLSocketFactory as default:

HttpsURLConnection.setDefaultSSLSocketFactory(...);

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

<http-conf:conduit name="*.http-conduit">
  <http-conf:tlsClientParameters useHttpsURLConnectionDefaultSslSocketFactory="true" />
<http-conf:conduit>

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

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

This is my example, do all network ops

  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 use UrlConnection, you can use any library you want in handler. Have fun!

For those trying and still not getting it to work, 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 from the Property key is gone here.

I use Wildfly 8 and it does not work for me either. (What do you mean with dynamic Dispatcher? - Please check my Posts: stackoverflow.com/questions/37158821/… and stackoverflow.com/questions/37158821/… – badera May 11, 2016 at 12:11

I had problems trusting a self signed certificate when setting up the trust manager. I used the SSLContexts builder of the 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 passing in the new TrustSelfSignedStrategy() as an argument in the loadTrustMaterial method.

we faced this problem, due to a keystore clash between system integrations, so we used the following code.

private PerSecurityWS prepareConnectionPort()  {
      final String HOST_BUNDLE_SYMBOLIC_NAME = "wpp.ibm.dailyexchangerates";
      final String PATH_TO_SLL = "ssl/<your p.12 certificate>";
      final File ksFile = getFile(HOST_BUNDLE_SYMBOLIC_NAME, PATH_TO_SLL);
      final String serverURI = "you url";
      final KeyStore keyStore = KeyStore.getInstance("pkcs12");
      keyStore.load(new FileInputStream(ksFile.getAbsolutePath()), keyStorePassword.toCharArray());
      final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
      kmf.init(keyStore, keyStorePassword.toCharArray());
      final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        @Override
        public boolean verify(final String hostname, final SSLSession session) {
          return false;
      final SSLContext ctx = SSLContext.getInstance("TLS");
      ctx.init(kmf.getKeyManagers(), null, null);
      final SSLSocketFactory sslSocketFactory = ctx.getSocketFactory();
      final PerSecurityWS port = new PerSecurityWS_Service().getPerSecurityWSPort();
      final BindingProvider bindingProvider = (BindingProvider) port;
      bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory",sslSocketFactory);
      bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, serverURI);
      bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.hostname.verifier",DO_NOT_VERIFY);
      return port;

I tried the steps here:

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

And, that fixed the issue. I made some minor tweaks - I set the two parameters using System.getProperty...

Please quote the most relevant part of the link, in case the target site is unreachable or goes permanently offline. – Błażej Michalik Jun 23, 2017 at 17:20 This answer would set the trust store for the entire application. Relevant portion: -Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/cacerts -Djavax.net.ssl.trustStorePassword=password – EpicVoyage Apr 24, 2019 at 17:04

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.