0

working on an event manager application , connecting to an http:// web service to retrieve JSON response storing events in local sqlite DB and so forth everything was going alright , until we moved the web service to https://, i started receiving ssl certificate error every time i tried to connect to the service . using DefaultHttpClient ,
i looked up solutions on stack overflow and i found some going as far as to write custom classes to solve the issue . i can't believe that there's no straight forward solution to connect to a web service on https:// from android without having to write custom

i'd appreciate if someone could help me with this issue

here's the code

package com.xxxxx.xxxxxxxxx.utility;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.List;  
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

public class JSONParser {
    // input stream to buffer data
    static InputStream is = null;
    //json object 

    static JSONObject jObj = new JSONObject();
    // json string
    static String json = "";
    private String socketResult = null;

    // constructor
    public JSONParser() {

    }

    // function get json from url

    public JSONObject makeHttpRequest(String url, List<NameValuePair> params) {

        // Making HTTP request
        try {

            final HttpParams httpParameters = new BasicHttpParams();
            // Set the timeout in milliseconds until a connection is established.
              HttpConnectionParams.setConnectionTimeout(httpParameters, 240000);

            // Set the default socket timeout (SO_TIMEOUT)
            // in milliseconds which is the timeout for waiting for data.
           HttpConnectionParams.setSoTimeout(httpParameters, 180000);
            // request method is POST
            // defaultHttpClient

           DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
            // HTTP POST method
            HttpPost httpPost = new HttpPost(url);
            // Hands the entity to the request. // thr paramters to pass to the request in the form of name value pairs  
            httpPost.setEntity(new UrlEncodedFormEntity(params));
            // handels the response form the http request 
            HttpResponse httpResponse = httpClient.execute(httpPost);

StatusLine status = httpResponse.getStatusLine();
if (status.getStatusCode() == HttpStatus.SC_OK) {


    // An entity that can be sent or received with an HTTP message. Entities can be found in some    requests and in responses, where they are optional.
    HttpEntity httpEntity = httpResponse.getEntity();
      // store the content / data of the entity in an input stream 
    is = httpEntity.getContent();
}else{
    // Do something else, if wanted.
}

           // An entity that can be sent or received with an HTTP message. Entities can be found in some requests and in responses, where they are optional.
         // HttpEntity httpEntity = httpResponse.getEntity();
           // store the content / data of the entity in an input stream 
         //is = httpEntity.getContent();



        } catch (UnsupportedEncodingException e) {
            Log.d("UnsupportedEncodingException", "HTTP Error", e);

        } catch (ClientProtocolException e) {
            Log.d("ClientProtocolException", "HTTP Error", e);

        } catch (IOException e) {
            Log.d("IOException", "Connection Error", e);

        }

        try {

            // read the data in the input stream entity to buffer 
            BufferedReader reader = new BufferedReader(new InputStreamReader(is, "iso-8859-1"), 8);
            StringBuilder sb = new StringBuilder();
            String line = null;
            // construct a string builder object the buffer data 
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
            // close the input stream 
            is.close();


            //  create string from the json data 
            json = sb.toString();
        } catch (Exception e) {
            Log.d("Buffer Error", "Error converting result " + e.toString());
        }

        // try parse the string to a JSON object
        try {
            //----------------------------------------------------------------------
            //Log.d(" creating json object " , json);


            jObj = new JSONObject(json);
        } catch (JSONException e) {
            Log.d("JSON Parser", "Error parsing data " + e.toString());
            //----------------------------------------------------------------------
             System.out.println("JSON Parserexception:" + e);
        }

        // return JSON String
        return jObj;

    }
}
  • see : http://stackoverflow.com/questions/995514/https-connection-android – Blaze Tama Nov 07 '14 at 14:48
  • it looks similar to another post i read while i was searching but without implementing the SSLSocketFactory class , anyway i'll give it a try an see , thanks Blaze – jimmy_flash Nov 07 '14 at 14:53

3 Answers3

0

The certificate has to be signed by a trusted third party certification authority that recognizes the device. If it is not the case, there are some hacks to your code like include the certificate inside it and validate it.

Plebios
  • 835
  • 1
  • 7
  • 17
0

The first thing you need to do is to set the level of verification. Such levels is not so much:

ALLOW_ALL_HOSTNAME_VERIFIER BROWSER_COMPATIBLE_HOSTNAME_VERIFIER STRICT_HOSTNAME_VERIFIER Although the method setHostnameVerifier() is obsolete for new library apache, but for version in Android SDK is normal. And so we take ALLOW_ALL_HOSTNAME_VERIFIER and set it in the method factory SSLSocketFactory.setHostnameVerifier().

Next, You need set our factory for the protocol to https. To do this, simply call the SchemeRegistry.register() method.

Then you need to create a DefaultHttpClient with SingleClientConnManager. Also in the code below you can see that on default will also use our flag (ALLOW_ALL_HOSTNAME_VERIFIER) by the method HttpsURLConnection.setDefaultHostnameVerifier()

Below code works for me:

    HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

    DefaultHttpClient client = new DefaultHttpClient();

    SchemeRegistry registry = new SchemeRegistry();
    SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
    socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
    registry.register(new Scheme("https", socketFactory, 443));
    SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
    DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());

    // Set verifier     
    HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

    // Example send http request
    final String url = "https://encrypted.google.com/";
    HttpPost httpPost = new HttpPost(url);
    HttpResponse response = httpClient.execute(httpPost);
Kamuy
  • 177
  • 1
  • 6
0

Try adding a class in your project -

public class MySSLSocketFactory extends SSLSocketFactory {
    SSLContext sslContext = SSLContext.getInstance("TLS");

    public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(truststore);

        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

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

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

        sslContext.init(null, new TrustManager[] { tm }, null);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}

And then call this method for getting the client -

public HttpClient getNewHttpClient() {
        try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null, null);

            SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

            HttpParams params = new BasicHttpParams();
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

            SchemeRegistry registry = new SchemeRegistry();
            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            registry.register(new Scheme("https", sf, 443));

            ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

            return new DefaultHttpClient(ccm, params);
        } catch (Exception e) {
            return new DefaultHttpClient();
        }
    }

Hope this will helps you.

Ashish Tamrakar
  • 810
  • 10
  • 24
  • thanks Ashish , i'm testing all solutions hope this will be it – jimmy_flash Nov 07 '14 at 15:04
  • after testing i got a rather different error that the one i used to get no peer certificate, here's what i received in log: javax.net.ssl.SSLException: SSL handshake aborted: ssl=0x12f8698: I/O error during system call, Connection reset by peer, i searched the error all suggestion point to the certificate on server – jimmy_flash Nov 09 '14 at 19:15