2016-04-19 1 views
1

J'ai une application Web (sur WebSphere) qui interagit avec un tiers pour formater certaines données reçues, puis effectue un appel RESTful à ce tiers, qui réside sur un Tomcat server. Dans l'application Web, je peux effectuer avec succès un appel RESTful GET RESTful en utilisant HttpsUrlConnection natif de Java (voir ci-dessous), mais lorsque j'utilise le HttpClient d'Apache, il échoue avec une erreur de chaînage SSL.Avec https URL, HttpsURLConnection fonctionne mais HttpClient ne fonctionne pas

Le HttpsURLConnection:

String urlWithParams = "https://example.com/rest/issue/59"; 

    String methodType = "GET"; 
    String acceptType = MediaType.APPLICATION_JSON; 

    HttpsURLConnection conn = null; 

    try { 

     URL url = new URL(urlWithParams); 
     conn = (HttpsURLConnection) url.openConnection(); 
     conn.setRequestMethod(methodType); 
     conn.setRequestProperty("Accept", acceptType); 

     if (conn.getResponseCode() != 200) { 
      System.out.println("Failed. httpErrorUrl=" + conn.getResponseCode() 
        + " httpErrorCode=" + conn.getResponseCode() 
        + " httpErrorMsg=" + conn.getResponseMessage()); 

     } 

     BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream()))); 

     String rawData; 
     String toReturn = ""; 
     while ((rawData = br.readLine()) != null) { 
      toReturn += rawData; 
     } 

     System.out.println(toReturn); 

    } catch (MalformedURLException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally{ 
     if(conn != null){ 
      conn.disconnect(); 
     } else { 
      System.out.println("httpUrlConnection is null"); 
     } 
    } 

Le code HttpClient:

String uri = "https://example.com/rest/issue/59"; 
    PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); 
    connManager.setDefaultMaxPerRoute(20); 
    connManager.setMaxTotal(40); 

    CloseableHttpClient httpclient = HttpClients.createDefault(); 

Les méthodes HttpClient sont exécutées dans la fonction ci-dessous:

private JSON request(HttpRequestBase req) throws RestException, IOException { 
     req.addHeader("Accept", "application/json"); 

     if (creds != null) 
      creds.authenticate(req); 

     HttpResponse resp = httpClient.execute(req); 
     HttpEntity ent = resp.getEntity(); 
     StringBuilder result = new StringBuilder(); 

     if (ent != null) { 
      String encoding = null; 
      if (ent.getContentEncoding() != null) { 
       encoding = ent.getContentEncoding().getValue(); 
      } 

      if (encoding == null) { 
       Header contentTypeHeader = resp.getFirstHeader("Content-Type"); 
       HeaderElement[] contentTypeElements = contentTypeHeader.getElements(); 
       for (HeaderElement he : contentTypeElements) { 
        NameValuePair nvp = he.getParameterByName("charset"); 
        if (nvp != null) { 
         encoding = nvp.getValue(); 
        } 
       } 
      } 

      InputStreamReader isr = encoding != null ? 
       new InputStreamReader(ent.getContent(), encoding) : 
       new InputStreamReader(ent.getContent()); 
      BufferedReader br = new BufferedReader(isr); 
      String line = ""; 

      while ((line = br.readLine()) != null) 
       result.append(line); 
     } 

     StatusLine sl = resp.getStatusLine(); 

     if (sl.getStatusCode() >= 300) 
      throw new RestException(sl.getReasonPhrase(), sl.getStatusCode(), result.toString()); 

     return result.length() > 0 ? JSONSerializer.toJSON(result.toString()): null; 
    }  

L'erreur produite est une exception de chaînage typique , ce qui signifie généralement que les certificats SSL ne sont pas corrects. Puisque les certificats sont importés au niveau du serveur d'applications, je m'attendrais à ce que les connexions SSL soient traitées de la même manière pour les appels HttpsURLConnection et HttpClient.

