Connect over secure rest web service for mobile application on android

29 Mar 2011

Connect over secure rest web service for mobile application on android

In the last article, we developed application for android to get the data from rest web service (geo-names). Previous approach works fine for http rest web service but it doesn’t work over SSL secure connection. We were developing android application for a client whose rest web services are running over secure connection. Initially we thought it would be much simple to connect to secure rest web service because we already have the framework to connect to http connection. When we use it and there was exception “javax.net.ssl.SSLException: Not trusted server certificate” all over the application.
We didn’t loose our patience and asked our truly friends google and stackoverflow. We found various solution to intercept the connection and use self certificate but we wanted a solution which just by pass the authorization of the certificates. After checking various sites and reading the article, we found a solution which fit our requirements.

Create Easy SSL Socket Factory and create httpclient instance

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.conn.ssl.SSLSocketFactory;
public class EasySSLSocketFactory extends SSLSocketFactory {
        SSLContext sslContext = SSLContext.getInstance("TLS");

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

}

We shall be using this ssl socket factory to access the secure connection to rest web service.

import java.security.KeyStore;

import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

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

                SSLSocketFactory sf = new EasySSLSocketFactory(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();
            }
        }
}

Back to our original rest client code

// Create a new RestTemplate instance
				RestTemplate restTemplate = new RestTemplate();

				// The HttpComponentsClientHttpRequestFactory uses the
				// org.apache.http package to make network requests
				restTemplate
						.setRequestFactory(new HttpComponentsClientHttpRequestFactory(
								HttpUtils.getNewHttpClient()));

				// The URL for making the GET request
				final String url = "https://xxx.xxx.xxx.xxx";
                                // Initiate the HTTP GET request, expecting an array of
				// objects in response
				Object result = restTemplate.getForObject(url, Object.class);

Finally we were able to make connection over secure rest web service android application.

Feel free to comment or ask questions.

Useful resources

  • Murali

    Hi,

    Can you please provide the details how to call a secured WebService from a stand alone java service(which was configured with spring core).I will appreciate if anyone has any experience on this and share with me.

  • Streben

    Hi
    Can you give us the changed that you maked in the file server.xml and tomcat-users.xml to secure the web service REST

  • http://www.makeurownrules.com Kapil Jain

    Hi there,

    Well this article covers only android client-side and we have used rest server on apache. I think you can take a look at this http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html to enable ssl on tomcat.

    Cheers,
    Kapil

  • Streben

    Hi
    Can you please show us the web.xml file of web service to have an idea about configuration of secure REST in server side
    thanks

  • http://www.makeurownrules.com kapil

    We worked on the client-side part only and server-side was implemented by third party.So we cannot show you web.xml.

    Cheers,
    Kapil

  • chris

    Can you show the import statements please, or provide full code download. I tried the code, and it isn’t compiling. I guess I have the wrong imports present

  • http://www.makeurownrules.com Kapil Jain

    Hi Chris,

    We have updated the code with import statements.Please take a look and let us know if you face any issue.

    Cheers,
    Kapil

  • Jose

    Would this work if instead of 443 I decide to use any other port?

    Thanks,

  • http://www.makeurownrules.com Kapil Jain

    Hi Jose,

    It should work for any port. Let me know if you have any issues.

    Cheers,
    Kapil

  • Michael Schramm

    thx to you I finially found a way to get https working with springframework

  • http://www.ipragmatech.com/ Kapil Jain

    Glad to hear that this article help you :-)