Contents


Enhance mobile application security with Bluemix Mobile Services, Part 1

Secure client-side authentication with Mobile Client Access and Facebook

Comments

IBM's Bluemix® Mobile Services package includes a collection of back-end services that allow you to quickly build and scale iOS, Android, and hybrid mobile applications. In this two-part tutorial, you'll learn how to utilize two core Bluemix Mobile Services—Mobile Client Access and IBM Push Notifications—to create a secure cross-platform mobile application.

In this first part, you'll quickly create a mobile back end on Bluemix and connect it to a cross-platform mobile application built using StrongLoop and Node.js. You'll then be able to extend the mobile app for secure client-side authentication using Bluemix's Mobile Client Access service and Facebook. In Part 2, you'll extend and modify the Bluemix back end so that you can securely send broadcast push messages to registered devices using custom Node.js code.

We've provided application code for both Android and iOS, to demonstrate how to use the mobile client SDK to consume these mobile services.

What you'll need

For your basic development environment you'll need the following:

For the iOS mobile app you'll need:

For the Android mobile app you'll need:

  • An Android development environment (we recommend Android Studio)
  • A GCM sender ID and API key (see instructions on Bluemix)

This tutorial assumes you are familiar with programming for iOS and Android mobile apps.

Step 1. Create the mobile backend app on Bluemix

In the Bluemix catalog, you'll find the MobileFirst Services Starter boilerplate, which contains the core services for building mobile applications on Bluemix. You can leverage this boilerplate and the provided services to greatly ease the process of developing a secure mobile application.

Begin by creating an instance of the MobileFirst Services Starter boilerplate:

  • In the Boilerplates section of the Bluemix catalog, click MobileFirst Services Starter:
  • Enter a unique name and host for your mobile backend and click Create:
  • After the provisioning is complete you'll be taken to a Start Coding page, which will provide resources for deploying your app with the Cloud Foundry (CF) command-line interface. Click the Overview tab on the left-hand side of the page. You'll see a top-level view of the Node.js runtime and service tiles for your newly deployed Bluemix application:
  • Click the Mobile Options link in the top-right corner of the screen. Here you'll find your appRoute and appGUID. Keep this screen open in your browser; you'll need these parameters when you configure the mobile client application:

Step 2. Interact with your Bluemix mobile app

Using the browser of your choice, navigate to your mobile application's appRoute (<Application_Name>.mybluemix.net). You'll find a web app built with Node.js and StrongLoop that you can use to create, update, and view a set of list items. Familiarize yourself with the web application by clicking these prompts.

You'll note that the application's delete function doesn't yet work. The boilerplate Node.js code uses Mobile Client Access (MCA) to protect the delete endpoint. You'll have an opportunity to complete this function using the mobile client SDK later in the tutorial.

Bluemix and StrongLoop

When you build a Bluemix application with StrongLoop, it creates and stores API References at http://Your_Application_Name.mybluemix.net/explorer/#!/Item. Use the StrongLoop API Explorer, shown below, to familiarize yourself with the RESTful APIs for the for the backend web application. You'll utilize some of these later in this tutorial.

You can also access the source code for the bms-helloTodo-strongloop boilerplate application on GitHub.

Step 3. Get, configure, and run the demo

