From 21ae41c96bf6f2de018d3e78198a37d0410a2d32 Mon Sep 17 00:00:00 2001 From: Reason Date: Wed, 16 Apr 2014 11:51:22 -0500 Subject: [PATCH] Fix issues with incorrect variable assignment of key, secret, and token obtained from Instance Metadata. --- lib/aws.js | 159 ++++++++++++++++++++++++++++------------------------- 1 file changed, 85 insertions(+), 74 deletions(-) diff --git a/lib/aws.js b/lib/aws.js index ee28416..724e2df 100644 --- a/lib/aws.js +++ b/lib/aws.js @@ -38,130 +38,141 @@ exports.createCFNClient = cfn.init(genericAWSClient); exports.createEMRClient = emr.init(genericAWSClient); exports.createMetaDataClient = metadata.init(); -// a generic AWS API Client which handles the general parts -function genericAWSClient(obj) { - var securityToken = obj.token; +// A generic AWS API Client which handles the general parts. +function genericAWSClient (obj) { var signHeader = obj.signHeader; var host = obj.host; - var accessKeyId = obj.accessKeyId; var path = obj.path; var agent = obj.agent; - var secretAccessKey = obj.secretAccessKey; - var secure = obj.secure == null ? true : false; + // Default true. + var secure = obj.secure !== false; var connection = secure ? https : http; - return {call: call}; + return { call : call }; - function call(action, query, callback) { + function call (action, query, callback) { // Wrap the callback to prevent it from being called multiple times. - callback = (function(next) { + callback = (function (next) { var isCalled = false; - return function() { - if (isCalled) return; + return function () { + if (isCalled) { + return; + } isCalled = true; next.apply(null, arguments); + }; + })(callback); + + // Try to set credentials with metadata API if no credentials provided. + // This will add the credentials to obj. + metadata.readCredentials(obj, function (err) { + if (err) { + return callback(err); } - })(callback) - - // Try to set credentials with metadata API if no credentials provided - metadata.readCredentials(obj, function(err) { - if (err) return callback(err); var date = new Date(); - query = addQueryProperties(query, securityToken, accessKeyId, date); + query = addQueryProperties(query, obj.token, obj.accessKeyId, obj.secretAccessKey, date); var body = qs.stringify(query); - var headers = createHeaders(host, body.length, date, securityToken, accessKeyId, secretAccessKey); + var headers = createHeaders(host, body.length, date, obj.token, obj.accessKeyId, obj.secretAccessKey); sendRequest(); return; - function sendRequest() { + function sendRequest () { var options = { - host: host, - path: path, - agent: agent, - method: 'POST', - headers: headers + host : host, + path : path, + agent : agent, + method : 'POST', + headers : headers }; var req = connection.request(options, function (res) { var data = ''; - //the listener that handles the response chunks + // The listener that handles the response chunks. res.addListener('data', function (chunk) { - data += chunk.toString() - }) - res.addListener('end', function() { + data += chunk.toString(); + }); + res.addListener('end', function () { var parser = new xml2js.Parser(); - parser.addListener('end', function(result) { - if (typeof result != "undefined") { - var err = result.Error || (result.Errors ? result.Errors.Error : null) + parser.addListener('end', function (result) { + if (result !== undefined) { + var err = result.Error || (result.Errors ? result.Errors.Error : null); if (err) { - callback(new Error(err.Message), result) - } else { - callback(null, result) + callback(new Error(err.Message), result); } - } else { - callback(new Error('Unable to parse XML from AWS.')) + else { + callback(null, result); + } + } + else { + callback(new Error('Unable to parse XML from AWS.')); } }); parser.parseString(data); - }) - res.addListener('error', callback) + }); + res.addListener('error', callback); }); - req.write(body) - req.addListener('error', callback) - req.end() + req.write(body); + req.addListener('error', callback); + req.end(); } }); } - function addQueryProperties(query, securityToken, accessKeyId, date) { + function addQueryProperties (query, securityToken, accessKeyId, secretAccessKey, date) { var extendedQuery = _.clone(query); - if (securityToken) extendedQuery["SecurityToken"] = securityToken; - extendedQuery["Timestamp"] = date.toISOString(); - extendedQuery["AWSAccessKeyId"] = accessKeyId; - extendedQuery["Signature"] = signQuery(extendedQuery); + if (securityToken) { + extendedQuery.SecurityToken = securityToken; + } + extendedQuery.Timestamp = date.toISOString(); + extendedQuery.AWSAccessKeyId = accessKeyId; + extendedQuery.Signature = signQuery(extendedQuery, secretAccessKey); return extendedQuery; } - function createHeaders(host, bodyLength, date, securityToken, accessKeyId, secretAccessKey) { + function createHeaders (host, bodyLength, date, securityToken, accessKeyId, secretAccessKey) { var headers = { - "Host": host, - "Content-Type": "application/x-www-form-urlencoded; charset=utf-8", - "Content-Length": bodyLength + 'Host' : host, + 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf-8', + 'Content-Length' : bodyLength }; if (signHeader) { - headers["Date"] = date.toUTCString(); - if (securityToken !== undefined) headers["x-amz-security-token"] = securityToken; - headers["x-amzn-authorization"] = - "AWS3-HTTPS " + - "AWSAccessKeyId=" + accessKeyId + ", " + - "Algorithm=HmacSHA256, " + - "Signature=" + utils.hmacSha256(secretAccessKey, date.toUTCString()); + headers.Date = date.toUTCString(); + if (securityToken !== undefined) { + headers['x-amz-security-token'] = securityToken; + } + headers['x-amzn-authorization'] = + 'AWS3-HTTPS ' + + 'AWSAccessKeyId=' + accessKeyId + ', ' + + 'Algorithm=HmacSHA256, ' + + 'Signature=' + utils.hmacSha256(secretAccessKey, date.toUTCString()); } return headers; } - function signQuery(query) { - var keys = [] - var sorted = {} + function signQuery (query, secretAccessKey) { + var key; + var keys = []; + var sorted = {}; - for(var key in query) - keys.push(key) + for (key in query) { + keys.push(key); + } - keys = keys.sort() + keys = keys.sort(); - for(var n in keys) { - var key = keys[n] - sorted[key] = query[key] + for (var index = 0, length = keys.length; index < length; index++) { + key = keys[index]; + sorted[key] = query[key]; } - var stringToSign = ["POST", host, path, qs.stringify(sorted)].join("\n"); - - // Amazon signature algorithm seems to require this - stringToSign = stringToSign.replace(/!/g,"%21"); - stringToSign = stringToSign.replace(/'/g,"%27"); - stringToSign = stringToSign.replace(/\*/g,"%2A"); - stringToSign = stringToSign.replace(/\(/g,"%28"); - stringToSign = stringToSign.replace(/\)/g,"%29"); + var stringToSign = ['POST', host, path, qs.stringify(sorted)].join('\n'); + + // Amazon signature algorithm seems to require this. + stringToSign = stringToSign.replace(/!/g,'%21'); + stringToSign = stringToSign.replace(/'/g,'%27'); + stringToSign = stringToSign.replace(/\*/g,'%2A'); + stringToSign = stringToSign.replace(/\(/g,'%28'); + stringToSign = stringToSign.replace(/\)/g,'%29'); return utils.hmacSha256(secretAccessKey, stringToSign); }