org.openmidaas.library.MIDaaS.java Source code

Java tutorial

Introduction

Here is the source code for org.openmidaas.library.MIDaaS.java

Source

/*******************************************************************************
 * Copyright 2013 SecureKey Technologies Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *   
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package org.openmidaas.library;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Date;
import java.util.Map;

import org.json.JSONException;
import org.json.JSONObject;
import org.openmidaas.library.authentication.AVSAccessTokenStrategy;
import org.openmidaas.library.authentication.AVSDeviceRegistration;
import org.openmidaas.library.authentication.AuthenticationManager;
import org.openmidaas.library.authentication.DeviceRegistrar;
import org.openmidaas.library.authentication.SKDeviceAuthentication;
import org.openmidaas.library.common.Constants;
import org.openmidaas.library.common.WorkQueueManager;
import org.openmidaas.library.common.WorkQueueManager.Worker;
import org.openmidaas.library.common.network.AVSServer;
import org.openmidaas.library.common.network.AndroidNetworkFactory;
import org.openmidaas.library.common.network.ConnectionManager;
import org.openmidaas.library.model.core.AbstractAttribute;
import org.openmidaas.library.model.core.InitializationCallback;
import org.openmidaas.library.model.core.MIDaaSException;
import org.openmidaas.library.persistence.AttributeDBPersistence;
import org.openmidaas.library.persistence.AttributePersistenceCoordinator;

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

/**
 * Class that controls device registration
 */
public final class MIDaaS {
    private static String TAG = "MIDaaS";
    private static int currentLoggingLevel = 6;
    public static final int LOG_LEVEL_VERBOSE = 2;
    public static final int LOG_LEVEL_DEBUG = 3;
    public static final int LOG_LEVEL_INFO = 4;
    public static final int LOG_LEVEL_WARN = 5;
    public static final int LOG_LEVEL_ERROR = 6;
    private static final Object LOG_LOCK = new Object();
    private static Context mContext;

    /**
     * Returns the current logging level.
     * @return
     */
    public static int getLoggingLevel() {
        return currentLoggingLevel;
    }

    public static void setContext(Context context) {
        mContext = context;
    }

    /**
     * Set's the logging level of the library. 
     * Default is 6 - logs only errors. 
     * @param level
     */
    public static void setLoggingLevel(int level) {
        synchronized (LOG_LOCK) {
            currentLoggingLevel = level;
        }
    }

    /**
     * Returns the set context. 
     * @return -  the set context
     */
    public static Context getContext() {
        return mContext;
    }