At this stage, you've developed a backend web application using StrongLoop and Node.js and created a few list items against an unprotected MCA instance, meaning no login is required. Next, you'll get, configure, and run the iOS or Android mobile app.

  1. Find the source code for the sample Android and iOS mobile applications in our GitHub repository.
  2. Use the Git command-line interface to clone the repository locally, save it to your computer using the GitHub Desktop app, or download the .zip directly.
  3. Configure and initialize the helloTodoAdvanced application for iOS or Android. (Note: Please stick to the configuration steps in the README documents for now. We'll complete and explain the remainder of the steps later in this tutorial.)
  4. Run the application for the first time on your desired platform:
    • In Xcode, click Product > Run.
    • In Android Studio, click Run and select a device.

When you run the Android or iOS mobile application for the first time, your client will initialize with your Bluemix instance and attempt to pull down the group of list items that you've created. If you're successful, the data you entered via the web interface will be displayed on the client app's main page. Here's a screenshot of the iOS app:

Here's the Android app:

Notes about the demo

Because MCA allows access using the mobile client SDK, you can edit, create, and even delete any of the to-do tasks (just hold the item on Android or swipe left on iOS).

You aren't required to log in to the application because you haven't yet enabled an authentication mechanism. The MCA configuration is all you need to securely access data.

Don't worry if you see a few errors in the logs! They're nonfatal and will be resolved when you enable IBM Push Notifications in Part 2.

How the client SDK communicates with Node.js

At the beginning of this tutorial you used StrongLoop to automatically create simple CRUD API endpoints. All the CRUD data interactions for the demo app are subsequently done via REST requests to your Bluemix StrongLoop-enabled Node.js application, using the mobile client SDK. In the code snippets below, you can see how the SDK provides the necessary APIs for easy RESTful interactions.

Listing 1 shows the IMFResourceRequest for iOS.

Listing 1. iOS: ViewController.m
- (void) createItem: (NSString*) itemText
{
    NSString *restAPIURL = [NSString stringWithFormat:@"%@/api/Items",_backendRoute];
    IMFResourceRequest* request = [IMFResourceRequest requestWithPath:restAPIURL];
    NSDictionary *jsonDict = [NSDictionary dictionaryWithObjectsAndKeys:
                              itemText, @"text",
                              @"false", @"isDone", nil];
    NSData *data = [NSJSONSerialization dataWithJSONObject:jsonDict options:NSJSONWritingPrettyPrinted error:nil];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPBody:data];
    [request sendWithCompletionHandler:^(IMFResponse *response, NSError *error) {
        if (error != nil) {
            NSLog(@"createItem failed with error: %@",error);
        }
        else {
            NSLog(@"Item created successfully"); 
        }
        [self listItems];
    }];


}

Listing 2 shows the Request for Android, sending item information to the API endpoint for item creation.

Listing 2. Android: MainActivity.java
// Create JSON for new TodoItem, id should be 0 for new items
String json = "{\"text\":\"" + name + "\",\"isDone\":false,\"id\":0}";

// Create POST request with the Bluemix Mobile Services SDK and set HTTP headers so Bluemix knows what to expect in the request
Request request = new Request(bmsClient.getBluemixAppRoute() + "/api/Items", Request.POST);

HashMap headers = new HashMap();
List<String> contentType = new ArrayList<>();
contentType.add("application/json");
List<String> accept = new ArrayList<>();
accept.add("Application/json");

headers.put("Content-Type", contentType);
headers.put("Accept", accept);

request.setHeaders(headers);

request.send(getApplicationContext(), json, new ResponseListener() {
   // On success, update local list with new TodoItem
   @Override
   public void onSuccess(Response response) {
       Log.i(TAG, "Item " + name + " created successfully");

       loadList();
   }

   // On failure, log errors
   @Override
   public void onFailure(Response response, Throwable throwable, JSONObject extendedInfo) {
       String errorMessage = "";

       if (response != null) {
           errorMessage += response.toString() + "\n";
       }

       if (throwable != null) {
           StringWriter sw = new StringWriter();
           PrintWriter pw = new PrintWriter(sw);
           throwable.printStackTrace(pw);
           errorMessage += "THROWN" + sw.toString() + "\n";
       }

       if (extendedInfo != null){
           errorMessage += "EXTENDED_INFO" + extendedInfo.toString() + "\n";
       }

       if (errorMessage.isEmpty())
           errorMessage = "Request Failed With Unknown Error.";

       Log.e(TAG, "addTodo failed with error: " + errorMessage);
   }
});

You'll notice the data interaction requests all hit the https://<Your_Application_Name>.mybluemix.net/api/Items endpoint, allowing you to appropriately react to any HTTP response. You always want to be in sync with the cloud data, so when you successfully create an item, make sure to GET the remote list data from our Node.js cloud server.

Next we'll show you how to use Bluemix Mobile Services to secure your mobile application data.

