Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
Adds AWS SIG V4 headers to each request that is configured with a 'beforeRequest' handler of 'addAmazonSignatureV4'.

Note that this plugin obtains all AWS configuration from the AWS SDK and as such, that SDK must be initialized before this plug-in is required by Artillery.
  • Loading branch information
gwsii committed Jun 29, 2016
1 parent 430112b commit c82b5ff
Show file tree
Hide file tree
Showing 8 changed files with 280 additions and 4 deletions.
17 changes: 17 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
; EditorConfig is awesome: http://EditorConfig.org

root = true ; top-most EditorConfig file

; Unix-style newlines with a newline ending every file
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

; 4 space indentation
[*.py]
indent_size = 4
indent_style = space
9 changes: 6 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
### Node template
# Logs
logs
*.log
Expand All @@ -14,9 +15,6 @@ lib-cov
# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

Expand All @@ -35,3 +33,8 @@ jspm_packages

# Optional REPL history
.node_repl_history

# Created by .ignore support plugin (hsz.mobi)

# JetBrains
.idea
77 changes: 77 additions & 0 deletions .jscsrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"requireCurlyBraces": [
"if",
"else",
"for",
"while",
"do",
"try",
"catch",
"finally",
"switch"
],
"requireSpaceAfterKeywords": [
"if",
"else",
"for",
"while",
"do",
"switch",
"case",
"return",
"try",
"catch",
"finally",
"in",
"var",
"typeof",
"void"
],
"disallowSpacesInNamedFunctionExpression": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInFunctionDeclaration": {
"beforeOpeningRoundBrace": true
},
"disallowEmptyBlocks": true,
"disallowKeywords": [
"with"
],
"disallowKeywordsOnNewLine": [
"else"
],
"disallowMixedSpacesAndTabs": "smart",
"disallowMultipleLineBreaks": true,
"disallowNewlineBeforeBlockStatements": true,
"disallowPaddingNewlinesInBlocks": true,
"disallowQuotedKeysInObjects": true,
"disallowSpaceAfterObjectKeys": true,
"disallowSpaceAfterPrefixUnaryOperators": true,
"disallowSpaceBeforeBinaryOperators": [
","
],
"disallowSpaceBeforePostfixUnaryOperators": true,
"disallowSpaceBeforeSemicolon": true,
"disallowSpacesInCallExpression": true,
"disallowSpacesInsideArrayBrackets": true,
"disallowSpacesInsideParentheses": true,
"disallowTrailingComma": true,
"disallowTrailingWhitespace": true,
"requireBlocksOnNewline": 1,
"requireCamelCaseOrUpperCaseIdentifiers": "ignoreProperties",
"requireCapitalizedConstructors": true,
"requireCommaBeforeLineBreak": true,
"requireLineFeedAtFileEnd": true,
"requireMultipleVarDecl": "onevar",
"requireParenthesesAroundIIFE": true,
"requireSpaceAfterBinaryOperators": true,
"requireSpaceAfterLineComment": true,
"requireSpaceBeforeBinaryOperators": true,
"requireSpaceBeforeBlockStatements": true,
"requireSpaceBeforeObjectValues": true,
"requireSpacesInConditionalExpression": true,
"requireSpacesInsideObjectBrackets": "all",
"validateIndentation": 4,
"validateParameterSeparator": ", ",
"validateQuoteMarks": "'"
}
20 changes: 20 additions & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"bitwise": true,
"curly": true,
"eqeqeq": true,
"latedef": true,
"noarg": true,
"node": true,
"quotmark": "single",
"smarttabs": true,
"strict": true,
"trailing": true,
"undef": true,
"unused": false,
"mocha": true,
"globals": {
"define": true,
"describe": true,
"it": true
}
}
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,34 @@
# artillery-plugin-aws-sigv4
# artillery-plugin-aws-sigv4
A plugin for artillery.io that signs HTTP requests using the AWS Signature V4 specification.

To use:

1. `npm install -g artillery`
2. `npm install artillery-plugin-aws-sigv4`
3. Add `aws-sigv4` plugin config to your "`hello.json`" Artillery script
```
{
"config": {
"plugins": {
"aws-sigv4": {
"serviceName": "execute-api"
}
}
},
"scenarios": [
{
"beforeRequest": "addAmazonSignatureV4"
}
]
}
```
4. `artillery run hello.json`
This will add an authentication header to every request that conforms to V4 of the AWS Signature Specification.
For more information, see:
* https://github.com/shoreditch-ops/artillery
* http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
Enjoy!
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use strict';

