1

My question(s):

It would appear one of the differences in the underlying sun.net.www.protocol.https.HttpsClient is the HostNameVerifier implementation - The problem appears to be currently in HttpsClient in the afterConnect method where setHost is not being called, and that doesn’t seem to refer to any SSLParameters - my attempt to work around this was to get our WS client invocation code to load our factory, I have been unsuccessful thus far-

1) How do I get our WS client invocation code to load our factory?

OR

2) How do I setup JBOSS to process this request correctly? (Assuming it is a JBOSS configuration)

The Stage: - Java Oracle JDK 1.8 64-bit - Jboss 6.4 EAP - AXIS2 - JAX - Certs are Valid and loaded correctly - I am able to replicate the error using a standalone java application and I am able to repair the error with a standalone java application.

Attempts:

1) Added a CXF out interceptor of PRE-PROTOCOL phase, which will add hostname in header.

public void handleMessage(Message message) {
       System.out.println("Inside handle message");
       Map<String, List> headers = (Map<String, List>) message.get(Message.PROTOCOL_HEADERS);
       try {
                  headers.put("Host", Collections.singletonList("ecm-users-dev.aexp.com"));
           } catch (Exception ce) {
           throw new Fault(ce);
       }
    }

2) Tried disabling HostNameVerfier as some blogs suggested enabling hostNameverfier would cause issues.

3) Created a wrapper around SSLSocketFactory to inject SSL parameters as suggested in below blog http://javabreaks.blogspot.com/2015/12/java-ssl-handshake-with-server-name.html

4) Injecting host parameters into httpconduit session through client policy.

final HTTPConduit httpConduit = (HTTPConduit) cxfClient.getConduit();
    final TLSClientParameters tlsCP = new TLSClientParameters();
   HTTPClientPolicy clientPolicy = new HTTPClientPolicy();
   clientPolicy.setHost(endpoint.getHost());
   httpConduit.setClient(clientPolicy);
   httpConduit.setTlsClientParameters(tlsCP);

5) Tried injecting wrapper SSLSocketfactory through binding provider.

What appears to be the issue: Setting the SNI..

My logs:

-------Working-----

14:11:02,417 INFO  [stdout] (http-/127.0.0.1:8080-2) Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA
14:11:02,419 I
NFO  [stdout] (http-/127.0.0.1:8080-2) Extension server_name, server_name: [type=host_name (0), value=some.server.value]
14:11:02,419 
INFO  [stdout] (http-/127.0.0.1:8080-2) ***

----Non-working-----

14:15:35,081 INFO  [stdout] (http-/127.0.0.1:8080-1) Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA
14:15:35,082 
INFO  [stdout] (http-/127.0.0.1:8080-1) ***

(this one is missing the SNI)

(two attempted) code snippets:

try{               bp.getRequestContext().put("com.sun.xml.ws.transport.https.client.SSLSocketFactory", new SSLSocketFactoryWrapper(sslContext.getSocketFactory(), sslParameters));
                        } catch (Exception e) {
                            log.error("Error of port default SSL configuration applying", e);
                            throw new IllegalArgumentException("fail to configure ws client by configuration", e);
                           }

--------------------

bp.getRequestContext().put("com.sun.xml.ws.transport.https.client.SSLSocketFactory" , new SSLSocketFactoryFacade().createSocket(endPoint,443));
                        log.info("exit getServiceClient(): " + client);
                        return client;
        } catch(Throwable e) {
                        log.error("Error creating the Service Client", e);
                        throw new RuntimeException("Error creating the Service Client: " + e.getMessage(), e);
    }

Similar Question:

(Suggestion did not work) Extended server_name (SNI Extension) not sent with jdk1.8.0 but send with jdk1.7.0

Community
  • 1
  • 1
Bob
  • 388
  • 5
  • 19

2 Answers2

0