    /**
     * This methods initializes the library. It first checks to see if the 
     * device is already registered. If it is, it calls the onSuccess()
     * method. Otherwise, it tries to register the device with the server and calls
     * onSuccess() or onError() accordingly. 
     * @param context - the Android context. 
     * @param attributeServerUrl - the attribute server that verifies and releases attributes. If null, the 
     * default server is used. This is defined in the Constants.java file. 
     * @param initCallback - the Initialization callback. 
     * @throws URISyntaxException 
     */
    public static void initialize(final Context context, final String attributeServerUrl,
            final InitializationCallback initCallback) throws URISyntaxException {
        if (context == null) {
            MIDaaS.logError(TAG, "context is null");
            throw new IllegalArgumentException("Context cannot be null");
        }
        if (initCallback == null) {
            MIDaaS.logError(TAG, "initialization callback is null");
            throw new IllegalArgumentException("InitializationCallback cannot be null");
        }
        mContext = context.getApplicationContext();
        /* *** initialization routines *** */
        logDebug(TAG, "Initializing library");
        if (attributeServerUrl == null || attributeServerUrl.isEmpty()) {
            ConnectionManager.setNetworkFactory(new AndroidNetworkFactory(Constants.AVP_SB_BASE_URL));
        } else {
            URI uri = new URI(attributeServerUrl);
            // check to see if we have a complete URL
            if (uri.isAbsolute()) {
                // since we're using the URI class, check that the scheme is http or https. 
                if (uri.getScheme().equals("http") || uri.getScheme().equals("https")) {
                    ConnectionManager.setNetworkFactory(new AndroidNetworkFactory(attributeServerUrl));
                } else {
                    MIDaaS.logError(TAG, "Unknown URI scheme: " + uri.getScheme());
                    throw new URISyntaxException(attributeServerUrl, "Unknown URI scheme: " + uri.getScheme());
                }
            } else {
                MIDaaS.logError(TAG, "URI appears to be incomplete: " + attributeServerUrl);
                throw new URISyntaxException(attributeServerUrl,
                        "URI appears to be incomplete: " + attributeServerUrl);
            }
        }
        // we will use a SQLITE database to persist attributes. 
        AttributePersistenceCoordinator.setPersistenceDelegate(new AttributeDBPersistence());
        // set the authentication strategy to level0 device authentication 
        AuthenticationManager.getInstance().setDeviceAuthenticationStrategy(new SKDeviceAuthentication());
        // we will use our access token strategy that depends on level 0 device authentication
        AuthenticationManager.getInstance().setAccessTokenStrategy(new AVSAccessTokenStrategy());
        logDebug(TAG, "Checking to see if device is registered.");
        WorkQueueManager.getInstance().addWorkerToQueue(new WorkQueueManager.Worker() {
            @Override
            public void execute() {
                DeviceRegistrar.setDeviceRegistrationDelegate(new AVSDeviceRegistration());
                DeviceRegistrar.registerDevice(initCallback);
            }
        });
    }

    private static void log(int logLevel, String tag, String message, Throwable throwable) {
        if (logLevel >= currentLoggingLevel) {
            if (throwable == null) {
                Log.println(logLevel, tag, message);
            } else {
                Log.println(logLevel, tag, (new StringBuilder()).append(message).append("\n")
                        .append(throwable.getMessage()).toString());
            }
        }
    }

    /**
     * Log - information messages
     * @param tag
     * @param message
     */
    public static void logInfo(String tag, String message) {
        logInfo(tag, message, null);
    }

    /**
     * Log - information messages
     * @param tag
     * @param message
     * @param throwable
     */
    public static void logInfo(String tag, String message, Throwable throwable) {
        log(4, tag, message, throwable);
    }

    /**
     * Log - errors
     * @param tag
     * @param message
     */
    public static void logError(String tag, String message) {
        logError(tag, message, null);
    }

    /**
     * Log - errors
     * @param tag
     * @param message
     * @param throwable
     */
    public static void logError(String tag, String message, Throwable throwable) {
        log(6, tag, message, throwable);
    }

    /**
     * Log - warnings
     * @param tag
     * @param message
     */
    public static void logWarn(String tag, String message) {
        logWarn(tag, message, null);
    }

    /**
     * Log - warnings 
     * @param tag
     * @param message
     * @param throwable
     */
    public static void logWarn(String tag, String message, Throwable throwable) {
        log(5, tag, message, throwable);
    }

    /**
     * Log - debug messages
     * @param tag
     * @param message
     */
    public static void logDebug(String tag, String message) {
        logDebug(tag, message, null);
    }

    /**
     * Log - debug messages
     * @param tag
     * @param message
     * @param throwable
     */
    public static void logDebug(String tag, String message, Throwable throwable) {
        log(3, tag, message, throwable);
    }

    /**
     * Log - detailed messages
     * @param tagthis.mStreetAddress
     * @param message
     */
    public static void logVerbose(String tag, String message) {
        logVerbose(tag, message, null);
    }

    /**
     * Log - detailed messages
     * @param tag
     * @param message
     * @param throwable
     */
    public static void logVerbose(String tag, String message, Throwable throwable) {
        log(2, tag, message, throwable);
    }

