Restlet client version 2.1.6, SSL configuration on Android

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Restlet client version 2.1.6, SSL configuration on Android

Mark Petrovic-2
Hello.  I am new to Restlet client programming.  I am attempting to use Restlet client 2.1.6 on Android.

I have read the documentation on SSL config by way of DefaultSslContextFactory, as well as having read StackOverflow articles on configuring an HttpsClientHelper.  I chose the latter route, as I could convince myself that the client helper approach installed the helper for all subsequent use of ClientResource.  However, I cannot get this approach to work.  I receive this error message in an exception from the Restlet client when I attempt to connect to the remote server:

Internal connector error 1002

No available client connector supports the required protocol: 2131034127. Please add the JAR of a matching connector to your classpath.

Here is my approach in detail:

1) Perform this once before any network calls are made:

        List<ConnectorHelper<Client>> registeredClients = Engine.getInstance().getRegisteredClients();
        registeredClients.add(0, new SslHelper(this));

where SslHelper is a subclass of HttpsClientHelper and is defined by

package com.homosuperiorus.clips.clients;

import android.content.Context;
import android.util.Log;

import com.homosuperiorus.clips.R;

import org.restlet.ext.ssl.HttpsClientHelper;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

public class SslHelper extends HttpsClientHelper {
    private final String TAG = "SslHelper";
    private KeyStore trustStore;

    public SslHelper(Context appContext) {
        super(null);
        InputStream inputStream = appContext.getResources().openRawResource(R.raw.keystore);
        try {
            trustStore = KeyStore.getInstance("BKS");
            trustStore.load(inputStream, "changeit".toCharArray());
        } catch (Exception e) {
            Log.d(TAG, "Keystore error", e);
            throw new RuntimeException(e);
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                Log.d(TAG, "error closing keystore inputStream", e);
            }
        }
    }

    @Override
    protected SSLContext getSslContext() {
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
            tmf.init(trustStore);
            sslContext.init(new KeyManager[0], tmf.getTrustManagers(), null);
            setSslContext(sslContext);
            return sslContext;
        } catch (NoSuchAlgorithmException shouldNeverHappen) {
            throw new RuntimeException(shouldNeverHappen);
        } catch (KeyStoreException shouldNeverHappen) {
            throw new RuntimeException(shouldNeverHappen);
        } catch (KeyManagementException shouldNeverHappen) {
            throw new RuntimeException(shouldNeverHappen);
        }
    }
}

The BKS keystore loads successfully.

Next, I setup and make the client call:

    public MyStuff getMyStuff() {
        ClientResource resource = new ClientResource(BASEURL);
        resource.setChallengeResponse(ChallengeScheme.HTTP_BASIC, credentials.userName, credentials.password);
        resource.accept(MediaType.APPLICATION_JSON);
        MyStuff myStuff;
        try {
            myStuff = resource.getChild(PATH).get(MyStuff.class);
            Log.d(TAG, myStuff.toString());
            return myStuff;
        } catch (ResourceException e) {
            String reasonPhrase = e.getStatus().getReasonPhrase();
            Log.d(TAG, String.format("Login with GET /mystuff failed:  status=%d, reason phrase=%s", e.getStatus().getCode(), reasonPhrase));
            return null;
        }
    }

The client throws a ResourceException, with the detail I provided above.

My dependencies on restlet are as follows:

dependencies {
    compile 'com.google.android:support-v4:r7'
    compile 'com.google.code.gson:gson:2.2.4'
    compile group: "org.restlet.android", name: "org.restlet", version: versions.restlet
    compile group: "org.restlet.android", name: "org.restlet.ext.json", version: versions.restlet
    compile group: "org.restlet.android", name: "org.restlet.ext.ssl", version: versions.restlet
}

I feel like this code is one line from working, but I cannot tell which line.  It sounds like I need another restlet jar on the classpath, but I cannot take a good guess at which one I'm missing.

Your help is much appreciated.

Thank you.

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=3071486
Reply | Threaded
Open this post in threaded view
|

RE: Restlet client version 2.1.6, SSL configuration on Android

Mark Petrovic-2
I worked more on this, but to no avail.  Here is my new set of dependencies, which seems more correct given the "net" jar and ssl support are both on the classpath:

dependencies {
    compile 'com.google.android:support-v4:r7'
    compile 'com.google.code.gson:gson:2.2.4'
    compile group: "org.restlet.android", name: "org.restlet", version: versions.restlet
    compile group: "org.restlet.android", name: "org.restlet.ext.json", version: versions.restlet
    compile group: "org.restlet.android", name: "org.restlet.ext.net", version: versions.restlet
}

This is a Gradle 1.9 build btw, wagged to some extent by my use of Android Studio 0.4x.  I'm ok with the Gradle build, which I mention for the sake of completeness.

The problem with this set of dependencies is that it does not change the original error 1002.  It also requires, during APK repackaging that I add this exclusion to the packaging in the build file:


        packagingOptions {
            exclude 'META-INF/services/org.restlet.engine.ClientHelper'
        }

If I do not exclude the META-INF file, I get this when I build:

