Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SSL connection reuse with Android HttpClient

I'm developing a secure web service between my self-implemented java web proxy (that forwards requests to the actual web service) and an android application.

Doing so with standard (insecure) http connections works perfectly well. Now I want to use a secure (SSL) connection between the proxy and the android client.

This works as long as I instantiate a new HttpClient for each request, which is beside wasting resources extremely slow as I'm is doing a two way handshake for each request.

So I'm trying to reuse the HttpClient for each request which results for secure connections in the following exception

java.lang.IllegalStateException: Connection already open. at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:150) at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360) at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)

When I change my proxy and the client to no-ssl communication it works without any problems. Does anybody know what I'm doing wrong? Thanks a lot for your help!

By the way the server code is totally similar except using SSLServerSocket with loaded certificates instead of using ServerSocket.

Client parameter setup

// Set basic data
    HttpParams params = new BasicHttpParams();
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
    HttpProtocolParams.setContentCharset(params, "UTF-8");
    HttpProtocolParams.setUseExpectContinue(params, true);
    HttpProtocolParams.setUserAgent(params, "Android app/1.0.0");

    // Make pool
    ConnPerRoute connPerRoute = new ConnPerRouteBean(12);
    ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);
    ConnManagerParams.setMaxTotalConnections(params, 20);

    // Set timeout
    HttpConnectionParams.setStaleCheckingEnabled(params, false);
    HttpConnectionParams.setConnectionTimeout(params, connectionTimeoutMillis);
    HttpConnectionParams.setSoTimeout(params, socketTimeoutMillis);
    HttpConnectionParams.setSocketBufferSize(params, 8192);

    // Some client params
    HttpClientParams.setRedirecting(params, false);

Http client creation

// load truststore certificate
            InputStream clientTruststoreIs = context.getResources().openRawResource(R.raw.server);
            KeyStore trustStore = KeyStore.getInstance("BKS");
            trustStore.load(clientTruststoreIs, "server".toCharArray());

            // initialize trust manager factory with the read truststore
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(trustStore);

            // setup client certificate

            // load client certificate
            InputStream keyStoreStream = context.getResources().openRawResource(R.raw.client);
            KeyStore keyStore = KeyStore.getInstance("BKS");
            keyStore.load(keyStoreStream, "client".toCharArray());

            // initialize key manager factory with the read client
            // certificate
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, "client".toCharArray());

            // initialize SSLSocketFactory to use the certificates
            SSLSocketFactory socketFactory = new SSLSocketFactory(SSLSocketFactory.TLS, keyStore, "client", trustStore, null, null);

            // Register http/s shemas!
            SchemeRegistry schReg = new SchemeRegistry();
            schReg.register(new Scheme("https", socketFactory, port));
            ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);

            httpClient = new DefaultHttpClient(conMgr, params);

Client request execution

HttpResponse response = httpClient.execute(request);
        HttpEntity entity = response.getEntity();
        in = entity.getContent();
        String result = convertStreamToString(in);
        in.close();
like image 680
user1033552 Avatar asked Sep 21 '12 12:09

user1033552


Video Answer


1 Answers

I have this exact same issue with Android and HttpClient - it only seems to manifest itself when using a client-side certificate, just like you have. Remove client auth and it works fine, haven't found a workaround as of yet.

Edit:

Enable stale connection checking.

HttpConnectionParams.setStaleCheckingEnabled(params, true);

Fixed it for me.

like image 190
user705142 Avatar answered Oct 22 '22 15:10

user705142