Caused by: `com.ibm.jsse2.util.j: PKIX` path building failed: `java.security.cert.CertPathBuilderException: PKIXCertPathBuilderImpl` co 

ULD ne pas construire une cause interne CertPath.; valide est: java.security.cert.CertPathValidatorException: Le certificat délivré par le CN = Entrust autorité de certification racine, OU = "(c) 2 006 Entrust, Inc.", OU = www.entrust .net/CPS est incorporé par référence, O = "Entrust, Inc.", C = US n'est pas fiable; cause interne est:

`java.security.cert.CertPathValidatorException:` Certificate chaining error 
    at com.ibm.jsse2.util.h.b(h.java:18) ~[na:6.0 build_20141024] 
    at com.ibm.jsse2.util.h.b(h.java:118) ~[na:6.0 build_20141024] 
    at com.ibm.jsse2.util.g.a(g.java:14) ~[na:6.0 build_20141024] 
    at com.ibm.jsse2.pc.a(pc.java:41) ~[na:6.0 build_20141024] 
    at com.ibm.jsse2.pc.checkServerTrusted(pc.java:1) ~[na:6.0 build_20141024] 
    at com.ibm.jsse2.pc.b(pc.java:90) ~[na:6.0 build_20141024] 
    at com.ibm.jsse2.lb.a(lb.java:499) ~[na:6.0 build_20141024] 
    ... 80 common frames omitted 

causés par: java.security.cert.CertPathBuilderException: PKIXCertPathBuilderImpl ne pouvait pas construire une CertPath valide. à com.ibm.security.cert.PKIXCertPathBuilderImpl.engineBuild(PKIXCertPathBuilderImpl.java:411) ~ [na: na] à java.security.cert.CertPathBuilder.build(CertPathBuilder.java:258) ~ [na: na] à com.ibm.jsse2.util.h.b(h.java:61) ~[na:6.0 build_20141024] ... 86 cadres communs omis

Pourquoi les certificats appliqués pour HttpsURLConnection mais pas pour HttpClient? Qu'est-ce que je fais mal?

+0

Je suppose que c'est un problème avec SNI, voir http: // stackoverflow.com/questions/5879894/android-ssl-sni-support. Si ce poste est de forme 2011, il est toujours pertinent. –

Répondre

2

HttpClient ne prend pas en compte les propriétés système à moins d'être explicitement configuré pour le faire.

Essayez de remplacer

HttpClients.createDefault() 

avec

HttpClients.createSystem() 

S'il vous plaît noter également que PoolingHttpClientConnectionManager par exemple dans votre code n'est pas utilisé. Ne créez pas de gestionnaires de connexions personnalisés, sauf si vous avez une très bonne raison de le faire.

+0

Merci @oleg Wow, je ne peux pas croire après tout de mon google recherche sur Apache HttpClient et SSL je ne suis pas tombé sur HttpClients.createSystem(). Merci beaucoup pour l'info, il a résolu mes problèmes –

+0

Cela a également fonctionné dans notre cas, bravo. –

0

La question suivante contient un bon exemple de code sur l'utilisation de HTTPS sur HttpClient.

Using Apache httpclient for https

En bref: votre code est manquant tous les protocoles HTTP S de configuration spécifique .. vous utilisez comme si elle était une requête HTTP régulière.

+0

Je ne suis pas sûr de comprendre ce que vous dites. Dans le document [HttpClient SSL Docs] (http://hc.apache.org/httpclient-3.x/sslguide.html), il est indiqué que ** Une fois que JSSE est correctement installé, la communication HTTP sécurisée via SSL devrait être aussi simple en tant que communication HTTP simple **. Puisque la source de mon appel est dans WebSphere, il devrait gérer toutes les négociations SSL (comme c'est le cas lorsque j'utilise HttpsURLConnection, n'est-ce pas?) –

+0

Cela ne semble pas être le cas maintenant. et voir si ça fonctionne – MichaelK