    /**
     * Returns an attribute bundle signed by the AVS server 
     * for a set of verified attributes.
     * @param clientId the client making the request
     * @param state the sate parameter if present
     * @param attributeBundleMap the attribute map. The key of the map is set as the key in the response
     * object
     * @param callback callback method provides the response once done. 
     * @throws IllegalArgumentException 
     */
    public static void getVerifiedAttributeBundle(final String clientId, final String state,
            final Map<String, AbstractAttribute<?>> attributeBundleMap,
            final VerifiedAttributeBundleCallback callback) throws IllegalArgumentException {
        if (clientId == null || clientId.isEmpty()) {
            throw new IllegalArgumentException("Client ID must be provided");
        }

        WorkQueueManager.getInstance().addWorkerToQueue(new Worker() {

            @Override
            public void execute() {
                AVSServer.bundleVerifiedAttributes(clientId, state, attributeBundleMap, callback);
            }
        });
    }

    /**
     * Returns a locally created attribute bundle in a JWT format. 
     * @param clientId
     * @param state
     * @param attributeBundleMap
     * @return the JWT Base64 encoded or null if something went wrong. 
     * @throws IllegalArgumentException
     */
    public static String getAttributeBundle(String clientId, String state,
            Map<String, AbstractAttribute<?>> attributeBundleMap) throws IllegalArgumentException {
        if (clientId == null) {
            MIDaaS.logError(TAG, "Client ID cannot be null");
            throw new IllegalArgumentException("Client ID cannot be null");
        }
        if (attributeBundleMap == null || attributeBundleMap.size() == 0) {
            MIDaaS.logError(TAG, "Attribute map is either null or empty");
            throw new IllegalArgumentException("Attribute map is either null or empty");
        }
        try {
            JSONObject bundleData = new JSONObject();
            bundleData.put(Constants.AttributeBundleKeys.ISSUER, Constants.APP_ISSUER_ID);
            bundleData.put(Constants.AttributeBundleKeys.AUDIENCE, clientId);
            JSONObject attributes = new JSONObject();
            for (Map.Entry<String, AbstractAttribute<?>> entry : attributeBundleMap.entrySet()) {
                if (entry.getValue() == null) {
                    MIDaaS.logError(TAG, "Key " + entry.getKey() + " has value null");
                    throw new NullPointerException("Key " + entry.getKey() + " has value null");
                } else {
                    Object object = entry.getValue().getResponseTokenValue();
                    if (object instanceof String || object instanceof JSONObject) {
                        attributes.put(entry.getKey(), object);
                    } else {
                        MIDaaS.logError(TAG,
                                "attribute method \"getValueAsJSONSerializableObject()\" is not returning an object of instance String or JSONObject");
                        return null;
                    }
                }
            }
            Date now = new Date();
            bundleData.put(Constants.AttributeBundleKeys.ISSUED_AT, now.getTime() / 1000);
            bundleData.put(Constants.AttributeBundleKeys.ATTRIBUTES, attributes);
            return (getJWS(bundleData.toString()));
        } catch (JSONException e) {
            MIDaaS.logError(TAG, e.getMessage());
            return null;
        } catch (UnsupportedEncodingException e) {
            MIDaaS.logError(TAG, e.getMessage());
            return null;
        }
    }

    private static String getJWS(String body) throws JSONException, UnsupportedEncodingException {
        JSONObject header = new JSONObject();
        header.put("alg", "none");
        return (Base64.encodeToString(header.toString().getBytes("UTF-8"), Base64.NO_PADDING + Base64.NO_WRAP) + "."
                + Base64.encodeToString(body.getBytes("UTF-8"), Base64.NO_PADDING + Base64.NO_WRAP) + ".");
    }

    /**
     * 
     * Callback interface to get the verified attribute bundle
     *
     */
    public static interface VerifiedAttributeBundleCallback {

        /**
         * Called when the verifiedResponse is successfully received
         * from the AVS server.
         * @param verifiedResponse the base-64 encoded response 
         * from the AVS server
        **/
        public void onSuccess(String verifiedResponse);

        /**
         * Called when a error occurs either internally or sent
         * by the server. 
         * @param exception MIDaaSException 
         */
        public void onError(MIDaaSException exception);
    }
}