2011-01-10 6 views
6

J'utilise ksoap2-android pour appeler le service wcf via SSL. Je peux le faire fonctionner sans SSL, mais maintenant je veux passer l'appel via SSL, mais j'ai rencontré des problèmes.Certificat de confiance utilisant ksoap2-android

J'utilise le HttpsTransportSE au lieu de HttpTransportSE, mais je me fais l'erreur: javax.net.ssl.SSLException: certificat de serveur non sécurisé

Comment puis-je résoudre ce problème? Puis-je ajouter le certificat de serveur au Keystore dans Android pour résoudre le problème?

private static final String SOAP_ACTION = "http://example.com/Service/GetInformation"; 
private static final String METHOD_NAME = "GetInformation"; 
private static final String NAMESPACE = "http://example.com";  
private static final String URL = "dev.example.com/Service.svc"; 

public static Result GetInformation() 
{ 
    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME); 

    PropertyInfo property = new PropertyInfo(); 
    property.name = "request"; 

    Request request = 
     new Request("12", "13", "Ben"); 

    userInformationProperty.setValue(request); 
    userInformationProperty.setType(request.getClass()); 
    request.addProperty(property); 

    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); 
    envelope.dotNet = true; 
    envelope.setOutputSoapObject(request); 
    envelope.addMapping(NAMESPACE, "Request",new Request().getClass()); 

    HttpsTransportSE transport = new HttpsTransportSE(URL, 443, "", 1000); 

    //HttpTransportSE androidHttpTransport = new HttpTransportSE(URL); 
    transport.debug = true; 

    try 
    { 
     transport.call(SOAP_ACTION, envelope);   
     return Result.FromSoapResponse((SoapObject)envelope.getResponse()); 
    } 
    catch (IOException e) 
    { 
     e.printStackTrace(); 
    } 
    catch (XmlPullParserException e) 
    { 
     e.printStackTrace(); 
    } 

    return null; 
} 

Répondre

4

Eh bien, il y a un moyen plus simple de le faire au lieu de modifier HttpsServiceConnectionSE. Vous pouvez installer un faux gestionnaire d'approbation comme décrit dans http://groups.google.com/group/android-developers/browse_thread/thread/1ac2b851e07269ba/c7275f3b28ad8bbc?lnk=gst&q=certificate, puis appelez allowAllSSL() avant d'effectuer toute communication/appel SSL vers ksoap2. Il va enregistrer un nouveau HostnameVerifier et TrustManager par défaut. ksoap2, lors de sa communication SSL, utilisera les paramètres par défaut et fonctionne comme un charme.

