Skip to content

Commit

Permalink
Merge pull request #2036 from simov/fix-aws-sign4
Browse files Browse the repository at this point in the history
Add AWS Signature Version 4
  • Loading branch information
simov committed Jan 27, 2016
2 parents 29d8181 + a5101c5 commit d9906af
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 38 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -754,7 +754,7 @@ The first argument can be either a `url` or an `options` object. The only requir
- `auth` - A hash containing values `user` || `username`, `pass` || `password`, and `sendImmediately` (optional). See documentation above.
- `oauth` - Options for OAuth HMAC-SHA1 signing. See documentation above.
- `hawk` - Options for [Hawk signing](https://github.com/hueniverse/hawk). The `credentials` key must contain the necessary signing info, [see hawk docs for details](https://github.com/hueniverse/hawk#usage-example).
- `aws` - `object` containing AWS signing information. Should have the properties `key`, `secret`. Also requires the property `bucket`, unless you’re specifying your `bucket` as part of the path, or the request doesn’t use a bucket (i.e. GET Services)
- `aws` - `object` containing AWS signing information. Should have the properties `key`, `secret`. Also requires the property `bucket`, unless you’re specifying your `bucket` as part of the path, or the request doesn’t use a bucket (i.e. GET Services). If you want to use AWS sign version 4 use the parameter `sign_version` with value `4` otherwise the default is version 2. **Note:** you need to `npm install aws4` first.
- `httpSignature` - Options for the [HTTP Signature Scheme](https://github.com/joyent/node-http-signature/blob/master/http_signing.md) using [Joyent's library](https://github.com/joyent/node-http-signature). The `keyId` and `key` properties must be specified. See the docs for other options.

---
Expand Down
29 changes: 15 additions & 14 deletions package.json
Expand Up @@ -22,26 +22,26 @@
},
"main": "index.js",
"dependencies": {
"aws-sign2": "~0.6.0",
"bl": "~1.0.0",
"caseless": "~0.11.0",
"combined-stream": "~1.0.5",
"extend": "~3.0.0",
"forever-agent": "~0.6.1",
"form-data": "~1.0.0-rc3",
"har-validator": "~2.0.6",
"hawk": "~3.1.0",
"http-signature": "~1.1.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.7",
"node-uuid": "~1.4.7",
"qs": "~6.0.2",
"tunnel-agent": "~0.4.1",
"tough-cookie": "~2.2.0",
"http-signature": "~1.1.0",
"oauth-sign": "~0.8.0",
"hawk": "~3.1.0",
"aws-sign2": "~0.6.0",
"qs": "~6.0.2",
"stringstream": "~0.0.4",
"combined-stream": "~1.0.5",
"isstream": "~0.1.2",
"is-typedarray": "~1.0.0",
"har-validator": "~2.0.6"
"tough-cookie": "~2.2.0",
"tunnel-agent": "~0.4.1"
},
"scripts": {
"test": "npm run lint && npm run test-ci && npm run test-browser",
Expand All @@ -51,24 +51,25 @@
"lint": "eslint lib/ *.js tests/ && echo Lint passed."
},
"devDependencies": {
"browserify-istanbul": "^0.1.5",
"aws4": "^1.2.1",
"bluebird": "^3.0.2",
"browserify": "^13.0.0",
"browserify-istanbul": "^0.1.5",
"buffer-equal": "^1.0.0",
"codecov.io": "^0.1.6",
"coveralls": "^2.11.4",
"eslint": "1.10.3",
"function-bind": "^1.0.2",
"istanbul": "^0.4.0",
"karma-browserify": "^4.4.0",
"karma": "^0.13.10",
"karma-browserify": "^4.4.0",
"karma-cli": "^0.1.1",
"karma-coverage": "^0.5.3",
"karma-phantomjs-launcher": "^0.1.4",
"karma-tap": "^1.0.3",
"rimraf": "^2.2.8",
"server-destroy": "^1.0.1",
"tape": "^4.2.0",
"taper": "^0.4.0",
"bluebird": "^3.0.2"
"taper": "^0.4.0"
}
}
69 changes: 46 additions & 23 deletions request.js
Expand Up @@ -8,7 +8,7 @@ var http = require('http')
, zlib = require('zlib')
, bl = require('bl')
, hawk = require('hawk')
, aws = require('aws-sign2')
, aws2 = require('aws-sign2')
, httpSignature = require('http-signature')
, mime = require('mime-types')
, stringstream = require('stringstream')
Expand Down Expand Up @@ -1229,29 +1229,52 @@ Request.prototype.aws = function (opts, now) {
self._aws = opts
return self
}
var date = new Date()
self.setHeader('date', date.toUTCString())
var auth =
{ key: opts.key
, secret: opts.secret
, verb: self.method.toUpperCase()
, date: date
, contentType: self.getHeader('content-type') || ''
, md5: self.getHeader('content-md5') || ''
, amazonHeaders: aws.canonicalizeHeaders(self.headers)

if (opts.sign_version == 4 || opts.sign_version == '4') {
var aws4 = require('aws4')
// use aws4
var options = {
host: self.uri.host,
path: self.uri.path,
method: self.method,
headers: {
'content-type': self.getHeader('content-type') || ''
},
body: self.body
}
var path = self.uri.path
if (opts.bucket && path) {
auth.resource = '/' + opts.bucket + path
} else if (opts.bucket && !path) {
auth.resource = '/' + opts.bucket
} else if (!opts.bucket && path) {
auth.resource = path
} else if (!opts.bucket && !path) {
auth.resource = '/'
}
auth.resource = aws.canonicalizeResource(auth.resource)
self.setHeader('authorization', aws.authorization(auth))
var signRes = aws4.sign(options, {
accessKeyId: opts.key,
secretAccessKey: opts.secret
})
self.setHeader('authorization', signRes.headers.Authorization)
self.setHeader('x-amz-date', signRes.headers['X-Amz-Date'])
}
else {
// default: use aws-sign2
var date = new Date()
self.setHeader('date', date.toUTCString())
var auth =
{ key: opts.key
, secret: opts.secret
, verb: self.method.toUpperCase()
, date: date
, contentType: self.getHeader('content-type') || ''
, md5: self.getHeader('content-md5') || ''
, amazonHeaders: aws2.canonicalizeHeaders(self.headers)
}
var path = self.uri.path
if (opts.bucket && path) {
auth.resource = '/' + opts.bucket + path
} else if (opts.bucket && !path) {
auth.resource = '/' + opts.bucket
} else if (!opts.bucket && path) {
auth.resource = path
} else if (!opts.bucket && !path) {
auth.resource = '/'
}
auth.resource = aws2.canonicalizeResource(auth.resource)
self.setHeader('authorization', aws2.authorization(auth))
}

return self
}
Expand Down
61 changes: 61 additions & 0 deletions tests/test-aws.js
@@ -0,0 +1,61 @@
'use strict'

var request = require('../index')
, server = require('./server')
, tape = require('tape')

var s = server.createServer()

var path = '/aws.json'

s.on(path, function(req, res) {
res.writeHead(200, {
'Content-Type': 'application/json'
})
res.end(JSON.stringify(req.headers))
})

tape('setup', function(t) {
s.listen(s.port, function() {
t.end()
})
})

tape('default behaviour: aws-sign2 without sign_version key', function(t) {
var options = {
url: s.url + path,
aws: {
key: 'my_key',
secret: 'my_secret'
},
json: true
}
request(options, function(err, res, body) {
t.ok(body.authorization)
t.notOk(body['x-amz-date'])
t.end()
})
})

tape('aws-sign4 options', function(t) {
var options = {
url: s.url + path,
aws: {
key: 'my_key',
secret: 'my_secret',
sign_version: 4
},
json: true
}
request(options, function(err, res, body) {
t.ok(body.authorization)
t.ok(body['x-amz-date'])
t.end()
})
})

tape('cleanup', function(t) {
s.close(function() {
t.end()
})
})

0 comments on commit d9906af

Please sign in to comment.