I've just given it a quick try myself - temporarily updated HttpsURLConnectionFactory ignore the verifier but I still see no server_name extension in the debug - I've tried jax_rs/basic_http demo
with Java 8.

Sergey


On 15/09/16 16:43, Sergey Beryozkin wrote:
Hi
On 15/09/16 11:59, Chris Lott wrote:
Thanks Sergey for looking at this.  I am using fully qualified domain
names in all cases, should've mentioned that.

These bug reports at OpenJDK/Sun/Oracle are relevant; the second says
they know the problem but there's no resolution; any fix will probably
be in v9, not 1.8.:

    https://bugs.openjdk.java.net/browse/JDK-8072464

    http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8144566

Perhaps you can use Java 9 to run your client code ?


Stack overflow also says that CXF+SNI worked in 1.7, not in 1.8 and
offers a CXF workaround for 1.8 users; I wonder if this solution could
be incorporated into CXF?

It does not seem to be a solution that can guarantee anything. Colm do
you think it is worth it ?

    
http://stackoverflow.com/questions/30817934/extended-server-name-sni-extension-not-sent-with-jdk1-8-0-but-send-with-jdk1-7


So, does CXF configure a custom hostname verifier?  The mere presence
of that seems to trigger the bug in v1.8.
It does but I can see one issue being closed as can not reproduce.
If you'd like you can experiment with the following:
- check out CXF 3.1.x source
- add NoOpHostnameVerifier which will throw UOE in this package
https://github.com/apache/cxf/tree/master/rt/transports/http/src/main/java/org/apache/cxf/transport/https

- update this code,
https://github.com/apache/cxf/blob/master/rt/transports/http/src/main/java/org/apache/cxf/transport/https/HttpsURLConnectionFactory.java#L167


to check if the verifier an instance of NoOpHostnameVerifier, if yes -
do not set it at all.
- rebuild rt/transports/http

- configure HTTPConduit TSL properties with an instance of
NoOpHostnameVerifier (you can get to it with
WebClient.getConfig(webClient).getHttpConduit())

and see if avoiding setting the verifier at all can fix it...
If yes then we can decide on the final fix

Cheers, Sergey



HTH


On Sep 15, 2016, at 5:43 AM, Sergey Beryozkin <sberyoz...@gmail.com>
wrote:

Hi

According to
http://stackoverflow.com/questions/35366763/in-java-8-can-httpsurlconnection-be-made-to-send-server-name-indication-sni


SNI is sent only if it is a fully qualified name.

HTH, Sergey

On 14/09/16 22:22, Chris Lott wrote:

I'd like to ask about a behavior I see in CXF v 3.0.10 and v 3.1.7.
I'm
using JDK 1.8, and I have a tiny test program (see below).  Our REST
service is provided by Apache HTTPD (fronting Tomcat).  The HTTPD is
configured with 2 virtual hosts that differ only in name.  A conforming
client that sends SNI information works perfectly - receives the
appropriate certificate.  The CXF client does not work - throws an
exception like this:

Caused by: java.io.IOException: HTTPS hostname wrong:  should be
<my-host-qa.my.company.com>
   at
sun.net.www.protocol.https.HttpsClient.checkURLSpoofing(HttpsClient.java:649)


   at
sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:573)

   at
sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)


   at
sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1513)


   at
sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)


   at
java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
   at
sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:338)


   at
org.apache.cxf.transport.http.URLConnectionHTTPConduit$URLConnectionWrappedOutputStream.getResponseCode(URLConnectionHTTPConduit.java:332)


   at
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.doProcessResponseCode(HTTPConduit.java:1581)


   at
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1610)


   at
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1551)


   at
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1348)


   ... 12 more


In a nutshell, the CXF library does not seem to provide Server Name
Indication (SNI) to the remote HTTPS server.  Note that fetching
application/json content using a very plain Java method works just fine
- it provides SNI and gets the appropriate certificate - so I do not
believe it's a limitation of the platform that I'm using.

