szhem
szhem

Reputation: 4712

Unable to send a 48681 bytes message to secure wcf service from java

I have to call a secure WCF service from java using mutual authentication. Everything works fine except I'm unable to send messages which are greater than 48680 bytes in size. So 48680 byte messages are sent successfully, but 48681 byte - are not, and java application fails with read timed out exception, although WCF's quota settings permit much larger messages.

So what could be the problem?


EDIT

The source code:

package foo.bar;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.junit.Test;

import javax.net.ssl.*;
import java.io.*;
import java.net.URL;
import java.security.KeyStore;

public class ReadTimedOutTest {

    @Test
    public void testReadTimedOut() throws Exception {
        URL url = new URL("https://services/endpoint/");

        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        setUpSSL(connection);
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setRequestMethod("POST");
        connection.setRequestProperty("SOAPAction", "http://namespace/2012/01/service/Operation");
        connection.setRequestProperty("Accept", "*/*");
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");

        connection.setConnectTimeout(10 * 1000);
        connection.setReadTimeout(10 * 1000);
        connection.setInstanceFollowRedirects(true);

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        InputStream is = ReadTimedOutTest.class.getResourceAsStream("payload.failure.xml");
        try {
            IOUtils.copy(is, bos);
        } finally {
            is.close();
        }
        byte[] bytes = bos.toByteArray();
        connection.setRequestProperty("Content-Length", String.valueOf(bytes.length));

        OutputStream os = connection.getOutputStream();
        try {
            IOUtils.copy(new ByteArrayInputStream(bytes), os);
            os.flush();
        } finally {
            os.close();
        }

        int respCode = connection.getResponseCode();
        if(respCode >= HttpsURLConnection.HTTP_INTERNAL_ERROR) {
            is = connection.getErrorStream();
            try {
                IOUtils.copy(is, System.err);
            } finally {
                is.close();
            }
        } else {
            is = connection.getInputStream();
            try {
                IOUtils.copy(is, System.out);
            } finally {
                is.close();
            }
        }
    }

    private void setUpSSL(HttpsURLConnection connection) throws Exception {
        byte[] bytes = FileUtils.readFileToByteArray(new File("d:\\workspace\\temp\\keystore"));
        KeyStore keyStore = KeyStore.getInstance("JKS");
        keyStore.load(new ByteArrayInputStream(bytes), "changeit".toCharArray());
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509");
        keyManagerFactory.init(keyStore, "changeit".toCharArray());

        bytes = FileUtils.readFileToByteArray(new File("d:\\workspace\\temp\\truststore"));
        KeyStore trustStore = KeyStore.getInstance("JKS");
        trustStore.load(new ByteArrayInputStream(bytes), "changeit".toCharArray());
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
        trustManagerFactory.init(trustStore);

        SSLContext context = SSLContext.getInstance("TLS");
        context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
        SSLSocketFactory socketFactory = context.getSocketFactory();

        connection.setSSLSocketFactory(socketFactory);
    }

}

UPDATE

I have tested the service with .net WCF client and it was able to invoke the service successfully, so I'm wondering what could be the problem? Why WCF client is able to invoke the service and Java client, even if using ordinary HTTP POST request with UrlConnection, is not?


UPDATE

Here is sample of soap message

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <DoSomethingUseful xmlns="http://namespace/2012/01/service">
        ...
        </DoSomethingUseful>
    </soap:Body>
</soap:Envelope>

UPDATE

I was told that on the .net service side there are "Client certificate is required. No certificate was found in the request" messages which seem to occur on ssl session resumption. It happens only when Content-Length is greater than 48680 bytes. Also WCF service is configured with basicHttpBinding to use transport level security.

Upvotes: 6

Views: 1388

Answers (5)

szhem
szhem

Reputation: 4712

Finally, I resolved the issue. The problem was the following:

  1. cryptographic service provider of the given .net client supports tls renegotiation
  2. cryptographic provider of the java-client does not support tls renegotiation
  3. on the side of service there was no ClientCertNegotiation option set, so java client was not able to renegotiate.
  4. .net service was not responding to java-client that was waiting for the data, because this service expected a client-certificate, but the client was not able to provide it, as renegotiation is not supported.

Upvotes: 1

Shiraz Bhaiji
Shiraz Bhaiji

Reputation: 65391

This could be a SOAP version mismatch. The default version for basichttpbinding is SOAP 1.1. If the java client is using SOAP 1.2 you will get an error.

We have often seen that the error you get when the SOAP version does not match, has nothing to do with the real erros.

Upvotes: 0

Rajesh
Rajesh

Reputation: 7876

Have you tried sending in request from SOAPUI tool and checking if it behaves the same way. Also worth looking at the below link that discusses something about WCF Services and Java client.

Java Client and WCF Service

Upvotes: 0

J&#246;rg Beyer
J&#246;rg Beyer

Reputation: 3671

You asked, what could be the problem, here some suggestion:

  • the size of your request. That is basically you assumption, if I understand it right.
  • the structure of your request.
  • a server side policy, like request have to be smaller than 48681 bytes. In a comment you tell us that you are using an external server, not under your control
  • a server side bug. Remember the not under your control part and read it as buggy.
  • a race condition.

I would suggest to try a wider range of request. Do not only vary the size.

Upvotes: 0

anders.norgaard
anders.norgaard

Reputation: 1080

Have your tried to look at the actual packets being sent - eg. with tcpdump/Wireshark ( http://www.wireshark.org/ ) ?

I once had problems only on certain platforms reaching a service that was behind a very picky SSL offload engine.

Upvotes: 1

Related Questions