Apache CXF Exception in SSL communication: SocketT

2020-05-27 08:54发布

So here's the deal. I have a web service WSDL that I need to make SOAP calls to outside my corporate network. The webservice is HTTPS SOAP, and requires a client certificate. I've generated the client code in Java from wsdl2java, and things seem to go pretty well.

What I cannot do right now is receive a response from the web service through CXF. The SSL handshake seems to go just dandy even up to the point where CXF tries to do an HTTP POST, but times out waiting for a response (shown below):

Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: false
Is secure renegotiation: false
*** HelloRequest (empty)
main, SEND TLSv1 ALERT:  warning, description = no_renegotiation
Padded plaintext before ENCRYPTION:  len = 24
0000: 01 64 01 FD 5B 38 03 A6   70 41 57 58 6D 75 60 F7  .d..[8..pAWXmu`.
0010: 93 1F 02 F3 C4 46 01 01                            .....F..
main, WRITE: TLSv1 Alert, length = 24
[Raw write]: length = 29
0000: 15 03 01 00 18 0C 9B DF   1B 60 AB 12 EE C7 CF C9  .........`......
0010: 62 97 A5 5D 5F 14 48 E1   9F AD 8A 08 05           b..]_.H......
main, handling exception: java.net.SocketTimeoutException: Read timed out
main, called close()
main, called closeInternal(true)
main, SEND TLSv1 ALERT:  warning, description = close_notify
Padded plaintext before ENCRYPTION:  len = 24
0000: 01 00 BD 99 7A 7C 72 1F   BB 11 2D AB 3F 53 C9 CD  ....z.r...-.?S..

... continuing on

Now, if I use curl or somethign similar, I can get a response in less than a second, so I know the web service isn't at fault. Below is the entirety of the code necessary to create the service port, including setup with TLS and an HTTP proxy. I have a very simple JUnit test to create and run this, too:

public static MYPORT setupTLS(MYPORT port) throws IOException,
        GeneralSecurityException {

    HTTPConduit httpConduit = (HTTPConduit) ClientProxy.getClient(port)
            .getConduit();


    String keyPassword = "password";
    KeyStore keyStore = KeyStore.getInstance("pkcs12");
    URL pkcs12_file = MECTPortFactory.class.getResource(System
            .getProperty("pkcs12.keyFile"));
    InputStream keyFile = pkcs12_file.openStream();
    keyStore.load(keyFile, keyPassword.toCharArray());
    KeyManager[] myKeyManagers = getKeyManagers(keyStore, keyPassword);

    TLSClientParameters tlsCP = new TLSClientParameters();
    tlsCP.setKeyManagers(myKeyManagers);
    tlsCP.setDisableCNCheck(true);
    FiltersType cipher_suite_filter = new FiltersType();
    cipher_suite_filter.getInclude().add("SSL_RSA_WITH_3DES_EDE_CBC_SHA");
    cipher_suite_filter.getExclude().add(".*_DH_anon_.*");
    tlsCP.setCipherSuitesFilter(cipher_suite_filter);
    httpConduit.setTlsClientParameters(tlsCP);
    httpConduit.setClient(getHttpClient());

    return port;
}

private static HTTPClientPolicy getHttpClient() {
    HTTPClientPolicy client_policy = new HTTPClientPolicy();
    client_policy.setProxyServer("PROXY_SERVER_ADDRESS");
    client_policy.setProxyServerPort(8080);
    client_policy.setAutoRedirect(true);
    client_policy.setConnection(ConnectionType.KEEP_ALIVE);
    client_policy.setAllowChunking(true);
    client_policy.setReceiveTimeout(10000);
    return client_policy;
}

private static KeyManager[] getKeyManagers(KeyStore keyStore,
        String keyPassword) throws GeneralSecurityException, IOException {
    String alg = KeyManagerFactory.getDefaultAlgorithm();
    char[] keyPass = keyPassword != null ? keyPassword.toCharArray() : null;
    KeyManagerFactory fac = KeyManagerFactory.getInstance(alg);
    fac.init(keyStore, keyPass);
    return fac.getKeyManagers();
}

Edit:

I've fiddled with some client settings such as changing whether to AutoRedirect, AllowChunking, etc., with no differences, so I don't think that's causing errors.

Edit2:

I don't get a response from the web service. How can I troubleshoot and fix what is causing CXF to time out instead of receiving the response?

标签: java ssl proxy cxf
1条回答
神经病院院长
2楼-- · 2020-05-27 09:23

OMG! I figured it out.

So I went traipsing through the interwebs and found this little gem:

How to configure SoapUI with client certificate authentication

And it references a very important note from Oracle/Sun:

Transport Layer Security (TLS) Renegotiation Issue Readme

Applications that receive a renegotiation request from the peer will respond according to the type of connection in place:

TLSv1: A warning Alert message of type "no_renegotiation(100)" will be sent to the peer and the connection will remain open.

then, further down:

Renegotiations can be re-enabled for those applications that need it by setting the new system property sun.security.ssl.allowUnsafeRenegotiation to true before the JSSE library is initialized. There are several ways to set this property:

  1. Command Line:

    % java -Dsun.security.ssl.allowUnsafeRenegotiation=true Main

  2. Java Control Panel (Java Plug-in / Java Web Start) - Runtime Environment.

  3. Within the application:

    java.lang.System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", true);

Note that TLS/SSL renegotiation will not occur unless both client and server have enabled renegotiations.

So the long and short of it? System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");

And things. Just. Work.

查看更多
登录 后发表回答