Step 4. Configure Facebook authentication

You can configure MCA to use Facebook authentication to better secure your application data, by giving each user a unique identity. In this section you'll first create and configure a Facebook application using Facebook's Developer site, then configure your MCA instance to utilize the Facebook app as an authentication mechanism.

Set up your Facebook application

If you've already created a Facebook application you can skip the next steps; just make sure that the settings for your app match the settings described below.

  1. Create the Facebook application using the instructions from the Facebook's Developer site. If you need help, follow the instructions in "Obtaining a Facebook application ID from the Facebook Developer Portal."
    • Configurations for iOS: Add the desired platform (iOS) and bundle ID ("com.ibm.helloTodoAdvanced") to your Facebook application:
      Note that we recommend using an APNs-enabled bundle ID. It will be required when configuring push notifications later in the tutorial.
    • Configurations for Android: Add the Google Play Package Name ("com.ibm.helloTodoAdvanced") and class name ("com.ibm.helloTodoAdvanced.MainActivity") for the demo:
      Note that the Google Play Package Name and Class Name must be identical to the above screenshot to successfully run the Android version of the example application. Follow Steps 5 through 9 in the listed documentation to get the correct Key Hash for your development environment.
  2. After you've configured and created your Facebook application, you must provide the configurations to your MCA instance on Bluemix. Navigate back to your Bluemix application and click the Mobile Client Access service to open the MCA dashboard.
  3. Click SET UP AUTHENTICATION and choose Facebook:
  4. Add the Application ID to the User Authentication for Facebook:

Great! You now have set up Facebook authentication on your mobile backend application.

Configure client-side authentication

Next, you will configure the client-side helloTodoAdvanced application for Facebook authentication.

For iOS:

  1. Update the Info.plist file with your Facebook application ID and display name. You can get both from the Facebook developer console.
  2. Update URL Types > Item 0 > URL Schemes > Item 0. Update Item 0 using your client ID from the Facebook developer console; for example: fb1581349575427190.

For Android:

  1. Navigate to the strings.xml file, in the Android\helloTodoAdvanced\bluelist\app\src\main\res\values\ directory. Replace Your_Facebook_App_Id with the appID from the application you created.
  2. Verify that your Google Play package name in your Facebook appID is com.ibm.helloTodoAdvanced and that your class name is com.ibm.helloTodoAdvanced.MainActivity.

Run the application

Try running helloTodoAdvanced to see how the changes you've made affect the application. Notice that the application now requires Facebook authentication before it will display the list item data.

Log in with your Facebook account (only public profile information is required). After successful login you'll be able to see and interact with the list data. The first screenshot below shows the Facebook login page:

And here's the application with a to-do list item shown:

Client-side configuration details

You've successfully set up and configured your mobile application for Facebook authentication. We'll conclude Part 1 with a closer look at the client-side code that enabled us to use Facebook as an authentication mechanism with MCA.

iOS config

In iOS, you perform the client-side configuration in AppDelegate.m. You can see more information about the code at "Enabling Facebook authentication in iOS apps."

In the ViewController.m, you use the obtainAuthorizationHeaderWithCompletionHandler API call to kick off the authentication process and obtain the authorization token from the MCA instance. On a successful authentication, you obtain an authorization header, which the mobile client SDK automatically includes with outbound REST requests to protected resources, as shown in Listing 3.

Listing 3. iOS ViewController.m
-(void)obtainAuthorizationToken{
    IMFAuthorizationManager *authManager = [IMFAuthorizationManager sharedInstance];
    [authManager obtainAuthorizationHeaderWithCompletionHandler:^(IMFResponse *response, NSError *error) {
        if (error != nil) {
            NSLog(@"%@",error);
        } else {
            NSLog(@"You have obtained the authorization token from Bluemix successfully.");
            //Register for Push once Login to MCA is successful
            [self registerForPush];
[self listItems];
        }
        }];
}

This function is called as the main view loads, so the authentication process begins as the application starts. You can then only pull down the list items once the user has been successfully authenticated. As you can see in the code, you kick off the push registration process following a successful login. You'll learn more about the push registration process in Part 2.

