2011-01-10 22 views
6

Sto usando ksoap2-android per effettuare una chiamata al servizio wcf su SSL. Posso farlo funzionare senza SSL, ma ora voglio effettuare la chiamata su SSL, ma ho incontrato alcuni problemi.Certificato non attendibile utilizzando ksoap2-android

sto usando il HttpsTransportSE invece di HttpTransportSE, ma sto ottenendo l'errore: javax.net.ssl.SSLException: Non attendibile certificato server

Come posso risolvere questo problema?

Posso aggiungere il certificato del server al Keystore in Android per risolvere il problema?

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; 
} 

risposta

4

Beh, non c'è un modo più semplice per farlo invece di modificare HttpsServiceConnectionSE. È possibile installare un gestore fiducia falso come descritto in http://groups.google.com/group/android-developers/browse_thread/thread/1ac2b851e07269ba/c7275f3b28ad8bbc?lnk=gst&q=certificate e quindi chiamare allowAllSSL() prima di effettuare qualsiasi comunicazione SSL/chiamata a ksoap2. Registrerà un nuovo nome host predefinito e TrustManager. ksoap2, quando fa la sua comunicazione SSL, userà quelle predefinite e funzionerà come un incantesimo.

È anche possibile fare uno sforzo in più, renderlo (molto) più sicuro e installare i certificati in un gestore di fiducia locale dell'applicazione, immagino. Ero in una rete sicura e non avevo paura degli attacchi man-in-the-middle, quindi ho appena fatto il primo.

Ho trovato necessario utilizzare KeepAliveHttpsTransportSE come questo new KeepAliveHttpsTransportSE(host, port, file, timeout);. I parametri vanno in un oggetto URL, quindi ad es. per accedere a un'installazione di Jira è qualcosa come new KeepAliveHttpsTransportSE("host.whatever", 443, "/rpc/soap/jirasoapservice-v2", 1000).

A volte è utile se siete nuovi alla tecnologia o il servizio web che si desidera utilizzare per giocare con essa in un ambiente J2SE, invece di nell'emulatore o anche sul dispositivo, ma nel J2SE/ME biblioteca ksoap2 la roba (KeepAlive) HttpsTransportSE manca (ho usato ksoap2-j2se-full-2.1.2.jar). Quello che potresti fare è ottenere i sorgenti per le tre classi HttpsTransportSE, KeepAliveHttpsTransportSE e HttpsServiceConnectionSE dallo spin-off Android ksoap2-android e inserirli nel tuo progetto J2SE e usarli. Ha funzionato per me ed è diventato un miglioramento della produttività per fare i primi passi con un servizio web sconosciuto e piuttosto complesso.

+0

utilizzando la prima soluzione è più o meno lo stesso di utilizzare senza ssl – Rafa

0

Sì, probabilmente si può provare questo fuori

Https Connection Android

C'è stato un bug che è stato depositato l'Issue Tracker per quanto riguarda questo

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

+0

Per quanto riguarda il primo link: da dove viene quel codice va? – Awesome

+0

È possibile provare ad aggiungere questo prima di effettuare una chiamata al server – DeRagan

+0

Ho fornito il mio codice corrente nel post. Non riesco a vedere dove e come dovrei inserire il codice. – Awesome

11

Per completare la risposta di Vedran con un codice sorgente, mi dispiace non posso commentare.

Il 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()); 
} 

La chiamata al tuo metodo:

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

Note:

  1. Server è l'URL del server.
  2. 443 è la porta https predefinita, è necessario specificare una porta poiché il costruttore la prevede.
  3. URL il percorso per l'operazione WS
  4. 1000 es il timeout

che è costruito come: [https: // server: 443/URL]

+0

Grazie mille. questo collegamento mi ha aiutato di più ... – akk

+0

Grazie! Funziona perfettamente! – lomza

1

funziona per me KSOAP + WCF servizio Web con Eclipse

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 { 

     } 
    } 
Problemi correlati