Android N – Security with Self Signed Certificates

Posted By Hoyt Summers Pittman

If you are a good developer you are securing your services with SSL encryption. Unless you have put in a lot of effort, local testing still uses the good old fashioned self signed certificate and just click through the warning window of shame.

Screenshot from 2016-05-04 13-04-42

This is great until you are writing a RESTful service to be consumed by something which isn’t a browser. If you are an Android developer you have probably come across blog posts (or the official Android docs) encouraging you to make your own Trust Manager to accept your certificate or, worse, disable certificate checking altogether! However, Android N has come to the rescue with new security configuration features.

Using Self Signed Certificates with Android N

To use a self signed certificate you need to

  1. Add a meta-data tag to your AndroidManifest.xml which points to a security configuration xml file
  2. Add to your xml resources directory the security configuration file
  3. Download your self signed certificate to your project

Edit AndroidManifest.xml

I’ve added in my projects the following code to Android Manifest’s application element

<meta-data android:name="android.security.net.config"
               android:resource="@xml/network_security_config" />

This code just informs Android that the configuration file is found in res/xml/network_security_config.xml.

Creating the Network Security Config

The full documentation for the network security files covers a lot more than our use case for a self signed certificate. It is well worth a read to understand what is being done.

Here is my XML file to load my certificate from the raw directory. I have it named server_aerogear_dev, but the file name is irrelevant. What matters is that the common name in the certificate file matches the domain name of the server. I am pretty sure that this also works with IP addresses, but I haven’t tested it.

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="@raw/server_aergear_dev"/>
        </trust-anchors>
    </base-config>
</network-security-config>

Downloading the certificate

You can download the certificate to the raw directory in your source using your web browser or using the command line.

cd app/src/main/res/raw;
echo -n | openssl s_client -connect server.aerogear.dev:8443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > server_aerogear_dev
// Credit to SO : http://serverfault.com/questions/139728/how-to-download-the-ssl-certificate-from-a-website

Replace the name of the server and the port with configuration appropriate to you.

Final Notes

This is a very simple example of a new feature from Android N. This may change or go out of date. However, this gives us a simple was to manage security and it ALSO works within Android’s build flavor system. Take a look, and stay safe.

May 4th, 2016

RHMAP and Google Accounts in Android

Posted By Hoyt Summers Pittman

The Red Hat Mobile Application Platform (RHMAP) has strong authentication and authorization mechanisms baked into its Auth Policy system. Android has deep integration with Google’s ecosystem which provides many easy mechanisms for authorizing services to act on a user’s behalf. Out of the box RHMAP allows for connecting to a Google account using OAuth and a web view, but a better user experience is using Google’s Android account picker. To enable this integration in RHMAP we have to use a MBaaS Auth Policy.

Prerequisites

This post should be informative to anybody who wishes to learn more about RHMAP; however, you will have the most benefit if you have access to a RHMAP instance and have read through the Getting Started documentation. If you do not have access to a instance of RHMAP, you may sign up for a free one at openshift.feedhenry.com.

Additionally you will need a Google account and Android emulator or device with Google’s APIs set up.

Demo

You can view an example of this integration in my FehBot video. The Android portion of this post will refer to the code in the application.

Creating an MBaaS Auth Policy

Create a blank MBaaS Service

Select “Services & APIs” from the top navigation. Click “Provision MBaaS Services/API”

CReate_MBaaS_1

Select “Choose” next to the item “New mBaaS Service”.

CReate_MBaaS_2

Name the service, click “Next”, ensure you are using the “Development” environment, and finally click “Deploy”. The service should deploy and you should have a green bar.

CReate_MBaaS_3

You are now ready to set up the Auth Policy.

Setup the Auth Policy

Select “Admin” from the top navigation and then “Auth Policies” from the 6 boxes which appear. Create_auth_policy_1

Click “Create” on the next screen to begin setting up an Auth Policy.
CReate_Auth_Policy_2

Name the Policy and select “MBaaS Service” as the “Type” under “Authentication. From the “Service” drop down select the service you created in the previous step. For “Endpoint” our MBaaS service will use “/auth/init”. Finally select for your “Default Environment” the value “Development.
CReate_Auth_Policy_3

Scroll down to the bottom of the page and click “Create Auth Policy”.

Implementing the MBaaS

I have created a MBaaS Service for us to use. It implements the server side token validation that Google recommends in its documentation. You should be able to copy this project into your MBaaS’s source and redeploy it.

