6

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.

szhem
  • 4,672
  • 2
  • 18
  • 30
  • Could you please provide your WCF service configuration? – Sergey Vyacheslavovich Brunov Jan 28 '12 at 15:57
  • Unfortunately this is the external service that is used by organization I'm working for. Probably I will obtain the config by Monday. The problem occurs only when I'm trying to send the request which is big enough. When receiving a big response there are no any problems. The developer of WCF service says that there are no any issues with calling this service using .net client from their internal network. – szhem Jan 28 '12 at 16:18
  • Are they using the same endpoint as you from their internal network? – Richard Blewett Jan 28 '12 at 16:29
  • Yes, the endpoint is exactly the same. – szhem Jan 28 '12 at 17:05
  • 1
    @mijer, it seems that the client side is misconfigured. Could you show us Java client code? – Sergey Vyacheslavovich Brunov Jan 28 '12 at 17:15
  • @Serge, the post is updated with the code that is used to test service response. – szhem Jan 28 '12 at 22:34
  • Are you sure that IIS service is configured to acept HTTP post requests? Maybe the server is acepting SOAP but not HTTP Post... – jlvaquero Feb 04 '12 at 19:40
  • @user551263, I'm sure. Transport layer is HTTP. Moreover I have mentioned that requests that are less than 48681 bytes in size are accepted and handled successfully. – szhem Feb 04 '12 at 22:53
  • @mijer what happens if you try the same thing from Java without SSL (pure HTTP) ? – Yahia Feb 05 '12 at 12:23
  • 1
    Why do you pin the result _only_ to the size of your request? – Jörg Beyer Feb 06 '12 at 21:57
  • @Yahia, unfortunately this is the external service that is not under my control, so it's hardly possible to disable ssl. – szhem Feb 06 '12 at 23:01
  • @Jörg, it's the first thing that strikes the eye when sending a number of different files. Finally I suppose, that the issue may be connected with the basicHttpBinding of the wcf service that previously was the customBinding. I will check it soon. – szhem Feb 06 '12 at 23:02
  • 2
    Since the issue seems to be on the client side, can you use fiddler to capture requests from both java and .net clients and compare them (including the headers) ? – Kiran Mothe Feb 07 '12 at 13:12
  • So, do you use client certificates in the .net client? – anders.norgaard Feb 08 '12 at 21:53
  • I do. .net client seems to work fine with exactly the same private key and certificate. – szhem Feb 08 '12 at 22:57

5 Answers5

1

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.

anders.norgaard
  • 1,062
  • 13
  • 23
  • I have. Unfortunately from the java side there is nothing special. Here is how the interaction looks like: 1. an _ack push_ from java client to .net service; 2. read time out; 3. _ack fin_ packet from java client to .net service; 4. .net service replies with _ack_ – szhem Feb 07 '12 at 08:42
  • .net client is provided by developers of the service, so I have to ask them to modify it a little bit. I will let you know about the results soon. – szhem Feb 08 '12 at 23:04
  • Hi, @anders. I have posted the answer to this question. The problem was in tls renegotiation. – szhem Feb 10 '12 at 08:36
1

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.
szhem
  • 4,672
  • 2
  • 18
  • 30
0

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.

Jörg Beyer
  • 3,631
  • 21
  • 35
  • - The issue is surely not in the quota, as .net client is able to send larger requests - I don't think the the structure of the request is an issue, as it was taken from trace of .net client - Server side policies as I mentioned earlier in the topic allows much larger requests – szhem Feb 06 '12 at 23:07
0

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

Rajesh
  • 7,766
  • 5
  • 22
  • 35
0

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.

Shiraz Bhaiji
  • 64,065
  • 34
  • 143
  • 252
  • Java uses soap 1.1. Sorry that this is not clearly visible, but soap namespace in the samples is *http\://schemas.xmlsoap.org/soap/envelope/*, content-type is *text/xml*. – szhem Feb 07 '12 at 20:20