Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

wcf

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.

like image 849
szhem Avatar asked Jan 28 '12 15:01

szhem


2 Answers

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.

like image 79
anders.norgaard Avatar answered Nov 08 '22 20:11

anders.norgaard


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.
like image 44
szhem Avatar answered Nov 08 '22 19:11

szhem