Is there some additional configuration I need to do in this sample
client?

Thanks for listening.

---

package com.mycompany.ecomp;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URL;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;

import javax.net.ssl.HttpsURLConnection;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.cxf.jaxrs.client.WebClient;

/**
* Trivial Java REST client to test whether SNI is provided when HTTPS
content
* is fetched.  Tested with Apache CXF ver 3.0.10 and 3.1.7.
*/
public class FetchRestContent {

   class HttpResponse {
       int code;
       String body;
   }

   /**
    * Fetches REST content using only features provided by standard
Java
    * libraries.
    *
    * @param url
    * @param user
    *            Set as header parameter "username"
    * @param pass
    *            Set as header parameter "password";
    * @return Code and body fetched from remote server
    * @throws Exception
    *             on any failure
    */
   private HttpResponse getRestContentJdk(String uriString, String
path, String user, String pass) throws Exception {

       URL url = new URL(uriString + '/' + path);
       HttpsURLConnection con = (HttpsURLConnection)
url.openConnection();
       if (con == null)
           throw new Exception("Failed to open HTTPS connection");

       con.setRequestMethod("GET");
       con.setConnectTimeout(2000);
       con.setReadTimeout(2000);
       con.setRequestProperty("username", user);
       con.setRequestProperty("password", pass);

       // Throws an exception on an HTTPS connection if the
       // local trust store is not configured appropriately to
       // accept the self-signed certificate at the remote end.
       HttpResponse resp = new HttpResponse();
       resp.code = con.getResponseCode();
       BufferedReader in = new BufferedReader(new
InputStreamReader(con.getInputStream(), "UTF-8"));

       Certificate[] certs = con.getServerCertificates();
       for (Certificate cert : certs) {
           if (cert instanceof X509Certificate) {
               X509Certificate xcert = (X509Certificate) cert;
               System.out.println("X509 Principal name " +
xcert.getSubjectX500Principal().getName());
           }
       }

       StringBuffer sb = new StringBuffer();
       String inputLine;
       while ((inputLine = in.readLine()) != null)
           sb.append(inputLine);
       in.close();
       con.getInputStream().close();
       con.disconnect();
       resp.body = sb.toString();
       return resp;
   }

   /**
    * Fetches REST content using Jax-RS, as implemented by Apache CXF.
    *
    * @param uri
    * @param path
    * @param user
    * @param pass
    * @return
    * @throws Exception
    */
   private HttpResponse getRestContentJaxrs(String uriString, String
path, String user, String pass) throws Exception {
       URI uri = new URI(uriString);
       WebClient client = WebClient.create(uri);

client.type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);

       client.path(path);
       Response response = client.get();
       HttpResponse httpResponse = new HttpResponse();
       httpResponse.code = response.getStatus();
       httpResponse.body = response.readEntity(String.class);
       return httpResponse;
   }

   public static void main(String[] args) throws Exception {
       if (args.length != 4)
           throw new IllegalArgumentException("Expect 4 arguments: URL
path username password");
       if (!args[0].toLowerCase().startsWith("https"))
           throw new IllegalArgumentException("Expect https prefix");
       FetchRestContent fetcher = new FetchRestContent();

       System.out.println("GET-ing content via Java from " + args[0] +
", path " + args[1]);
       HttpResponse r1 = fetcher.getRestContentJdk(args[0], args[1],
args[2], args[3]);
       System.out.println("HTTP response code is " + r1.code);
       System.out.println("Response body follows:");
       System.out.println(r1.body);

       System.out.println("GET-ing content via Jax-RS from " + args[0]
+ ", path " + args[1]);
       HttpResponse r2 = fetcher.getRestContentJaxrs(args[0], args[1],
args[2], args[3]);
       System.out.println("HTTP response code is " + r2.code);
       System.out.println("Response body follows:");
       System.out.println(r2.body);
   }
}


--
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/






--
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Reply via email to