KSOAP 2 Android with HTTPS
Asked Answered
C

4

14

I am using KSOAP2 to manage SOAP in Android but it use https for the SOAP url and I am getting this error: javax.net.ssl.SSLException: Not trusted server certificate
A normal error because the certificate is untrusted, but anyone knows how to workaround with this error? I can not manage the certificate because is from a other company and I don't have access to change it.

Thanks

Collimate answered 9/8, 2010 at 12:40 Comment(0)
M
10

I can't comment yet so i post my comments to rallat answer here. His solution works but it needs further explanations. To run ksoap2 with ssl:

  1. Put ksoap2-android-assembly-2.5.2-jar-with-dependencies.jar in a project
  2. Download ksoap2 sources from https://github.com/mosabua/ksoap2-android/tree/ (ksoap2 repository)
  3. Copy HttpTransportSE.java, ServiceConnectionSE.java (I also needed to copy Transport.java, ServiceConnection.java and HeaderProperty.java). Delete imports from those files and make sure that they use your files (not imports from ksoap2.jar)
  4. Use rallat answer ( I copy-pasted it):

    • ServiceConnectionSE.java add this for accept untrusted certificate:

      private TrustManager[] trustAllCerts = new TrustManager[] {
          new X509TrustManager() {
              public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                  return null;
              }
              public void checkClientTrusted(
                  java.security.cert.X509Certificate[] certs, String authType) {
              }
              public void checkServerTrusted(
                  java.security.cert.X509Certificate[] certs, String authType) {
              }
          }
      };
      
    • then use this constructors to allow untrusted certificates and not verified hostnames:

      public ServiceConnectionSE(String url) throws IOException {
          try {
              SSLContext sc = SSLContext.getInstance("TLS");
              sc.init(null, trustAllCerts, new java.security.SecureRandom());
              HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
          } catch (Exception e) {
              e.getMessage();
          }
          connection = (HttpsURLConnection) new URL(url).openConnection();
          ((HttpsURLConnection) connection).setHostnameVerifier(new AllowAllHostnameVerifier());
      }    
      
    • Second contructor

      public ServiceConnectionSE(Proxy proxy, String url) throws IOException {
          try {
              SSLContext sc = SSLContext.getInstance("TLS");
              sc.init(null, trustAllCerts, new java.security.SecureRandom());
              HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
           } catch (Exception e) {
              e.getMessage();
           }
           connection = (HttpsURLConnection) new URL(url).openConnection();
          ((HttpsURLConnection) connection).setHostnameVerifier(new AllowAllHostnameVerifier());
      
          connection.setUseCaches(false);
          connection.setDoOutput(true);
          connection.setDoInput(true);
      }
      
  5. In your code just use:

    HttpTransportSE aht = new HttpTransportSE(URL);    
    aht.call(SOAP_ACTION, envelope);
    

Other things as in tutorials

Meghan answered 10/2, 2011 at 12:56 Comment(3)
@Zirael...Thanks for ur anwser it helped...I was eager to know rather than working around if Had the Security Certificate...How do i proceed further with it..?Currency
Can't find the sources of ksoap using the provided link - its broken. =\ update: I found it... just use :github.com/mosabua/ksoap2-androidChartulary
How can i include ssl in ksoap2 ? Can you check - #62006680Foal
O
18

Checking again this problem, I've discovered a more clean solution for me. No KSOAP2 files modification needed.

In your project, link the ksoap2-android-assembly-3.0.0-jar, with no modifications.

Next, create a file named SSLConnection.java with this code:

package com.example.mypackage;

