15

I try to send a SOAP message in an XML file to a webservice and than grab the binary output and decode it. Endpoint uses HTTPS protocol, so I used TrustManager in my code to avoid PKIX problems. You can see my code here:

import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.X509Certificate;

public class Main{
    public static void sendSoapRequest() throws Exception {
        String SOAPUrl = "URL HERE";
        String xmlFile2Send = ".\\src\\request.xml";
        String responseFileName = ".\\src\\response.xml";
        String inputLine;

        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; }
            public void checkClientTrusted(X509Certificate[] certs, String authType) { }
            public void checkServerTrusted(X509Certificate[] certs, String authType) { }

        } };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

        // Create all-trusting host name verifier
        HostnameVerifier allHostsValid = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) { return true; }
        };
        // Install the all-trusting host verifier
        HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);

        // Create the connection with http
        URL url = new URL(SOAPUrl);
        URLConnection connection = url.openConnection();
        HttpURLConnection httpConn = (HttpURLConnection) connection;
        FileInputStream fin = new FileInputStream(xmlFile2Send);
        ByteArrayOutputStream bout = new ByteArrayOutputStream();

        copy(fin, bout);
        fin.close();

        byte[] b = bout.toByteArray();
        StringBuffer buf=new StringBuffer();
        String s=new String(b);

        b=s.getBytes();

        // Set the appropriate HTTP parameters.
        httpConn.setRequestProperty("Content-Length", String.valueOf(b.length));
        httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
        httpConn.setRequestProperty("SOAPAction", "");
        httpConn.setRequestMethod("POST");
        httpConn.setDoOutput(true);

        OutputStream out = httpConn.getOutputStream();
        out.write(b);
        out.close();

        // Read the response.
        httpConn.connect();
        System.out.println("http connection status :"+ httpConn.getResponseMessage());
        InputStreamReader isr = new InputStreamReader(httpConn.getInputStream());
        BufferedReader in = new BufferedReader(isr);

        while ((inputLine = in.readLine()) != null)
            System.out.println(inputLine);
        FileOutputStream fos=new FileOutputStream(responseFileName);
        copy(httpConn.getInputStream(),fos);
        in.close();
    }

    public static void copy(InputStream in, OutputStream out) throws IOException {

        synchronized (in) {
            synchronized (out) {
                byte[] buffer = new byte[256];
                while (true) {
                    int bytesRead = in.read(buffer);
                    if (bytesRead == -1)
                        break;
                    out.write(buffer, 0, bytesRead);
                }
            }
        }
    }

    public static void main(String args[]) throws Exception {
        sendSoapRequest();
    }
}

I get following error code, when I execute this.

Exception in thread "main" java.io.IOException: Server returned HTTP response code: 403 for URL

16
  • 1
    You should provide credentials to gain access. Authentication header with login/password in base64 for basic authentication, simplest variant, but it depends of server side. You should provide what server required. Commented Jul 31, 2017 at 7:51
  • @user1516873 : No need for authentication on this server. Commented Jul 31, 2017 at 12:15
  • 3
    403-forbidden means that the request has reached the server and is valid but the server has denied the access to the requested resource. Summarizing, the SSL connection is ok, so you are invoking to the wrong endpoint or there are missing credentials in the SOAP header. Commented Aug 15, 2017 at 13:57
  • @pedrofb : I see, but when I use content of XML files in a SOAP request with SoapUI, I get response from the same endpoint. Commented Aug 16, 2017 at 6:51
  • 1
    If the content is the same, then inspect and compare the headers that is actually sending SOAPUI and your connection. It is possible that the server detects some incorrectness and treats it as 403 Commented Aug 16, 2017 at 7:00

4 Answers 4

9
+25

Your implementation is alright, the problem is related to your Content-Type header, in fact.

The value text/xml; charset=utf-8 is the default Content-Type of SOAP 1.1, which is probably not the version of yours. SOAP 1.2 expects a header of type application/soap+xml; charset=utf-8, so changing your line of code to this one below is gonna make it working:

httpConn.setRequestProperty("Content-Type", "application/soap+xml; charset=utf-8");

In SoapUI, it's possible to check the headers calling the request and going to the Headers tab on the bottom of the window:

enter image description here

Then, you can compare the differences between your application configs and the SoapUI ones.

Sign up to request clarification or add additional context in comments.

6 Comments

I can't find any headers in SoapUI and I get the exact same error with this Content-Type too.
The headers are on the response side, not in the request. Make a request and check there.
It is application/timestamp-reply on the response side.
Is there possible for you to share the endpoint? Or at least the service project at GitHub? It's very hard to guess the specificities of your implementation.
@bosco : It solved my similar problem. Thanks a ton!.
|
2

403 error might be related to your soap request headers being sent to the server. All Hosts valid will allow your Java App to trust the SSL Cert for the URL. Check if your server is expecting soap header with username/password. If you have access to this server, you can check through the web server logs on where your request is failing. Error code points to to missing Soap Header particularly Soap Headers with username and password

1 Comment

No username/password is needed, it is not set in the current SoapUI request.
1

Wonder if your SOAP request contains any kind of authentication information in headers like SAML. One option is, in your above code where you read the file and send the data to server, instead of sending it to server you dump it to another file. Dump that byteoutputstream. Then copy text from that file and put it in SOAP UI and try running that. Does that work?

7 Comments

Why is it better to make another file with the same content?
That's specifically in case your SOAP request contains SAML or some other binary data. That's to see if it is getting corrupted during file IO. Your code contains this small piece: byte[] b = bout.toByteArray(); StringBuffer buf=new StringBuffer(); String s=new String(b); b=s.getBytes(); where you are converting the data to String and back to bytes. Is there some specific need to do that?
As @pedrofb suggested, I deleted these lines earlier from code.
Oh, ok. And were you able to capture the headers being sent from SOAP UI vs the ones being sent from your code. Are those same too.
Yes, I sent request to Requestbin, but body was empty. Is there something wrong with my Java code?
|
0

In a similar situation we have been some time before, and as long as trying TrustManager didn't work as expected, we managed to overcome this problem by installing the certificate from server to JVM's keystore (JVM used to run the application). More information about how to do it you can find in several posts, like How to import a .cer certificate into a java keystore?

I am aware that it is a try to force JVM to accept SSL certificates, and this functionality would be better to live in application context, but as long as we were building a web application which ran in specific application servers, the implemented solution was an accepted one.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.