To send HTTP request to CloudStack API endpoint, you need to implement a little bit comlicated authentication system. http://docs.cloudstack.apache.org/en/latest/dev.html Following is the format of URL to send HTTP Request.
Base URL+API Path+Command String + Signature
where, Base URL is http://cloudstacl_ip:8080 API Path is /client/api? Command String: command, its parameters, in addition, API_Key which is like "miVr6X7u6bN_sdahOBpjNejPgEsT35eXqjB8CG20YI3yaxXcgpyuaIRmFI_EJTVwZ0nUkkJbPmY3y2bciKwFQ" that identifies the account. You can find it at CloudStack Management GUI. and Signature is a hashed and encoded string generated by HMAC SHA-1 hashing with "Secret Key" and Base64 Encoding. You can find "Secret Key" at Management GUI as well.
What comlicating part is that you need to generate "Signature". To generate signature, you need to follow the steps. First, lower case the entire Command String and sort it alphabetically. Second, combine all the key-value pairs with '&'. Finally, hash the combined string using HMAC SHA-1 with Secret Key and encode by Base64.
There is a tutorial for signature generation in the document, however, it is written in python. So I neeed to write code for the signature generation process by myself. The following codes are what I implemented for this authentication to connect to CloudStack REST API.
val signature_map = Map[String, String]()
signature_map += "command" -> command
signature_map += "response" -> response_type
signature_map += "apikey" -> apikey
where, command = "listUsers" and response_type = "json".
val alphabetically_sorted_signature_map = ListMap(signature_map.toSeq.sortWith(_._1 < _._1): _*)
var combined_http_parameter_string = ""
alphabetically_sorted_signature_map.foreach { case (key, value) =>
if (combined_http_parameter_string != "") {
combined_http_parameter_string = combined_http_parameter_string.concat("&")
}
combined_http_parameter_string = combined_http_parameter_string.concat(key)
combined_http_parameter_string = combined_http_parameter_string.concat("=")
combined_http_parameter_string = combined_http_parameter_string.concat(value)
}
val http_request_string = combined_http_parameter_string
val cloudstack_signature = getHmacSha1_hashing_and_base64_encoding(secretkey, combined_http_parameter_string.toLowerCase)
At the bottom of the code, you pass Secret Key and lowercased and combined Command String to getHmacSha1_hashing_and_base64_encoding() function.
Passing Secret Key and Combined Command String, the below function returns Signature through HMAC SHA-1 Hashing and Base64 Encoding.
def getHmacSha1_hashing_and_base64_encoding(secretkey: String, input: String) = {
//HMAC SHA-1 hashing
val signingKey = new SecretKeySpec(secretkey.getBytes, "HmacSHA1")
val mac = Mac.getInstance("HmacSHA1")
mac.init(signingKey)
var result: Array[Byte] = mac.doFinal(input.getBytes)
//Base64 Encoding
Base64.getEncoder.encodeToString(result)