You may wish to limit which Cloud applications can access your MBaaS services in the “Service Settings” section of the MBaaS “Details” page.

Create_MBaas_4

/auth/init

The /auth/init route will consume tokens from the Android device and set up user accounts in RHMAP. The code should be easy ish to follow along. The most important part is that we return a userId value in the json which we can use to look up the user’s session informaiton.

/list/:session

The route /list/:session can be used by Cloud applications to fetch a user’s account information which is created and saved after a call to “/auth/init”.

Android Integration

In order to integrate with Android, please follow Google’s Guide for instructions on how to setup an Android account and get an IdToken from a sign in. The FehBot Android client contains a working example.

Once you have a IdToken you can use FH.buildAuthRequest to perform the sign-in with RHMAP. For the three parameters us the Auth Policy name you assigned during “Setup the Auth Policy”, the IdToken you retrived from Google, and an empty string for the final parameter. Here is an example from the FeHBot app.

Caveats

As per the RHMAP Authentication API if you use this you will have to manually verify your sessions in your application yourself. The built in verification methods will not work.

Conclusion

As you can see, it is easy to add a third party authentication mechanism to RHMAP. The principles in this post can be applied to many other authentication providers and client platforms.

Mar 23rd, 2016

Picasso and Keycloak

Posted By Hoyt Summers Pittman

So over the weekend I was trying to use Picasso to cleanly load images served by a server secured using KeyCloak. This was surprisingly easy using AeroGear’s authz library.

I needed the following dependencies in my apps build.gradle file

    //AGDroid deps
    compile 'org.jboss.aerogear:aerogear-android-core:2.1.0'
    compile 'org.jboss.aerogear:aerogear-android-security:2.1.0'
    compile 'org.jboss.aerogear:aerogear-android-store:2.1.0'
    compile 'org.jboss.aerogear:aerogear-android-authz:2.1.0'
    //Picasso deps
    compile 'com.squareup.picasso:picasso:2.5.2'
    compile 'com.squareup.okhttp:okhttp:2.4.+'
    compile 'com.squareup.okio:okio:1.5.0'

And I configure Picasso with the following

OkHttpClient picassoClient = new OkHttpClient();

        picassoClient.interceptors().add(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                ModuleFields fields = AuthorizationManager.getModule("KeyCloakAuthz").loadModule(null, null, null);
                Pair<String, String> header = fields.getHeaders().get(0);
                Request newRequest = chain.request().newBuilder()
                        .addHeader(header.first, header.second)
                        .build();
                return chain.proceed(newRequest);
            }
        });

        picasso = new Picasso.Builder(appContext).downloader(new OkHttpDownloader(picassoClient)).build();

*KeyCloakAuthz* is a AuthzModule protecting my server. You can find out more about them on the AeroGear website.

Jul 8th, 2015

Aerogear Android 2.1 Released

Posted By Hoyt Summers Pittman

AeroGear 2.1

What’s New

Sync Alpha

AeroGear has released the first alpha of our data sync technology. This includes the AeroGear Sync Server and libraries for iOS, JavaScript, and of course Android. This technology allows for cross platform data synchronization as seen here :

AeroGear SyncDemo from Christos Vasilakis on Vimeo.

If you followed the development of the Android library you will remember that we originally tried to use Google’s XMPP services as the medium for data sync. Because of technical limitations we dropped this idea and moved to wrapping the Netty client provided with AeroGear Sync Server in an Android service instead.

To activate the service you need to add it to you AndroidManifest.xml file. You will also need to provide properties for serverHost, serverPort, and serverPath. These properties are defined by where you have deployed the sync server. Here is an example connecting to the sync server running on the host of an emulated Android device:

 <service android:name="org.jboss.aerogear.android.sync.SyncService">
  <meta -data
  android:name="serverHost"
  android:value="10.0.2.2" />
  <meta -data
  android:name="serverPort"
  android:value="7777" />
  <meta -data
  android:name="serverPath"
  android:value="/sync" />
</service>

Any Activty you want to receive sync events needs to implement the SyncServerConnectionListener interface, bind itself to the SyncService instance, and then subscribe to events on connections.

Binding and subscribing example :

