1

I'm trying to integrate with an external webservice and it use a certificate with TLS 1.0 protocol.

I've tried setting -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2,SSLv3 but the outbound gateway still uses TLSv1.2. It works correctly if I just limit the option to TLSv1 but I can't do that since I'm integrating to a lot of external services.

How can you set the protocol on the outbound gateway itself?

I tried doing that with this code but I ran to an exception:

SimpleWebServiceOutboundGateway handler = new SimpleWebServiceOutboundGateway(url);
HttpComponentsMessageSender sender = new HttpComponentsMessageSender();
SSLContext sslContext = SSLContext.getDefault();
sslContext.getDefaultSSLParameters().setProtocols(new String[]{"TLSv1"});
CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
sender.setHttpClient(httpClient);
handler.setMessageSender(sender);

Exception:

Caused by: org.apache.http.client.ClientProtocolException: null
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
    at org.springframework.ws.transport.http.HttpComponentsConnection.onSendAfterWrite(HttpComponentsConnection.java:121)
    at org.springframework.ws.transport.AbstractWebServiceConnection.send(AbstractWebServiceConnection.java:48)
    at org.springframework.ws.client.core.WebServiceTemplate.sendRequest(WebServiceTemplate.java:658)
    at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:606)
    at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:555)
    ... 91 common frames omitted
Caused by: org.apache.http.ProtocolException: Content-Length header already present
    at org.apache.http.protocol.RequestContent.process(RequestContent.java:97)
    at org.apache.http.protocol.ImmutableHttpProcessor.process(ImmutableHttpProcessor.java:133)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:182)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    ... 99 common frames omitted
Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
Bob Santos
  • 55
  • 1
  • 7
  • You might want to [enable SSL debugging](https://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/ReadDebug.html) to see what's causing the exception. Due to the insecurity of certain ciphers there are almost (if any at all) secure ciphers left for TLSv1/1.1 to use and usually the lack of secure ciphers will prevent a succeeding SSL handshake. Just enabling the TLSv1 protocol may therefore [not be enough](https://stackoverflow.com/questions/46356762/enable-tlsv1-ciphers-in-spring-boot) – Roman Vottner Nov 21 '17 at 10:49
  • @RomanVottner The cipher is available. The problem is that if I enable TLSv1 along with the other protocols it fails because the application uses TLSv1.2 by default. But if I just enable TLSv1 alone then it works. The main difference is `ClientHello, TLSv1.2` for the former and `ClientHello, TLSv1` for the latter. The latter gets to verify the correct certificate at the end. – Bob Santos Nov 21 '17 at 12:43
  • @RomanVottner Here's a log snippet for both: https://pastebin.com/6b8LWT4D – Bob Santos Nov 21 '17 at 12:50

1 Answers1

2

I looked at related documentations for HttpComponentsMessengerSender and found HttpComponentsMessageSender.RemoveSoapHeadersInterceptor

HttpClient HttpRequestInterceptor implementation that removes Content-Length and Transfer-Encoding headers from the request. Necessary, because some SAAJ and other SOAP implementations set these headers themselves, and HttpClient throws an exception if they have been set.

The solution is to add it to the interceptors of HttpComponentsMessengerSender.

The final version of the sender is:

SSLContext sslContext = SSLContexts.custom().useProtocol("TLSv1").build();
CloseableHttpClient httpClient = HttpClients.custom()
            .setSSLContext(sslContext)
            .addInterceptorFirst(new 
HttpComponentsMessageSender.RemoveSoapHeadersInterceptor())
            .build();

HttpComponentsMessageSender sender = new HttpComponentsMessageSender(httpClient);
Bob Santos
  • 55
  • 1
  • 7