com.proctorcam.proctorserv.HashedAuthenticator.java Source code

Java tutorial

Introduction

Here is the source code for com.proctorcam.proctorserv.HashedAuthenticator.java

Source

//
//  HashedAuthenticator.java
//  ProctorservApi
//
//  Copyright 2013 ProctorCam, 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.
//
//  Created by John Tabone on 6/6/13.
//

package com.proctorcam.proctorserv;

//Standard Java lib
import java.util.*;
import java.lang.reflect.Array;

import java.lang.*;
import java.security.*;
import java.io.UnsupportedEncodingException;

//Apache lib
import org.apache.commons.codec.binary.Hex;

public class HashedAuthenticator {
    /**  
     *  applyReverseGuidAndSign adds the signature (String), guid (String), and customer_id (String) 
     *  key-value pairs to options (HashMap) as measures used for authentication. 
     *
     *  A random GUID is generated and added to options along with the provided customer_identifier 
     *  (String). query (String) is generated using the key-value pairs in params and the provided 
     *  shared_secret (String) is appended to query. signature (String) is created using the SHA-256
     *  hashing algorithm on query and is added to params. Finally, the GUID value in options is 
     *  reversed. 
     *
     *  An authenticated params (HashMap) is returned and is sent to the request methods defined in
     *  RestRequestClient.java
     */

    // Determines if params value type is an hash
    public static boolean is_hashmap(Object value) {
        return value instanceof HashMap;
    }

    // Determines if params value type is an array
    public static boolean is_array(Object value) {
        return value.getClass().isArray();
    }

    public static HashMap<String, Object> applyReverseGuidAndSign(HashMap<String, Object> params,
            String customer_identifier, String shared_secret) {
        //Create random GUID
        SecureRandom secRandom = null;
        try {
            secRandom = SecureRandom.getInstance("SHA1PRNG");
        } catch (NoSuchAlgorithmException ex) {
            System.err.println(ex.getMessage());
        }
        String guid = new Integer(secRandom.nextInt()).toString();
        params.put("customer_id", customer_identifier);
        params.put("guid", guid);
        params.put("signature", "");

        //Create query string using key-value pairs in params and
        //appending shared_secret
        StringBuilder query = new StringBuilder();

        for (String key : params.keySet()) {
            if (key != "signature") {
                Object data = params.get(key);

                if (is_hashmap(data)) {
                    HashMap<String, Object> map = (HashMap<String, Object>) data;
                    String hashMapQuery = hashQuery(key, map);
                    query.append(hashMapQuery);

                } else if (is_array(data)) {
                    Object[] array = getArray(data);
                    String arrayString = arrayQuery(key, array);
                    query.append(arrayString);

                } else {
                    query.append(key).append("=").append(data).append("&");
                }
            }
        }

        //Deletes trailing & from query and append shared_secret
        query.deleteCharAt(query.length() - 1);
        query.append(shared_secret);
        String signature = buildSig(query);

        //Add signature to params
        params.put("signature", signature);

        //Reverse guid in params
        String reverseGUID = new StringBuilder(guid).reverse().toString();
        params.put("guid", reverseGUID);

        return params;
    }

    /**  
     *  buildSig takes query(StringBuilder) as a parameter. After hashing query
     *  in Hex, the resulting signature (String) is returned.
     */

    protected static String buildSig(StringBuilder query) {

        MessageDigest sha = null;
        try {
            sha = MessageDigest.getInstance("SHA-256");
        } catch (NoSuchAlgorithmException ex) {
            System.err.println(ex.getMessage());
        }

        byte[] hash = null;
        try {
            hash = sha.digest((query.toString()).getBytes("UTF-8"));
        } catch (UnsupportedEncodingException ex) {
            System.err.println(ex.getMessage());
        }

        return new Hex().encodeHexString(hash);

    }

    // When a request comes in we do not know if the array
    // sent will be a primitive array or object array. Since
    // Object arrays are easier to work with (cannot cast primitive arrays to object arrays)
    // we "convert" every array into a object array with this method
    //
    protected static Object[] getArray(Object arr) {
        // Does not convert if not necessary
        if (arr instanceof Object[])
            return (Object[]) arr;

        int arrlength = Array.getLength(arr);
        Object[] outputArray = new Object[arrlength];
        for (int i = 0; i < arrlength; ++i) {
            outputArray[i] = Array.get(arr, i);
        }
        return outputArray;
    }

    // create a query string if the request params 
    // contain a one dimensional HashMap
    // example: HashMap<String,String> params = "name" => {"first_name" => "Joe", "last_name" => "Smith" }
    // result: "name[first_name]=Joe&name[last_name]=Smith"
    //
    protected static String hashQuery(String key, HashMap<String, Object> valueHash) {
        StringBuilder query = new StringBuilder();
        for (String k : valueHash.keySet()) {
            String v = String.valueOf(valueHash.get(k));
            query.append(String.format("%s[%s]=%s&", key, k, v));
        }
        return query.toString();
    }

    // create a query string if the request params 
    // contatins a one dimensional array
    // example: params = "ids" => int[] {1,2,3} )
    // result: "ids[]=1&ids[]=2&ids[]=3"
    protected static String arrayQuery(Object key, Object[] array) {
        StringBuilder query = new StringBuilder();
        for (Object s : array) {
            String arrayValue = s.toString();
            query.append(String.format("%s[]=%s&", key, arrayValue));
        }
        return query.toString();
    }

}