@Override
protected void onStart() {
 super.onStart();
 serviceConnection = new ServiceConnection() {

  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   final SyncService syncService = ((SyncService.SyncServiceBinder) service).getService();
   SyncActivity.this.service = syncService;
   syncService.subscribe(SyncActivity.this);
  }

  @Override
  public void onServiceDisconnected(ComponentName name) {
   finish();
  }
 };
}

@Override
protected void onResume() {
 super.onResume();
 Intent syncServiceIntent = new Intent(this, SyncService.class);
 bindService(syncServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}

SyncServerConnectionListener implementation Example :

@Override
//Called when the SyncService instance is connected to the Sync server AND the Activity is subscribe to the service after binding.
public void onConnected() {
 /*clientId is a unique identifier which identifies the device connection*/
 clientId = getSyncService().getClientId();

 /*a client document is a document the sync APIs know how to synchronize and is managed by the sync libraries*/ 
 final ClientDocument<jsonnode> clientDocument = clientDoc(documentId, clientId, JsonUtil.toJsonNode(content));

 /*adding a document to the service causes it to send and receive updates*/
 getSyncService().addDocument(clientDocument);
}

@Override
//Called when the document is updated by an external source
public void patched(final ClientDocument data) {
 runOnUiThread(new Runnable() {
  @Override
  public void run() {
   final ClientDocument</jsonnode><jsonnode> document = (ClientDocument</jsonnode><jsonnode>) data;
   final Info updates = JsonUtil.fromJsonNode(document.content());
   //handle your updates here.
  }
 });
}

For a full implementation demo look at our cookbook.

Minor Changes

Pipe improvements

After nearly two years we have implemented AGDROID-7 by adding Pipe.read(String id, Callback<t> callback). Now fetching by id is as simple as the following:

private void retrieveData() {
  LoaderPipe<data> pipe = application.getPipe(this);
  pipe.reset();
  pipe.read(String.valueOf(15), new MyCallback());
}

GCM Push Configuration

We’ve added some extra validation to the GCM Push Registrar. Now if you leave off properties such as variantId the library will throw an exception when you try to build the PushRegistrar as opposed to the registration method failing with an error callback.

GCM Unregistration

Now the library will check to see if you have a registered client before it attempts unregistration. Previously it would always make a call to the Push Server which would fail with a HTTP 404 error if you were not registered. Now the method immediately fails without a network call.

Demo Improvements

We’ve added a few demos to the official cookbook.
* Sync Demo This is the demo for our sync libraries.
* Two Factor This is an example of a Two-Factor One Time Password app using AeroGear.
* Password Manager This demonstrates using encryption to secure a password store behind a passcode.

We’ve also fixed some bugs in the Shoot and Share app as well as the AGReddit app.

What’s Next

For 2.2 and the future we are looking at improvements to our authz libraries as well as better offline resource management. As per usual you can watch our JIRA

About AeroGear

If you would like to learn more about AeroGear’s Android libraries a great place to start is our Android landing page. If you would like to participate in development, have questions, or want to chat with us our community section has all of our contact information.

Changelog

  • AGDROID-362 Migrate AeroDoc example to Gradle and move to cookbook repo
  • AGDROID-156 Update aerogear-crypto-android-demo and move to cookbook repo
  • AGDROID-343 AeroGearGCMPushConfiguration#buildRegistrar needs more validation
  • AGDROID-361 AGReddit should say Bad Password when you fail at logging in.
  • AGDROID-7 add pipe functionality to retrieve data by ID
  • AGDROID-312 Implement Android Client Sync Engine
  • AGDROID-369 Sync Android Demo app
  • AGDROID-313 Implement Android Sync Client
  • AGDROID-368 unregister fails with server returned the error code 405 android
  • AGDROID-385 Update AeroGear Sync README
  • AGDROID-377 Move DiffSync client into a android.app.Service
  • AGDROID-386 Deprecate and remove client-xmpp
  • AGDROID-370 XMPP Client NPE @ DiffSyncClientHandler.java:45
  • AGDROID-364 Package XMPP Sync Client to not include duplicate files
  • AGDROID-363 Refactor XMPP Sync Client to get below the 65k method limit
  • AGDROID-371 XMPP sync client should support json patch
  • AGDROID-367 Shoot-n-Share 401 error (invalid_client) on Google Drive upload
  • AGDROID-366 Shoot-n-Share does not offer keyboard for Keycloak redirected login screen
  • AGDROID-365 XMPP Sync Client does not handle multiple documents correctly
Mar 25th, 2015
Next Page »