import android.util.Log;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class SSLConection {

    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 X509Certificate[] getAcceptedIssuers() {
            return (_AcceptedIssuers);
        }
    }

    public static void allowAllSSL() {

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

        javax.net.ssl.SSLContext context;

        if (trustManagers == null) {
            trustManagers = new TrustManager[]{new _FakeX509TrustManager()};
        }

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

And just call to SSLConection.allowAllSSL(); before calling a server method via KSOAP2. It's all, works for me. All SSL certificates are accepted and I can use KSOAP2 with https protocol.

Overspread answered 23/9, 2013 at 8:52 Comment(2)
Thanks for adding your snippet tooCollimate
This is a very dangerous workaround though. Leaves you exposed to MITM attacks.Sloane
M
10

I can't comment yet so i post my comments to rallat answer here. His solution works but it needs further explanations. To run ksoap2 with ssl:

  1. Put ksoap2-android-assembly-2.5.2-jar-with-dependencies.jar in a project
  2. Download ksoap2 sources from https://github.com/mosabua/ksoap2-android/tree/ (ksoap2 repository)
  3. Copy HttpTransportSE.java, ServiceConnectionSE.java (I also needed to copy Transport.java, ServiceConnection.java and HeaderProperty.java). Delete imports from those files and make sure that they use your files (not imports from ksoap2.jar)
  4. Use rallat answer ( I copy-pasted it):

    • ServiceConnectionSE.java add this for accept untrusted certificate:

      private TrustManager[] trustAllCerts = new TrustManager[] {
          new X509TrustManager() {
              public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                  return null;
              }
              public void checkClientTrusted(
                  java.security.cert.X509Certificate[] certs, String authType) {
              }
              public void checkServerTrusted(
                  java.security.cert.X509Certificate[] certs, String authType) {
              }
          }
      };
      
    • then use this constructors to allow untrusted certificates and not verified hostnames:

      public ServiceConnectionSE(String url) throws IOException {
          try {
              SSLContext sc = SSLContext.getInstance("TLS");
              sc.init(null, trustAllCerts, new java.security.SecureRandom());
              HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
          } catch (Exception e) {
              e.getMessage();
          }
          connection = (HttpsURLConnection) new URL(url).openConnection();
          ((HttpsURLConnection) connection).setHostnameVerifier(new AllowAllHostnameVerifier());
      }    
      
    • Second contructor

      public ServiceConnectionSE(Proxy proxy, String url) throws IOException {
          try {
              SSLContext sc = SSLContext.getInstance("TLS");
              sc.init(null, trustAllCerts, new java.security.SecureRandom());
              HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
           } catch (Exception e) {
              e.getMessage();
           }
           connection = (HttpsURLConnection) new URL(url).openConnection();
          ((HttpsURLConnection) connection).setHostnameVerifier(new AllowAllHostnameVerifier());
      
          connection.setUseCaches(false);
          connection.setDoOutput(true);
          connection.setDoInput(true);
      }
      
  5. In your code just use:

    HttpTransportSE aht = new HttpTransportSE(URL);    
    aht.call(SOAP_ACTION, envelope);
    

Other things as in tutorials

Meghan answered 10/2, 2011 at 12:56 Comment(3)
@Zirael...Thanks for ur anwser it helped...I was eager to know rather than working around if Had the Security Certificate...How do i proceed further with it..?Currency
Can't find the sources of ksoap using the provided link - its broken. =\ update: I found it... just use :github.com/mosabua/ksoap2-androidChartulary
How can i include ssl in ksoap2 ? Can you check - #62006680Foal
C
4

I find the answer by myself

  • on ServiceConnectionSE.java add this for accept untrusted certificate:

    private TrustManager[] trustAllCerts = new TrustManager[]{
        new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
            }
            public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
            }
        }
    };
    
  • then in the constructor add this to allow untrusted certificates and not verified hostnames:

        try {
           SSLContext sc = SSLContext.getInstance("TLS");
           sc.init(null, trustAllCerts, new java.security.SecureRandom());
           HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
           e.getMessage();
        }
        connection = (HttpsURLConnection) new URL(url).openConnection();
        ((HttpsURLConnection) connection).setHostnameVerifier(new AllowAllHostnameVerifier());
    
Collimate answered 11/8, 2010 at 10:39 Comment(0)
T
4

Create a new class FakeX509TrustManager to handle the certificate problem,

    FakeX509TrustManager.allowAllSSL();
    HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);

The new created class is as the following:

public class FakeX509TrustManager implements X509TrustManager { 

    private static TrustManager[] trustManagers; 
    private static final X509Certificate[] _AcceptedIssuers = new 
X509Certificate[] {}; 

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

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

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

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

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

    public static void allowAllSSL() { 
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() 
{ 
                    @Override 
                    public boolean verify(String hostname, 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 (NoSuchAlgorithmException e) { 
                    e.printStackTrace(); 
            } catch (KeyManagementException e) { 
                    e.printStackTrace(); 
            } 

       HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); 
    } 

} 
Tobiastobie answered 8/4, 2013 at 6:50 Comment(2)
Serious +1 jowett...I put your code at the end of my activity and all I had to do was make the FakeX509TrustManager static and it got right through...I've read a more than a few SO posts and this was the easiest to implement by far. Notice the dates on the previous answers in this post...enough said. Do you have any resources on the easiest way to NOT trust all certs for production code?Congruency
@Congruency sorry, no resource.Tobiastobie

© 2022 - 2024 — McMap. All rights reserved.