validateDebugSigning
:packageDebug
Error: duplicate files during packaging of APK /Users/mpetrovic/Projects/ClipsAndroid/build/apk/ClipsAndroid-debug-unaligned.apk
        Path in archive: META-INF/services/org.restlet.engine.ClientHelper
        Origin 1: /Users/mpetrovic/.gradle/caches/modules-2/files-2.1/org.restlet.android/org.restlet.ext.ssl/2.1.6/5c1929b6ed270fe29688f6f76665c281fb898f62/org.restlet.ext.ssl-2.1.6.jar
        Origin 2: /Users/mpetrovic/.gradle/caches/modules-2/files-2.1/org.restlet.android/org.restlet.ext.net/2.1.6/c0b207da17369e94f1eda18aa107e302d09b9fa2/org.restlet.ext.net-2.1.6.jar
You can ignore those files in your build.gradle:
        android {
          packagingOptions {
            exclude 'META-INF/services/org.restlet.engine.ClientHelper'
          }
        }
:packageDebug FAILED

I'm out of ideas.  Please help.

Thanks.

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=3071492
Reply | Threaded
Open this post in threaded view
|

RE: Restlet client version 2.1.6, SSL configuration on Android

Mark Petrovic-2
In reply to this post by Mark Petrovic-2
Well, I'm making progress.  My original code failed to expand the Android R resource id's into actual strings.  So my URL was horribly mangled.  I fixed that.  

But I still see this exception when connecting over https:

     Caused by: Internal Connector Error (1002) - No available client connector supports the required protocol: 'HTTPS'. Please add the JAR of a matching connector to your classpath.
            at org.restlet.resource.ClientResource.doError(ClientResource.java:612)
            at org.restlet.resource.ClientResource.handleInbound(ClientResource.java:1202)
            at org.restlet.resource.ClientResource.handle(ClientResource.java:1026)
            at org.restlet.resource.ClientResource.handle(ClientResource.java:968)
            at org.restlet.resource.ClientResource.get(ClientResource.java:680)
            at com.homosuperiorus.clips.clients.TransmitsClient.getTransmits(TransmitsClient.java:27)
            at com.homosuperiorus.clips.models.TransmitsSource.getTransmits(TransmitsSource.java:38)
            at com.homosuperiorus.clips.fragment.ClipsListFragment$GetTransmitsTask.doInBackground(ClipsListFragment.java:93)
            at com.homosuperiorus.clips.fragment.ClipsListFragment$GetTransmitsTask.doInBackground(ClipsListFragment.java:83)
            at android.os.AsyncTask$2.call(AsyncTask.java:288)
            at java.util.concurrent.FutureTask.run(FutureTask.java:237)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
            at java.lang.Thread.run(Thread.java:841)

Here is my latest dependency list:

dependencies {
    compile group: 'com.google.android', name: 'support-v4', version: 'r7'
    compile group: 'com.google.code.gson', name: 'gson', version: '2.2.4'
    compile group: 'joda-time', name: 'joda-time', version: "2.3"
    compile group: "org.restlet.android", name: "org.restlet", version: versions.restlet
    compile group: "org.restlet.android", name: "org.restlet.ext.jackson", version: versions.restlet
    compile group: "org.restlet.android", name: "org.restlet.ext.net", version: versions.restlet
}

Anybody?

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=3071495
Reply | Threaded
Open this post in threaded view
|

Re: Restlet client version 2.1.6, SSL configuration on Android

Thierry Boileau-4
Hello Mark,

I'm also trying to figure out what happens. I'll keep you informed.

Best regards,
Thierry


2014/1/12 Mark Petrovic <[hidden email]>
Well, I'm making progress.  My original code failed to expand the Android R resource id's into actual strings.  So my URL was horribly mangled.  I fixed that.

But I still see this exception when connecting over https:

     Caused by: Internal Connector Error (1002) - No available client connector supports the required protocol: 'HTTPS'. Please add the JAR of a matching connector to your classpath.
            at org.restlet.resource.ClientResource.doError(ClientResource.java:612)
            at org.restlet.resource.ClientResource.handleInbound(ClientResource.java:1202)
            at org.restlet.resource.ClientResource.handle(ClientResource.java:1026)
            at org.restlet.resource.ClientResource.handle(ClientResource.java:968)
            at org.restlet.resource.ClientResource.get(ClientResource.java:680)
            at com.homosuperiorus.clips.clients.TransmitsClient.getTransmits(TransmitsClient.java:27)
            at com.homosuperiorus.clips.models.TransmitsSource.getTransmits(TransmitsSource.java:38)
            at com.homosuperiorus.clips.fragment.ClipsListFragment$GetTransmitsTask.doInBackground(ClipsListFragment.java:93)
            at com.homosuperiorus.clips.fragment.ClipsListFragment$GetTransmitsTask.doInBackground(ClipsListFragment.java:83)
            at android.os.AsyncTask$2.call(AsyncTask.java:288)
            at java.util.concurrent.FutureTask.run(FutureTask.java:237)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
            at java.lang.Thread.run(Thread.java:841)

Here is my latest dependency list:

dependencies {
    compile group: 'com.google.android', name: 'support-v4', version: 'r7'
    compile group: 'com.google.code.gson', name: 'gson', version: '2.2.4'
    compile group: 'joda-time', name: 'joda-time', version: "2.3"
    compile group: "org.restlet.android", name: "org.restlet", version: versions.restlet
    compile group: "org.restlet.android", name: "org.restlet.ext.jackson", version: versions.restlet
    compile group: "org.restlet.android", name: "org.restlet.ext.net", version: versions.restlet
}

Anybody?

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=3071495