Android config

In MainActivity.java, you'll see the initAuth() function within onResume(). This ensures that every time the app enters the foreground, it will obtain an authorization header to validate against MCA.

The obtainAuthorizationHeader call is what issues the authentication request that kicks off Facebook authentication from the device. A new intent is created for the login prompt, enabled by the FacebookAuthorization SDK and AndroidManifest.xml changes.

For more information about how to configure and enable this login see "Enabling Facebook authentication in Android apps."

Upon a successful login the user is able to see the application data. Under the hood, MainActivity.java implements the ResponseListener interface, which requires the three overridden functions in order to securely handshake with your Bluemix MCA instance: onActivityResult(), onSuccess(), and onFailure().

Assuming that the Facebook login succeeds, your next step will be to load the list data from your Node.js app and register the app and device with the IBM Push Notifications service. We'll set up push notifications in Part 2. For now just study the code.

Listing 4. Android MainActivity.java
onSuccess()

@Override
public void onSuccess(Response response) {
    Log.i(TAG,"Successfully authenticated against MCA: " + response.getResponseText());

    // Register for push notifications and show data now that the user is authenticated
    registerForPush();
    loadList();
}

If a request from MCA Facebook authorization fails, the local list is wiped to protect the data. Note that any of the parameters can be null depending on the type of failure. Listing 5 shows the output of an authorization failure.

Listing 5. Android MainActivity.java
onFailure()

@Override
public void onFailure(Response response, Throwable throwable, JSONObject extendedInfo) {

   if(!mTodoItemAdapter.isEmpty()){
       Log.i(TAG, "clearing list data since authentication failed");
       mTodoItemList.clear();
       mTodoItemAdapter.notifyDataSetChanged();
   }

   String errorMessage = "";

   // Check for 404s and unknown host exception since this is the first request made by the app
   if (response != null) {
       if (response.getStatus() == 404) {
           errorMessage += "Application Route not found at:\n" + BMSClient.getInstance().getBluemixAppRoute() +
                   "\nPlease verify your Application Route and rebuild the app.";
       } else {
           errorMessage += response.toString() + "\n";
       }
   }

   // Be sure to check for null pointers, any of the above parameters may be null depending on the failure.
   if (throwable != null) {
       if (throwable.getClass().equals(UnknownHostException.class)) {
           errorMessage = "Unable to access Bluemix host!\nPlease verify internet connectivity and try again.";
       } else {
           StringWriter sw = new StringWriter();
           PrintWriter pw = new PrintWriter(sw);
           throwable.printStackTrace(pw);
           errorMessage += "THROWN" + sw.toString() + "\n";
       }
   }

   if (extendedInfo != null){
       errorMessage += "EXTENDED_INFO" + extendedInfo.toString() + "\n";
   }

   if (errorMessage.isEmpty())
       errorMessage = "Request Failed With Unknown Error.";

   Log.e(TAG, "Failed to authenticate against MCA: " + errorMessage);

}

The protected onActivityResult function enables interaction between MCA and your MainActivity, needed for proper authentication.

Listing 6. onActivityResult
onActivityResult()

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    FacebookAuthenticationManager.getInstance().onActivityResultCalled(requestCode, resultCode, data);
}

In addition to security features, MCA also provides monitoring and analytics for your mobile applications, including usage statistics and client-side log capture.

Now that you've run the example application successfully a few times, you should be able to see some of your data in the Monitoring tab of your Bluemix MCA instance.

Conclusion to Part 1

In the first half of this tutorial you've set up your development environment using Bluemix Mobile Services and the iOS or Android environment of your choice. You've created a web application backend on Bluemix and connected it to a mobile app built with StrongLoop and Node.js. You then used MCA to configure and enable your mobile app for secure Facebook authentication. In Part 2, we'll introduce IBM Push Notifications, which you'll use for secure broadcast push notification in your Node.js mobile app.


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Mobile development, Cloud computing
ArticleID=1031043
ArticleTitle=Enhance mobile application security with Bluemix Mobile Services, Part 1
publish-date=05042016