package com.cloud.sample; import java.io.FileInputStream; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Properties; import java.util.StringTokenizer; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.methods.GetMethod; import com.cloud.utils.encoding.Base64; /** * * Copyright (C) 2011 Citrix Systems, Inc. All rights reserved * * * This software is licensed under the GNU General Public License v3 or later. * * It is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * * This software is licensed under the GNU General Public License v3 or later. * * It is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /** * Sample CloudStack Management User API Executor. * * Prerequisites: - Edit usercloud.properties to include your host, apiUrl, apiKey, and secretKey - Use ./executeUserAPI.sh to * execute this test class * * @author will * */ public class UserCloudAPIExecutor { public static void main(String[] args) { // Host String host = null; // Fully qualified URL with http(s)://host:port String apiUrl = null; // ApiKey and secretKey as given by your CloudStack vendor String apiKey = null; String secretKey = null; try { Properties prop = new Properties(); prop.load(new FileInputStream("usercloud.properties")); // host host = prop.getProperty("host"); if (host == null) { System.out.println("Please specify a valid host in the format of http(s)://:/client/api in your usercloud.properties file."); } // apiUrl apiUrl = prop.getProperty("apiUrl"); if (apiUrl == null) { System.out.println("Please specify a valid API URL in the format of command=¶m1=¶m2=... in your usercloud.properties file."); } // apiKey apiKey = prop.getProperty("apiKey"); if (apiKey == null) { System.out.println("Please specify your API Key as provided by your CloudStack vendor in your usercloud.properties file."); } // secretKey secretKey = prop.getProperty("secretKey"); if (secretKey == null) { System.out.println("Please specify your secret Key as provided by your CloudStack vendor in your usercloud.properties file."); } if (apiUrl == null || apiKey == null || secretKey == null) { return; } System.out.println("Constructing API call to host = '" + host + "' with API command = '" + apiUrl + "' using apiKey = '" + apiKey + "' and secretKey = '" + secretKey + "'"); // Step 1: Make sure your APIKey is URL encoded String encodedApiKey = URLEncoder.encode(apiKey, "UTF-8"); // Step 2: URL encode each parameter value, then sort the parameters and apiKey in // alphabetical order, and then toLowerCase all the parameters, parameter values and apiKey. // Please note that if any parameters with a '&' as a value will cause this test client to fail since we are using // '&' to delimit // the string List sortedParams = new ArrayList(); sortedParams.add("apikey=" + encodedApiKey.toLowerCase()); StringTokenizer st = new StringTokenizer(apiUrl, "&"); String url = null; boolean first = true; while (st.hasMoreTokens()) { String paramValue = st.nextToken(); String param = paramValue.substring(0, paramValue.indexOf("=")); String value = URLEncoder.encode(paramValue.substring(paramValue.indexOf("=") + 1, paramValue.length()), "UTF-8"); if (first) { url = param + "=" + value; first = false; } else { url = url + "&" + param + "=" + value; } sortedParams.add(param.toLowerCase() + "=" + value.toLowerCase()); } Collections.sort(sortedParams); System.out.println("Sorted Parameters: " + sortedParams); // Step 3: Construct the sorted URL and sign and URL encode the sorted URL with your secret key String sortedUrl = null; first = true; for (String param : sortedParams) { if (first) { sortedUrl = param; first = false; } else { sortedUrl = sortedUrl + "&" + param; } } System.out.println("sorted URL : " + sortedUrl); String encodedSignature = signRequest(sortedUrl, secretKey); // Step 4: Construct the final URL we want to send to the CloudStack Management Server // Final result should look like: // http(s)://://client/api?&apiKey=&signature= String finalUrl = host + "?" + url + "&apiKey=" + apiKey + "&signature=" + encodedSignature; System.out.println("final URL : " + finalUrl); // Step 5: Perform a HTTP GET on this URL to execute the command HttpClient client = new HttpClient(); HttpMethod method = new GetMethod(finalUrl); int responseCode = client.executeMethod(method); if (responseCode == 200) { // SUCCESS! System.out.println("Successfully executed command"); } else { // FAILED! System.out.println("Unable to execute command with response code: " + responseCode); } } catch (Throwable t) { System.out.println(t); } } /** * 1. Signs a string with a secret key using SHA-1 2. Base64 encode the result 3. URL encode the final result * * @param request * @param key * @return */ public static String signRequest(String request, String key) { try { Mac mac = Mac.getInstance("HmacSHA1"); SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "HmacSHA1"); mac.init(keySpec); mac.update(request.getBytes()); byte[] encryptedBytes = mac.doFinal(); return URLEncoder.encode(Base64.encodeBytes(encryptedBytes), "UTF-8"); } catch (Exception ex) { System.out.println(ex); } return null; } }