module.exports = require(__dirname + '/lib/aws-sigv4');
91 changes: 91 additions & 0 deletions lib/aws-sigv4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
'use strict';

var aws = require('aws-sdk'),
url = require('url'),
constants = {
PLUGIN_NAME: 'aws-sigv4',
PLUGIN_PARAM_SERVICE_NAME: 'serviceName',
THE: 'The "',
CONFIG_REQUIRED: '" plugin requires configuration under [script].config.plugins.',
PARAM_REQUIRED: '" parameter is required',
PARAM_MUST_BE_STRING: '" param must have a string value',
HEADER_AUTHORIZATION: 'Authorization'
},
messages = {
pluginConfigRequired: constants.THE + constants.PLUGIN_NAME + constants.CONFIG_REQUIRED + constants.PLUGIN_NAME,
pluginParamServiceNameRequired: constants.THE + constants.PLUGIN_PARAM_SERVICE_NAME + constants.PARAM_REQUIRED,
pluginParamServiceNameMustBeString: constants.THE + constants.PLUGIN_PARAM_SERVICE_NAME + constants.PARAM_MUST_BE_STRING
},
impl = {
validateConfig: function(scriptConfig) {
// Validate that plugin config exists
if (!(scriptConfig && scriptConfig.plugins && constants.PLUGIN_NAME in scriptConfig.plugins)) {
throw new Error(messages.pluginConfigRequired);
}
// Validate NAMESPACE
if (!(constants.PLUGIN_PARAM_SERVICE_NAME in scriptConfig.plugins[constants.PLUGIN_NAME])) {
throw new Error(messages.pluginParamServiceNameRequired);
} else if (!('string' === typeof scriptConfig.plugins[constants.PLUGIN_NAME][constants.PLUGIN_PARAM_SERVICE_NAME] ||
scriptConfig.plugins[constants.PLUGIN_NAME][constants.PLUGIN_PARAM_SERVICE_NAME] instanceof String)) {
throw new Error(messages.pluginParamServiceNameMustBeString);
}
},
addAmazonSignatureV4: function(serviceName, requestParams, context, ee, callback) {
var targetUrl = url.parse(requestParams.uri),
credentials = aws.config.credentials,
region = aws.config.region,
end = new aws.Endpoint(targetUrl.hostname),
req = new aws.HttpRequest(end),
signer,
header;

req.method = requestParams.method;
req.path = targetUrl.path;
req.region = region;
req.headers.Host = end.host;

for (header in requestParams.headers) {
req.headers[header] = requestParams.headers[header];
}

if (requestParams.body) {
req.body = requestParams.body;
} else if (requestParams.json) {
req.body = JSON.stringify(requestParams.json);
}

signer = new aws.Signers.V4(req, serviceName);
signer.addAuthorization(credentials, new Date());

for (header in req.headers) {
requestParams.headers[header] = req.headers[header];
}

callback();
}
},
api = {
init: function(scriptConfig, eventEmitter) {
var AwsSigV4Plugin = function(scriptConfig, eventEmitter) {
var serviceName;
impl.validateConfig(scriptConfig);
serviceName = scriptConfig.plugins[constants.PLUGIN_NAME][constants.PLUGIN_PARAM_SERVICE_NAME];
if (!scriptConfig.processor) {
scriptConfig.processor = {};
}
scriptConfig.processor.addAmazonSignatureV4 = function(requestParams, context, ee, callback) {
impl.addAmazonSignatureV4(serviceName, requestParams, context, ee, callback);
};
};
return new AwsSigV4Plugin(scriptConfig, eventEmitter);
}
};

module.exports = api.init;

/* test-code */
module.exports.constants = constants;
module.exports.messages = messages;
module.exports.impl = impl;
module.exports.api = api;
/* end-test-code */
32 changes: 32 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "artillery-plugin-aws-sigv4",
"version": "0.0.1",
"description": "A plugin for artillery.io that add an authentication header to every request that conforms to V4 of the AWS Signature Specification. See https://github.com/shoreditch-ops/artillery. Also see http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/nordstrom/artillery-plugin-aws-sigv4.git"
},
"keywords": [
"artillery",
"aws",
"sigv4",
"plugin"
],
"author": "Greg Smith <[email protected]>",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/nordstrom/artillery-plugin-aws-sigv4/issues"
},
"homepage": "https://github.com/nordstrom/artillery-plugin-aws-sigv4#readme",
"dependencies": {
"aws-sdk": "^2.3.19"
},
"devDependencies": {
"chai": "^3.5.0",
"mocha": "^2.5.3"
}
}

0 comments on commit c82b5ff

Please sign in to comment.