Java tutorial
// // 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(); } }