I’ve created a basic AWS signed request library that should make it easier to interface with AWS services from agents. Check it out!
Also, here’s a wrapper class for the new Kinesis Firehose service that was announced earlier this week (it uses the request class internally):
Both of these libraries are still in beta (as v0.1.0 implies), so please let me know how they’re working for you, and if you have any comments or requests.
Hi. Thanks for this. The AWSRequestV4 library has been very helpful.
Just a heads up there seem to be a couple of errors in the latest AWSRequestV4 code on GitHub. May I suggest the following fixes/changes to the constructor and request function:
function request(method, path, queryString, headers, body, cb) { // CHANGED: 'callback' changed to 'cb' to match http.request request
_updateTimestamps();
// These headers are used in the request signature
headers["Host"] <- _serviceHost;
if(!("Content-Type" in headers)) // ADDED: User may wish to send non-json data
headers["Content-Type"] <- "application/x-amz-json-1.1";
// Add the signature to the headers
local signature = _getSignature(method, path, queryString, headers, body);
headers["Authorization"] <- format("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s",
ALGORITHM, _accessKeyId, _getCredentialScope(), _signedHeaders, signature);
// This header is added *after* the request is signed
headers["X-Amz-Date"] <- _dateTime;
local url = _serviceUrl+path+((queryString=="")?"":("?"+queryString)); // ADDED: Full URL now includes path and queryString not just _serviceUrl
http.request(method, url, headers, body).sendasync(cb); // CHANGED: uses full url not just _serviceUrl
}
Thanks for your suggestions! I’ll update the library soon. If you spot any additional problems or have feature requests, feel free to open an issue on GitHub.
Out of curiosity, what AWS service(s) are you using the library with?
Hey, sorry I didn’t get back to you sooner. Had no internet for a couple of days. Anyway if you still need it, here is an example SQS request.
Note: I used the the code from the AWSRequestV4 Library provided in Gino’s link above however I had to make a couple of changes to the “request” function (marked by comments) in order to get it to work with SQS
`
/************************* AWS HANDLER CLASS ********************************/
/
This class can be used to generate correctly structured requests intended for AWS endpoints,
sign the requests using Amazon’s “Signature Version 4”, and send them. It’s intended to be used
internally by wrapper classes for specific AWS services.
@private
*/
function _getHashedCanonicalRequest(method, path, queryString, headerTable, payload) {
// Format headers according to AWS spec (lowercase, whitespace trimmed, alphabetical order, etc)
// TODO: extra spaces between non-quoted header values should be removed as well
local headerArray = [];
local signedHeaderArray = [];
foreach(key, val in headerTable) {
headerArray.push(key.tolower() + “:” + strip(val) + “
”);
signedHeaderArray.push(key.tolower());
}
headerArray.sort();
signedHeaderArray.sort();
local headers = _strJoin(headerArray, “”);
_signedHeaders = _strJoin(signedHeaderArray, “;”);
// Hash the payload and convert to a lowercase hex string
local payloadHash = _blobToHexString(http.hash.sha256(payload));
// Create the canonical request and return a hex-encoded hash of it
local canonicalRequest = _strJoin([method, path, queryString, headers, _signedHeaders, payloadHash], “
”);
@private
*/
function _deriveSigningKey() {
local kDate = http.hash.hmacsha256(_date, “AWS4” + _secretAccessKey);
local kRegion = http.hash.hmacsha256(_region, kDate);
local kService = http.hash.hmacsha256(_service, kRegion);
local kSigning = http.hash.hmacsha256(“aws4_request”, kService);
return kSigning;
}
/**
Caninicalizes the request and creates the signature
@param {string} method
@param {string} path
@param {string} queryString
@param {array} headers
@param {string} body
@return {string}
@private
*/
function _getSignature(method, path, queryString, headers, body) {
// Get the bits and bobs we need to sign a request
local hashedCanonicalRequest = _getHashedCanonicalRequest(method, path, queryString, headers, body);
local stringToSign = _strJoin([ALGORITHM, _dateTime, _getCredentialScope(), hashedCanonicalRequest], “
”);
local signingKey = _deriveSigningKey();
// Return the signature
return _blobToHexString(http.hash.hmacsha256(stringToSign, signingKey));
}
}
function sendToSqs(msg){
local headers = { [“Content-Type”]= “application/x-www-form-urlencoded” };
local body = “Action=SendMessage&MessageBody=”+((typeof(msg)==“string”)?msg:json.encode(msg));