Android scanned login


Table of Contents:

Setup:

Demo App Analysis:


Prerequisites


Dependencies

  • Android Studio with Android SDK 16 or higher
  • Android SDK build tools 25.0.0
  • Android NDK
  • Also use Android SDK tools to install CMake

Downloading the repo

Then download the Android SDK repo from https://github.com/miracl/incubator-milagro-mfa-sdk-android

Note that the repo includes a submodule. So after downloading run:

git submodule init
git submodule update

You can rename the repo as you wish.


Building the SDK


To build the SDK:

From Android Studio:

Import the project from the Android Studio welcome screen by clicking on Import project (Eclipse ADT, Gradle, etc.):

studio_import_proj

The assembled aars will be located in /mpinsdk/build/outputs/aar

From Command Line:

  1. Navigate to the top level folder of the Android project
  2. Execute ./gradlew build
  3. The assembled aars will be located in /mpinsdk/build/outputs/aar

Create a demo web app to log into


Now that the project is imported, in order to enable you to test the demo iOS app, you should first of all create a demo MFA web app using one of our web SDKs, as explained in the SDK Instructions section of this documentation.

This involves the following:

  1. Register a new app in the MIRACL Trust® authentication portal (this is detailed in the instructions for each web SDK mentioned in step 2)
  2. Run a demo app using one of our web SDKs (tornado, flask, django, nodejs, ruby, php, go, java, dotnet)
  3. In your web browser, visit the configured url for the demo web app configured in step 2 (as per the instructions, this can be a simple localhost url such as http://127.0.0.1:5000) and click on the login button: php login
  4. You will then be able to scan the resulting QR code and login with an iOS app built as per the instructions to follow in this guide

Before building an iOS app, you will need to obtain your company id as the owner of the MFA web app. This is visible as a tooltip in the top right corner of your company dashboard in the portal:

view cid


Add mpin_cid to the project and build the APK


Once you have the company id / mpin_cid, open mfaSample/src/main/res/values/strings.xml from within your project folder, and enter it into the following line:

<string name="mpin_cid" formatted="false" translatable="false">company id / mpin_cid goes here</string>

Then save and close the file.

You can now build the apk from the 'mfaSample' folder. In Android Studio, select the 'mfaSample' folder and click on the 'build' menu:

build_apk

Then choose 'Build APK' and the APK will be output to the mfaSample/build/outputs/apk/ directory. This can then be installed for testing on an Android device.

You can now test the Android app via the following steps:

  1. Run your demo web MFA app and access it in your browser at e.g. http://127.0.0.1:5000

  2. Click on the login button

  3. Use your installed Android demo app to register and login with your MFA web app

Android Demo App Overview


The following tree view illustrates the file structure of the demo application found in the mfaSample subfolder:

treeview


SampleApplication.java


Here the SDK is intialized and the same instance is used throughout the application


QrReaderActivity.java


When the app is first loaded on your phone, the QR reader will be displayed.

Please see the code file itself for commented code on the operation of the QR Reader.

Once the information from the QR code has been read, within private void onQrUrlReceived new MpinMFA and ServiceDetails objects are created:

private void onQrUrlReceived(String url) {
        Uri qrUri = Uri.parse(url);
        stopCameraPreview();

        // Check if the url from the qr has the expected parts
        if (qrUri.getScheme() != null && qrUri.getAuthority() != null && qrUri.getFragment() != null && !qrUri.getFragment()
          .isEmpty()) {

            // Obtain the access code from the qr-read url
            mCurrentAccessCode = qrUri.getFragment();

            final String baseUrl = qrUri.getScheme() + "://" + qrUri.getAuthority();

            // Obtain the service details and set the backend
            new AsyncTask<Void, Void, Status>() {

                @Override
                protected com.miracl.mpinsdk.model.Status doInBackground(Void... voids) {
                    MPinMFA mPinMfa = SampleApplication.getMfaSdk();
                    ServiceDetails serviceDetails = new ServiceDetails();

                    // MPinSDK methods are synchronous, be sure not to call them on the ui thread
                    com.miracl.mpinsdk.model.Status serviceDetailsStatus = mPinMfa.getServiceDetails(baseUrl, serviceDetails);
                    if (serviceDetailsStatus.getStatusCode() == com.miracl.mpinsdk.model.Status.Code.OK) {

                        com.miracl.mpinsdk.model.Status backendStatus = mPinMfa.setBackend(serviceDetails.backendUrl);
                        if (backendStatus.getStatusCode() == com.miracl.mpinsdk.model.Status.Code.OK) {
                            mCurrentServiceDetails = serviceDetails;
                            // If the backend is set successfully, we can retrieve the session details using the access code
                            SessionDetails details = new SessionDetails();
                            return mPinMfa.getSessionDetails(mCurrentAccessCode, details);
                        } else {
                            return backendStatus;
                        }
                    } else {
                        return serviceDetailsStatus;
                    }
                }

getServiceDetails passes the url which has been extracted from the QR Code. The backendUrl is then returned, which is needed for the SDK to connect to the authentication platform.

setBackend then uses the returned backendUrl to make the connection and getSessionDetails uses the access code retrieved from the QR reader to retrieve the session details from the backend. These are returned as follows:

public class SessionDetails {

    public String prerollId;
    public String appName;
    public String appIconUrl;
}

Then, in private void onBackendSet(), listUsers will fetch the list of stored users in the app to see if there are any users already registered with the current backend service. An ArrayList is created and checked with an if statement:

if (currentBackendRegisteredUsers.isEmpty()) {
    // If there are no users, we need to register a new one
    startActivity(new Intent(QrReaderActivity.this, RegisterUserActivity.class));
} else {
    // If there is a registered user start the authentication process
    mCurrentUser = currentBackendRegisteredUsers.get(0);
    mEnterPinDialog.setTitle(mCurrentUser.getId());
    mEnterPinDialog.show();

If there are no users a new intent launches the RegisterUserActivity view:

reg_user

If the user has previously registered with the backend service, then the EnterPinDialog is shown to enable login (note that the demo app only allows for one identity per backend):

pin_dialog1

Once the user has registered and/or interacted with the PIN dialog, this activity then 'picks up the baton' again in public void onPinEntered(final String pin).

@Override
public void onPinEntered(final String pin) {
    new AsyncTask<Void, Void, Status>() {

        @Override
        protected com.miracl.mpinsdk.model.Status doInBackground(Void... voids) {
            MPinMFA mPinMfa = SampleApplication.getMfaSdk();
            if (mCurrentUser != null && mCurrentAccessCode != null) {
                // Start the authentication process with the scanned access code and a registered user
                com.miracl.mpinsdk.model.Status startAuthenticationStatus = mPinMfa
                  .startAuthentication(mCurrentUser, mCurrentAccessCode);
                if (startAuthenticationStatus.getStatusCode() == com.miracl.mpinsdk.model.Status.Code.OK) {
                    // Finish the authentication with the user's pin
                    return mPinMfa.finishAuthentication(mCurrentUser, pin, mCurrentAccessCode);
                } else {
                    return startAuthenticationStatus;
                }
            } else {
                return null;
            }
        }

startAuthentication(mCurrentUser, mCurrentAccessCode) then starts the authentication process by passing the user and access code to the server, in order to obtain a time permit which confirms that the user is authorized to attempt authentication. If this is successful then the process is completed with finishAuthentication(mCurrentUser, pin, mCurrentAccessCode) which combines the entered PIN with the user's access token which was stored in the app when they successfully registered.

The demo app then shows a failed or successful login using simple toast messages. The getId() method can be used to display the user:

loggedin_toast


RegisterUserActivity.java


This activity manages the initial user registration process which will have been kicked off when it is identified that the user is not yet registered, as described in the QrReaderActivity above. To begin registering the user will be asked to enter their email:

reguser

The Submit Button

Within the private void onSubmitClick() code bracket the user's email address is obtained and a new user object is then created with the SDK:

SampleApplication.getMfaSdk().makeNewUser(email, "Android Sample App");

Note that the second variable which is passed with makeNewUser is 'deviceName'. Here the text string has been entered manually, but some backends may require the device name to be captured, to use it later to determine which ID is associated with this device. It is also possible to use this method with just the first id variable being passed.

After we have a user, we can start the registration process for them. If successful this will trigger sending a confirmation email from the current backend

return SampleApplication.getMfaSdk().startRegistration(mCurrentUser, SampleApplication.getCurrentAccessCode());

Toast messages are then used in conjunction with using getStatusCode() to retrieve the status from the SDK.

Once the user's email address has been submitted, they will be presented with the confirmation screen:

confirm_email

The Confirmed Button

By this stage, the user will have received an email containing a confirmation link. Once they have activated the link, they will be able to click on the confirmed button to continue the process.

Within the private void onConfirmClick() code bracket, the confirmRegistration method is used to check that the user has indeed confirmed. A status of OK will be returned if this is the case. If the status is OK then the EnterPinDialog is shown:

if (status.getStatusCode() == com.miracl.mpinsdk.model.Status.Code.OK) {
        mEnterPinDialog.show();

The user can then set up their pin:

registered_create_pin

Once the user has set up their pin, public void onPinEntered() makes use of finishRegistration(mCurrentUser, pin) to complete registration of the user. The user's token is extracted and stored securely, their user state is set to REGISTERED and status is OK.

If the status is OK then a new intent opens the RegistrationSuccessfulActivity:

if (status.getStatusCode() == com.miracl.mpinsdk.model.Status.Code.OK) {
    startActivity(new Intent(RegisterUserActivity.this, RegistrationSuccessfulActivity.class));
    finish();
}

RegistrationSuccessfulActivity.java


Once the user has registered this activity enables the user to finally login to the service:

reg_successful

The Login button

In this activity, the onLoginClick code block is just used to trigger the EnterPinDialog:

private void onLoginClick() {
        mLoginButton.setEnabled(false);
        mEnterPinDialog.show();
    }

Once the user has entered their PIN, within onPinEntered() a listUsers() check is made to see if there is a stored user registered with the backend service that is being logged into. If this is successful, then startAuthentication(mCurrentUser, SampleApplication.getCurrentAccessCode()) is used to start the authentication with the stored access code and the registered user. Following this if startAuthenticationStatus.getStatusCode() gives a result of OK, then finishAuthentication(mCurrentUser, pin, SampleApplication.getCurrentAccessCode()) completes the authentication with the user's entered PIN.

Within onPostExecute(), toast messages are then used to display login success or failure depending on the status returned by getStatusCode().

Top