Sending SOAP messages through HTTPS using SAAJ

Introduction
This is just a step by step tutorial for calling services by sending SOAP messages through HTTPS. I had a project to call a network device using SOAP messages. I didn’t find a complete solution, so I developed it.

SAAJ
I’ve used SAAJ for calling web services. It is well known for Java developers.

Steps
The process contains below steps:
1. Export the HTTPS Certificate into a file
2. Import the HTTPS Certificate into Java HTTPS certificates
3. Creating a SOAP connection
4. Creating a SOAP message
5. Populating the message
6. Trust to HTTPS certificates
7. Sending the message
8. Retrieving the reply

Get the Certificate
Assume the WSDL address is:

https://192.168.10.1:8991/wsdl/balance.wsdl

Read this to find out how to get the certificate for access to the upper WSDL address.
Here I saved the certificate in “amirssw.cer” file.
Java HTTPS certificates stored in

$JAVA_HOME/jre/lib/security/cacerts

To import your new certificate into “cacerts” run below command:

sudo keytool -import -file amirssw.cer -keystore cacerts

The password is “changeit”.

SOAP message
In my sample SOAP message stored in a file: “/home/amir/projects/mine/p8/message/helloWorld.msg”.
You can find a sample SOAP message here.

Java Code
This is a simple code that shows clearly how to send a SOAP message through HTTPS. The only different between sending the message on HTTP over HTTPS is the URL and doTrustToCertificates() method call just before sending the message.

package com.hexican.webssl;

import javax.net.ssl.*;
import javax.xml.soap.*;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.FileInputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.Vector;

public class Client {

    public static void main(String[] args) {
        talk("https://192.168.10.1:8991/balance/soap", "/home/amir/projects/mine/p8/message/helloWorld.msg");
    }

    private static void talk(String urlval, String msgPath) {
        try {
            // Create message
            MessageFactory mf = MessageFactory.newInstance();
            SOAPMessage msg = mf.createMessage();

            // Object for message parts
            SOAPPart sp = msg.getSOAPPart();
            StreamSource prepMsg = new StreamSource(new FileInputStream(msgPath));
            sp.setContent(prepMsg);

            // Save message
            msg.saveChanges();

            // View input
            System.out.println("\n Soap request:\n");
            msg.writeTo(System.out);
            System.out.println();

            // Trust to certificates
            doTrustToCertificates();

            //SOAPMessage rp = conn.call(msg, urlval);
            SOAPMessage rp = sendMessage(msg, urlval);

            // View the output
            System.out.println("\nXML response\n");

            // Create transformer
            TransformerFactory tff = TransformerFactory.newInstance();
            Transformer tf = tff.newTransformer();

            // Get reply content
            Source sc = rp.getSOAPPart().getContent();

            // Set output transformation
            StreamResult result = new StreamResult(System.out);
            tf.transform(sc, result);
            System.out.println();

            // now GET the Response and PARSE IT !
            Vector list = new Vector();
            SOAPBody soapBody = rp.getSOAPBody();
            Iterator iterator1 = soapBody.getChildElements();
            while (iterator1.hasNext()) {
                SOAPBodyElement ThisBodyElement = (SOAPBodyElement) iterator1.next();
                Iterator it2 = ThisBodyElement.getChildElements();
                while (it2.hasNext()) {
                    SOAPElement child2 = (SOAPElement) it2.next();
                    Iterator it3 = child2.getChildElements();
                    while (it3.hasNext()) {
                        SOAPElement child3 = (SOAPElement) it3.next();
                        String value = child3.getValue();
                        list.addElement(value);
                    }
                }
            }
            for (int i = 0; i < list.size(); i++) {
                System.out.println(list.elementAt(i));
            }
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }

static public SOAPMessage sendMessage(SOAPMessage message, String endPoint) throws MalformedURLException, SOAPException {
        SOAPMessage result = null;
        if (endPoint != null && message != null) {
            URL url = new URL(endPoint);
            SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance();
            SOAPConnection connection = null;
            long time = System.currentTimeMillis();
            try {
                connection = scf.createConnection(); //point-to-point connection
                result = connection.call(message, url);
            } finally {
                if (connection != null) {
                    try {
                        connection.close();
                    } catch (SOAPException soape) {
                        System.out.print("Can't close SOAPConnection:" + soape);
                    }
                }
            }
        }
        return result;
    }

    static public void doTrustToCertificates() throws Exception {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }
                }
        };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) {
                    System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
                }
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }
}

Done.

This entry was posted in Java, Networking, Software Engineering. Bookmark the permalink.

19 Responses to Sending SOAP messages through HTTPS using SAAJ

  1. Patrica Dalponte says:

    Keep functioning ,fantastic job!

  2. Priya says:

    This does not work for me

    gets me the following error

    Jul 1, 2011 12:05:40 PM com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection post
    SEVERE: SAAJ0008: Bad Response; Bad Request
    java.security.PrivilegedActionException: com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Bad response: (400Bad Request

    can you help?

  3. kaophie says:

    Excellent, thanks a lot.

  4. EmejiaSV says:

    HEyyy Excelent example its nice thanks you for you time and post on topic

  5. pravat kumar dash says:

    it solves my problem. keep posting..
    Thanks a lot,

  6. Siva Dhulipudi says:

    I am getting compilation error at line
    Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
    Please help me.
    Access restriction: The type Provider is not accessible due to restriction on required library C:\java\jdk1.6.0_38\jre\lib\jsse.jar

  7. Vishal D says:

    I am getting compilation error at line
    Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
    Please help me.
    Access restriction: The type Provider is not accessible due to restriction on required library C:\java\jdk1.6.0_38\jre\lib\jsse.jar

    HostnameVerifier hv = new HostnameVerifier() {
    public boolean verify(String urlHostName, SSLSession session) {

    The type new HostnameVerifier(){} must implement the inherited abstract method HostnameVerifier.verify(String, SSLSession)
    &
    SSLSession cannot be resolved to a type

    • Vishal D says:

      i have just removed JRE system library from my project build path and re added. just the error message disappears, how it happened i don’t know but my error got resolved.

  8. tong123123 says:

    I don’t know why we already “import your new certificate into “cacerts”, why still need call doTrustToCertificates() ?

  9. Karan says:

    thanks a lot

  10. Johne165 says:

    This actually answered my drawback, thank you! geddgcdbefkk

  11. JohnnyP says:

    Hey, this may be a silly question – Does this code need to be hosted in a web container in order to run correctly?

  12. quychau says:

    This actually what i’m searching for. you saved my days! thank you.

  13. Johnk729 says:

    Hello! Do you use Twitter? I’d like to follow you if that would be okay. I’m undoubtedly enjoying your blog and look forward to new posts. aebdbdfddada

Leave a Reply