Vous pouvez également mettre plus d'efforts dans ce domaine, le rendre (beaucoup) plus sûr et installer des certificats dans un gestionnaire de confiance local d'application, je suppose. Je me trouvais dans un réseau sûr et je n'avais pas peur des attaques de l'homme dans le milieu, alors j'ai juste fait le premier. J'ai trouvé nécessaire d'utiliser KeepAliveHttpsTransportSE comme cela new KeepAliveHttpsTransportSE(host, port, file, timeout);. Les paramètres vont dans un objet URL, par exemple. pour accéder à une installation Jira c'est quelque chose comme new KeepAliveHttpsTransportSE("host.whatever", 443, "/rpc/soap/jirasoapservice-v2", 1000). Parfois, c'est pratique si vous êtes nouveau dans la technologie ou le service Web que vous aimez utiliser dans un environnement J2SE plutôt que dans l'émulateur ou même sur le périphérique, mais dans la bibliothèque K2ap/ME de J2SE/ME le truc (KeepAlive) HttpsTransportSE est manquant (j'ai utilisé ksoap2-j2se-full-2.1.2.jar). Ce que vous pouvez faire est d'obtenir les sources pour les trois classes HttpsTransportSE, KeepAliveHttpsTransportSE, et HttpsServiceConnectionSE de la spin-off Android ksoap2-android et les mettre dans votre projet J2SE et les utiliser. Cela a fonctionné pour moi et c'est devenu une amélioration de la productivité pour obtenir les premiers pas avec un service web inconnu et assez complexe.

+0

en utilisant votre première solution est plus ou moins la même chose que d'utiliser aucun SSL – Rafa

0

Oui probablement vous pouvez essayer cela

Https Connection Android

Il y a eu un bug qui a été déposée le problème Tracker concernant cette

http://code.google.com/p/android/issues/detail?id=2388

+0

En ce qui concerne le premier lien: Où va ce code? – Awesome

+0

Vous pouvez essayer d'ajouter ceci avant de faire un appel de serveur – DeRagan

+0

J'ai fourni mon code actuel dans la publication. Je ne peux pas voir où et comment je devrais mettre le code. – Awesome

11

Pour compléter la réponse de Vedran avec du code source, désolé je ne peux pas commenter.

Le TrustManager:

private static TrustManager[] trustManagers; 

public static class _FakeX509TrustManager implements 
     javax.net.ssl.X509TrustManager { 
    private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {}; 

    public void checkClientTrusted(X509Certificate[] arg0, String arg1) 
      throws CertificateException { 
    } 

    public void checkServerTrusted(X509Certificate[] arg0, String arg1) 
      throws CertificateException { 
    } 

    public boolean isClientTrusted(X509Certificate[] chain) { 
     return (true); 
    } 

    public boolean isServerTrusted(X509Certificate[] chain) { 
     return (true); 
    } 

    public X509Certificate[] getAcceptedIssuers() { 
     return (_AcceptedIssuers); 
    } 
} 

public static void allowAllSSL() { 

    javax.net.ssl.HttpsURLConnection 
      .setDefaultHostnameVerifier(new HostnameVerifier() { 
       public boolean verify(String hostname, SSLSession session) { 
        return true; 
       } 
      }); 

    javax.net.ssl.SSLContext context = null; 

    if (trustManagers == null) { 
     trustManagers = new javax.net.ssl.TrustManager[] { new _FakeX509TrustManager() }; 
    } 

    try { 
     context = javax.net.ssl.SSLContext.getInstance("TLS"); 
     context.init(null, trustManagers, new SecureRandom()); 
    } catch (NoSuchAlgorithmException e) { 
     Log.e("allowAllSSL", e.toString()); 
    } catch (KeyManagementException e) { 
     Log.e("allowAllSSL", e.toString()); 
    } 
    javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(context 
      .getSocketFactory()); 
} 

L'appel à votre méthode:

allowAllSSL(); 
HttpsTransportSE httpsTransport = new HttpsTransportSE(Server,443, URL, 1000); 

Notes:

  1. Server est l'URL du serveur.
  2. 443 est le port https par défaut, vous devez toujours spécifier un port car le constructeur en attend un.
  3. URL le chemin de l'opération de WS
  4. 1000 es le délai d'attente

Ce qui est construit comme: [https: // serveur: 443/URL]

+0

Merci beaucoup. ce lien m'a aidé plus ... – akk

+0

Merci! Cela fonctionne parfaitement! – lomza

1

Works pour moi KSOAP + Service Web WCF avec éclipse

private static SoapObject getBody(final SoapSerializationEnvelope soapEnvelope) throws Exception { 
     if (soapEnvelope.bodyIn == null) { 
      throw new Exception("soapEnvelope.bodyIn=null"); 
     } 
     else if (soapEnvelope.bodyIn.getClass() == SoapFault.class) { 
      throw new ExceptionLogic((SoapFault) soapEnvelope.bodyIn)); 
     } 
     else { 
      return (SoapObject) soapEnvelope.bodyIn; 
     } 

    } 

private static SoapSerializationEnvelope sendRequete(final SoapObject soapReq, final String classMappingName, 
      final Class<?> classMapping, final int timeOutSpecial) { 



     final SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); 
     soapEnvelope.implicitTypes = true; 
     soapEnvelope.dotNet = true; 

     if (classMappingName != null) { 
      soapEnvelope.addMapping(NAMESPACE, classMappingName, classMapping); 
     } 

     soapEnvelope.setOutputSoapObject(soapReq); 

     try { 

      final HttpTransportSE httpTransport = new HttpTransportSE(Constante.urlWebService, timeOutSpecial); 
      httpTransport.debug = BuildConfig.DEBUG; 

      // Prod 
      if (Constante.urlWebService.startsWith("https://")) { 
       final List<HeaderProperty> headerList = new ArrayList<HeaderProperty>(); 
       headerList.add(new HeaderProperty("Authorization", "Basic " 
         + org.kobjects.base64.Base64.encode((Constante.CERTIFICAT_LOGIN + ":" + Constante.CERTIFICAT_MDP).getBytes()))); 

       FakeX509TrustManager.allowAllSSL(); 
       httpTransport.call(NAMESPACE + "/" + soapReq.getName(), soapEnvelope, headerList); 
      } 
      // Test 
      else { 
       httpTransport.call(NAMESPACE + "/" + soapReq.getName(), soapEnvelope); 
      } 

      return soapEnvelope; 
     } 
     catch (final Exception e) { 
      throw new Exception("Erreur : " + e.getMessage(), e); 
     } 

    } 



    private static class FakeX509TrustManager implements X509TrustManager { 
     private static TrustManager[] trustManagers; 
     private final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {}; 

     @Override 
     public X509Certificate[] getAcceptedIssuers() { 
      return _AcceptedIssuers; 
     } 

     public static void allowAllSSL() { 
      HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { 

       @Override 
       public boolean verify(final String hostname, final SSLSession session) { 
        return true; 
       } 
      }); 
      SSLContext context = null; 
      if (trustManagers == null) { 
       trustManagers = new TrustManager[] { new FakeX509TrustManager() }; 
      } 
      try { 
       context = SSLContext.getInstance("TLS"); 
       context.init(null, trustManagers, new SecureRandom()); 
      } 
      catch (final NoSuchAlgorithmException e) { 
       e.printStackTrace(); 
      } 
      catch (final KeyManagementException e) { 
       e.printStackTrace(); 
      } 
      HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); 
     } 

     @Override 
     public void checkClientTrusted(final X509Certificate[] arg0, final String arg1) throws CertificateException { 

     } 

     @Override 
     public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException { 

     } 
    } 
Questions connexes