| 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 <http://www.gnu.org/licenses/>. |
| *
|
| *
|
| * 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<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;
|
| }
|
| }
|