If your WS client is based on resteasy :

  • there is bug in w java 8 (see : bugs.java.com/bugdatabase/view_bug.do?bug_id=8144566)
  • this bug affects deprecated apache httpclient code (see issues.apache.org/jira/browse/HTTPCLIENT-1726)
  • this deprecated code is used in resteasy (https://issues.jboss.org/browse/RESTEASY-1089)

Workaround from https://issues.jboss.org/browse/RESTEASY-1089 :

new ResteasyClientBuilder().httpEngine(new URLConnectionEngine()).build()

Majka
  • 123
  • 1
  • 7
  • Hey Majka! thank you for responding - the way this particular system is setup is that it will pick up whatever JAX-WS framework that the app server provides - I believe that in this case what it should be calling is the CXF apache framework supplied by jboss. (Don't I wish I was using resteasy!!!) – Bob Nov 18 '16 at 17:45
  • This bug in java occurs only without https proxy server. If you are able to configure proxy it should work. – Majka Nov 18 '16 at 20:37
0

The WS client we were using in this case is utilizing AXIS2 and is designed to be agnostic to the framework in use. The SNI issue was being caused by an SSL header that was not being set called:

Extension server_name, server_name:

Its posted values should look something like this:

[type=host_name (0), value=some.server.value]

During out initial trials two failed assumption sets that were made 1) that any httpclient could be used i.e. the jboss supplied client or the JAVAX supplied client or even the client supplied by AXIS2 – however this was not the case and lead down many roads which were not conducive to a solution. We knew with a fair amount of certainty that we needed to set the SNI headers via an SSLFactory, what we were unsure of was how to get that factory to produce connectors that would be used by the system. Something that might have been helpful in identifying this issue would have been:

 Class klass = String.class;
URL location = klass.getResource('/' + klass.getName().replace('.', '/') + ".class");

2) Another area that we were unable to procced forward with was the bind solution presented in multiple wikis and howto’s:

bindingProvider.getRequestContext().put("<a href="http://com.sun.xml.internal.ws">com.sun.xml.internal.ws</a>.transport.https.client.SSLSocketFactory", new SSLSocketFactoryFacade());

The Application had its own version of HTTPclient which needed to be used. So a new class called BrokeredEpaasSSLSocketFactory was created that implements SecureProtocolSocketFactory based on the org.apache.commons.httpclient 3.1 supplied by the application. The key pieces of code are these - In the client itself: (to restrict the factories usage we have altered the URL’s of EPAAS to carry epaas instead of HTTPS) Initially we had thought of using register in the protocol class for https – however that would then mean every application that has a unique URL would need to be tested

Protocol myHTTPS = new Protocol( "https", new MySSLSocketFactory(), 443 );
 Protocol.registerProtocol( "https", myHTTPS );

Also an attempt to try and alter the protocol (using epaas to make the request instead of https) resulted in AXIS throwing back an error that wouldn’t allow to proceed forward so we abandoned this idea…

String endPointFinal = endPoint.replaceAll("epaas://", "https://");
          bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endPointFinal);
          bp.getRequestContext().put("SO_TIMEOUT", new Integer(sTimout));
          bp.getRequestContext().put("CONNECTION_TIMEOUT", new Integer(cTimeout));
          BrokeredEpaasSSLSocketFactory factory = new BrokeredEpaasSSLSocketFactory();   
          Protocol authhttps = new Protocol("https", factory, 443);
          HttpClient httpclient = new HttpClient();
          URL URI = new URL(endPointFinal);
          httpclient.getHostConfiguration().setHost(URI.getHost(), 443, authhttps);
          GetMethod httpget  = new GetMethod("/ecmuser/BrokeredConnectorService");
          httpclient.executeMethod(httpget);

The newly created class (BrokeredEpaasSSLSocketFactory) has two methods of particular interest: This currently is the only createSocket being used by the application (though they have all been altered for future use):

public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException {
        // TODO Auto-generated method stub
        if (params == null) {
            throw new IllegalArgumentException("Parameters may not be null");
        }
        int timeout = params.getConnectionTimeout();
        if (timeout == 0) {
            return _defaultFactory.createSocket(host, port,localAddress,localPort);
        } else {

            SSLSocket socket = (SSLSocket) _defaultFactory.createSocket();
            setParameters(socket,host);
            SocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
            SocketAddress remoteaddr = new InetSocketAddress(host, port);
            socket.bind(localaddr);
            socket.connect(remoteaddr, timeout);
            return socket;
        }
    }

This is the method which actually sets the SNI headers on the SSL outbound request:

private void setParameters(SSLSocket socket, String host)
        throws MalformedURLException {
    SSLParameters sslParameters = new SSLParameters();
    List<SNIServerName> sniHostNames = new ArrayList<SNIServerName>(1);
    sniHostNames.add(new SNIHostName(host));
    sslParameters.setServerNames(sniHostNames);
    socket.setSSLParameters(sslParameters);
}
Bob
  • 388
  • 5
  • 19