2011-01-10 16 views
6

Estoy usando ksoap2-android para realizar una llamada al servicio wcf a través de SSL. Puedo hacer que funcione sin SSL, pero ahora quiero hacer la llamada a través de SSL, pero me he encontrado con algunos problemas.Certificado no confiable usando ksoap2-android

estoy usando el HttpsTransportSE en lugar de HttpTransportSE, pero estoy consiguiendo el error: javax.net.ssl.SSLException: No certificado de confianza

¿Cómo puedo solucionar este servidor?

¿Puedo agregar el certificado del servidor al almacén de claves en Android para resolver el 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; 
} 

Respuesta

4

Bueno, hay una forma más fácil de hacerlo en lugar de modificar HttpsServiceConnectionSE. Puede instalar un administrador de confianza falso como se describe en http://groups.google.com/group/android-developers/browse_thread/thread/1ac2b851e07269ba/c7275f3b28ad8bbc?lnk=gst&q=certificate y luego llamar a allowAllSSL() antes de realizar cualquier comunicación/llamada de SSL a ksoap2. Registrará un nuevo HostnameVerifier y TrustManager predeterminados. ksoap2, al hacer su comunicación SSL, usará los predeterminados y funciona como un amuleto.

También puede poner un poco más de esfuerzo en esto, hacerlo (mucho) más seguro e instalar certificados en un administrador de confianza local de la aplicación, supongo. Estaba en una red segura y no le temo a los hombres en los ataques intermedios, así que acabo de hacer lo primero.

Me pareció necesario utilizar KeepAliveHttpsTransportSE como este new KeepAliveHttpsTransportSE(host, port, file, timeout);. Los parámetros entran en un objeto URL, por ejemplo, para acceder a una instalación de Jira es algo así como new KeepAliveHttpsTransportSE("host.whatever", 443, "/rpc/soap/jirasoapservice-v2", 1000).

A veces es útil si eres nuevo en la tecnología o el servicio web que te gusta usar para jugar con él en un entorno J2SE en lugar de en el emulador o incluso en el dispositivo, sino en la biblioteca J2SE/ME ksoap2 el material (KeepAlive) HttpsTransportSE falta (utilicé ksoap2-j2se-full-2.1.2.jar). Lo que podría hacer es obtener las fuentes de las tres clases HttpsTransportSE, KeepAliveHttpsTransportSE y HttpsServiceConnectionSE del spin-off de Android ksoap2-android y ponerlas en su proyecto J2SE y usarlas. Me funcionó y se convirtió en una mejora de la productividad dar los primeros pasos con un servicio web desconocido y bastante complejo.

+0

usando su primera solución es más o menos lo mismo que usar no ssl – Rafa

0

Sí, probablemente, se puede probar esto

Https Connection Android

Se ha producido un error que ha sido presentada el seguimiento de problemas que atañen a esta

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

+0

Respecto al primer enlace: ¿A dónde va ese código? – Awesome

+0

Puede intentar agregar esto antes de realizar una llamada al servidor – DeRagan

+0

He proporcionado mi código actual en la publicación. Simplemente no puedo ver dónde y cómo debería poner el código. – Awesome

11

Para complementar la respuesta de Vedran con algún código fuente, lo siento, no puedo comentar.

El 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 llamada a su método:

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

Notas:

  1. servidor es la dirección URL del servidor.
  2. 443 es el puerto predeterminado https, aún debe especificar un puerto, ya que el constructor espera uno.
  3. URL de la ruta de acceso a la operación WS
  4. 1000 ca el tiempo de espera

que se construye como: [https: // servidor: 443/URL]

+0

Muchas gracias. este enlace me ayudó más ... – akk

+0

¡Gracias! Esto funciona perfectamente! – lomza

1

funciona para mí KSOAP + Servicio web WCF 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 { 

     } 
    } 
Cuestiones relacionadas