// 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;
}
}