Tag Archives: HTTPS

Consuming a SOAP webservice over HTTPS

In the previous post, we talked about producing and consuming a SOAP web service here. This post will be a sequel to that post since recently I faced a similar issue during my project. In this post, we will talk about how to consume a SOAP web service over https. Since this will be a small post, we will not be posting any code on github.

Problem –

While consuming a SOAP web service which is behind SSL, if you don’t handle SSL certificates, you will run into following error


sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
 at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
 at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
 at sun.security.validator.Validator.validate(Validator.java:260)
 at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
 at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
 at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
 at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1351)
 at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:156)
 at sun.security.ssl.Handshaker.processLoop(Handshaker.java:925)
 at sun.security.ssl.Handshaker.process_record(Handshaker.java:860)
 at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1043)
 at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343)
 at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:728)
 at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
 at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:138)
 at SSLPoke.main(SSLPoke.java:31)
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
 at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:145)
 at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
 at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
 at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
 ... 15 more

Solution –

Basically this error is happening if your SOAP web service is on SSL and the client is trying to connect to web service, web service doesn’t recognize the client and throws this error.

To resolve this error, you can download a SSL certificate from the server where you are hosting SOAP web service and import that certificate on your client machine’s keystore. In production environment, you should have a way to access this keystore when a call is made to the web service.

Let’s assume that our webservice from post is on SSL, like https://localhost:8943/benefits/endpoints/users.wsdl. If you access this URL in browser, you will be able to see the SSL certificate. Export this SSL certificate in base 64 format file, example sslcertificate.crt. Import this certificate in


keytool -import -alias sslcertificateofserver -keystore truststore.jks -storepass changeit -file sslcertificate.crt

Now, we will change the configuration class we wrote to configure web service components.


package com.betterjavacode.benefits.views;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;

@Configuration
public class ClientAppConfig
{
   private Resource getKeyStore()
   {
      Environment.getProperty("betterjavacode.com.keystore");
   }

   private String getKeystorePassword()
   {
      Environment.getProperty("betterjavacode.com.keyStorePassword");
   }

   @Bean
   public Jaxb2Marshaller marshaller()
   {
     Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
     marshaller.setContextPath("com.betterjavacode.benefits.soap");
     return marshaller;
   }

   @Bean
    public UserClient userClient(Jaxb2Marshaller marshaller) {
        // WSDL URL - http://localhost:8080/benefits/endpoints/users.wsdl
        UserClient uc = new UserClient();
        uc.setDefaultUri("http://localhost:8080/benefits/endpoints/users.wsdl");
        uc.setMarshaller(marshaller);
        uc.setUnmarshaller(marshaller);

        FileInputStream fis = new FileInputStream(getKeyStore());
        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(fis, getKeyStorePassword().toCharArray());

        try {
            fis.close();
        } catch (IOException e) {
        }
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(ks, keyStorePassword.toCharArray());

        FileInputStream fisTS = new FileInputStream(getKeyStore());
        KeyStore ts = KeyStore.getInstance("JKS");
        ts.load(fisTS, trustStorePassword.toCharArray());

        try {
            fisTS.close();
        } catch(IOException e) {
        }
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(ts);

        HttpsUrlConnectionMessageSender messageSender = new HttpsUrlConnectionMessageSender();
        messageSender.setKeyManagers(keyManagerFactory.getKeyManagers());
        messageSender.setTrustManagers(trustManagerFactory.getTrustManagers());

        HostNameVerifier hv = new HostNameVerifier(){
           @Override
           public boolean verify(    String hostname,    SSLSession session){
                  return true;
           }
        }
        messageSender.setHostnameVerifier(hv);
        uc.setMessageSender(messageSender);
        return uc;
    }

This change should fix the error about PKIX path building failed. I will post the code for this article on github in next few days.

Conclusion –

In short, we showed how to consume a SOAP web service over SSL by adding keystore and truststore check during runtime.