package com.appdynamics.monitors.azure.authenticator; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; /** * Taken from microsoft azure api */ public class CanonicalizedResource { public static String getCanonicalizedResource(final java.net.URL address, String accountName) { // Resource path final StringBuilder resourcepath = new StringBuilder("/"); resourcepath.append(accountName); // Note that AbsolutePath starts with a '/'. resourcepath.append(address.getPath()); final StringBuilder canonicalizedResource = new StringBuilder(resourcepath.toString()); // query parameters final Map<String, String[]> queryVariables = parseQueryString(address.getQuery()); final Map<String, String> lowercasedKeyNameValue = new HashMap<String, String>(); for (final Map.Entry<String, String[]> entry : queryVariables.entrySet()) { // sort the value and organize it as comma separated values final List<String> sortedValues = Arrays.asList(entry.getValue()); Collections.sort(sortedValues); final StringBuilder stringValue = new StringBuilder(); for (final String value : sortedValues) { if (stringValue.length() > 0) { stringValue.append(","); } stringValue.append(value); } // key turns out to be null for ?a&b&c&d lowercasedKeyNameValue.put(entry.getKey() == null ? null : entry.getKey().toLowerCase(Locale.US), stringValue.toString()); } final ArrayList<String> sortedKeys = new ArrayList<String>(lowercasedKeyNameValue.keySet()); Collections.sort(sortedKeys); for (final String key : sortedKeys) { final StringBuilder queryParamString = new StringBuilder(); queryParamString.append(key); queryParamString.append(":"); queryParamString.append(lowercasedKeyNameValue.get(key)); appendCanonicalizedElement(canonicalizedResource, queryParamString.toString()); } return canonicalizedResource.toString(); } protected static void appendCanonicalizedElement(final StringBuilder builder, final String element) { builder.append("\n"); builder.append(element); } public static boolean isNullOrEmpty(final String value) { return value == null || value.length() == 0; } public static HashMap<String, String[]> parseQueryString(String parseString) { final HashMap<String, String[]> retVals = new HashMap<String, String[]>(); if (isNullOrEmpty(parseString)) { return retVals; } // 1. Remove ? if present final int queryDex = parseString.indexOf("?"); if (queryDex >= 0 && parseString.length() > 0) { parseString = parseString.substring(queryDex + 1); } // 2. split name value pairs by splitting on the 'c&' character final String[] valuePairs = parseString.contains("&") ? parseString.split("&") : parseString.split(";"); // 3. for each field value pair parse into appropriate map entries for (int m = 0; m < valuePairs.length; m++) { final int equalDex = valuePairs[m].indexOf("="); if (equalDex < 0 || equalDex == valuePairs[m].length() - 1) { continue; } String key = valuePairs[m].substring(0, equalDex); String value = valuePairs[m].substring(equalDex + 1); key = safeDecode(key); value = safeDecode(value); // 3.1 add to map String[] values = retVals.get(key); if (values == null) { values = new String[] { value }; if (!value.equals("")) { retVals.put(key, values); } } else if (!value.equals("")) { final String[] newValues = new String[values.length + 1]; for (int j = 0; j < values.length; j++) { newValues[j] = values[j]; } newValues[newValues.length] = value; } } return retVals; } public static String safeDecode(final String stringToDecode) { if (stringToDecode == null) { return null; } if (stringToDecode.length() == 0) { return ""; } try { if (stringToDecode.contains("+")) { final StringBuilder outBuilder = new StringBuilder(); int startDex = 0; for (int m = 0; m < stringToDecode.length(); m++) { if (stringToDecode.charAt(m) == '+') { if (m > startDex) { outBuilder.append(URLDecoder.decode(stringToDecode.substring(startDex, m), "UTF-8")); } outBuilder.append("+"); startDex = m + 1; } } if (startDex != stringToDecode.length()) { outBuilder.append(URLDecoder.decode(stringToDecode.substring(startDex, stringToDecode.length()), "UTF-8")); } return outBuilder.toString(); } else { return URLDecoder.decode(stringToDecode, "UTF-8"); } } catch (final UnsupportedEncodingException e) { throw new RuntimeException(e); } } }