// Copyright 2012 Citrix Systems, Inc. Licensed under the // Apache License, Version 2.0 (the "License"); you may not use this // file except in compliance with the License. Citrix Systems, Inc. // reserves all rights not expressly granted by 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. // // Automatically generated by addcopyright.py at 04/03/2012 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; /** * * * * * * * * * */ /** * 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<String> sortedParams = new ArrayList<String>(); 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; } }