Compare commits
4 Commits
15958fdfef
...
d0a7d6701d
Author | SHA1 | Date |
---|---|---|
Alexandre Merle | d0a7d6701d | |
Alexandre Merle | 7ef6c17c6b | |
Rahul Padigela | 8ab0e071a9 | |
Nicolas Humbert | 0423cd52c8 |
|
@ -5,11 +5,15 @@ general:
|
||||||
- /^ultron\/.*/ # Ignore ultron/* branches
|
- /^ultron\/.*/ # Ignore ultron/* branches
|
||||||
|
|
||||||
machine:
|
machine:
|
||||||
|
environment:
|
||||||
|
CXX: g++-4.9
|
||||||
node:
|
node:
|
||||||
version: 4.5.0
|
version: 4.5.0
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
pre:
|
override:
|
||||||
|
- rm -rf node_modules
|
||||||
|
- npm install
|
||||||
- sudo pip install yamllint
|
- sudo pip install yamllint
|
||||||
|
|
||||||
test:
|
test:
|
||||||
|
|
|
@ -13,8 +13,8 @@ function check(request, log, data) {
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Check whether request has expired or if
|
Check whether request has expired or if
|
||||||
expires parameter is more than 100000000 milliseconds
|
expires parameter is more than 604800000 milliseconds
|
||||||
(1 day and 4 hours) in the future.
|
(7 days) in the future.
|
||||||
Expires time is provided in seconds so need to
|
Expires time is provided in seconds so need to
|
||||||
multiply by 1000 to obtain
|
multiply by 1000 to obtain
|
||||||
milliseconds to compare to Date.now()
|
milliseconds to compare to Date.now()
|
||||||
|
@ -27,8 +27,8 @@ function check(request, log, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentTime = Date.now();
|
const currentTime = Date.now();
|
||||||
// 100000000 ms (one day and 4 hours).
|
// 604800000 ms (seven days).
|
||||||
if (expirationTime > currentTime + 100000000) {
|
if (expirationTime > currentTime + 604800000) {
|
||||||
log.debug('expires parameter too far in future',
|
log.debug('expires parameter too far in future',
|
||||||
{ expires: request.query.Expires });
|
{ expires: request.query.Expires });
|
||||||
return { err: errors.AccessDenied };
|
return { err: errors.AccessDenied };
|
||||||
|
|
|
@ -32,7 +32,7 @@ function _toHexUTF8(char) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
function awsURIencode(input, encodeSlash) {
|
function awsURIencode(input, encodeSlash, noEncodeStar) {
|
||||||
const encSlash = encodeSlash === undefined ? true : encodeSlash;
|
const encSlash = encodeSlash === undefined ? true : encodeSlash;
|
||||||
let encoded = '';
|
let encoded = '';
|
||||||
for (let i = 0; i < input.length; i++) {
|
for (let i = 0; i < input.length; i++) {
|
||||||
|
@ -47,6 +47,8 @@ function awsURIencode(input, encodeSlash) {
|
||||||
encoded = encoded.concat('%20');
|
encoded = encoded.concat('%20');
|
||||||
} else if (ch === '/') {
|
} else if (ch === '/') {
|
||||||
encoded = encoded.concat(encSlash ? '%2F' : ch);
|
encoded = encoded.concat(encSlash ? '%2F' : ch);
|
||||||
|
} else if (ch === '*') {
|
||||||
|
encoded = encoded.concat(noEncodeStar ? '*' : '%2A');
|
||||||
} else {
|
} else {
|
||||||
encoded = encoded.concat(_toHexUTF8(ch));
|
encoded = encoded.concat(_toHexUTF8(ch));
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,16 @@ function createCanonicalRequest(params) {
|
||||||
payloadChecksum = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b' +
|
payloadChecksum = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b' +
|
||||||
'934ca495991b7852b855';
|
'934ca495991b7852b855';
|
||||||
} else if (pHttpVerb === 'POST') {
|
} else if (pHttpVerb === 'POST') {
|
||||||
|
let notEncodeStar = false;
|
||||||
|
// The java sdk does not encode the '*' parameter to compute the
|
||||||
|
// signature, if the user-agent is recognized, we need to keep
|
||||||
|
// the plain '*' as well.
|
||||||
|
if (/aws-sdk-java\/[0-9.]+/.test(pHeaders['user-agent'])) {
|
||||||
|
notEncodeStar = true;
|
||||||
|
}
|
||||||
let payload = queryString.stringify(pQuery, null, null, {
|
let payload = queryString.stringify(pQuery, null, null, {
|
||||||
encodeURIComponent: awsURIencode,
|
encodeURIComponent: input => awsURIencode(input, false,
|
||||||
|
notEncodeStar),
|
||||||
});
|
});
|
||||||
payload = payload.replace(/%20/g, '+');
|
payload = payload.replace(/%20/g, '+');
|
||||||
payloadChecksum = crypto.createHash('sha256')
|
payloadChecksum = crypto.createHash('sha256')
|
||||||
|
|
|
@ -99,7 +99,8 @@ function extractQueryParams(queryObj, log) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const expiry = Number.parseInt(queryObj['X-Amz-Expires'], 10);
|
const expiry = Number.parseInt(queryObj['X-Amz-Expires'], 10);
|
||||||
if (expiry && (expiry > 0 && expiry < 604801)) {
|
const sevenDays = 604800;
|
||||||
|
if (expiry && (expiry > 0 && expiry <= sevenDays)) {
|
||||||
authParams.expiry = expiry;
|
authParams.expiry = expiry;
|
||||||
} else {
|
} else {
|
||||||
log.warn('invalid expiry', { expiry });
|
log.warn('invalid expiry', { expiry });
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "arsenal",
|
"name": "arsenal",
|
||||||
"version": "1.1.0",
|
"version": "6.4.7",
|
||||||
"description": "Common utilities for the S3 project components",
|
"description": "Common utilities for the S3 project components",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
'use strict'; // eslint-disable-line strict
|
'use strict'; // eslint-disable-line strict
|
||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const awsURIencode =
|
||||||
|
require('../../../../lib/auth/v4/awsURIencode');
|
||||||
const createCanonicalRequest =
|
const createCanonicalRequest =
|
||||||
require('../../../../lib/auth/v4/createCanonicalRequest');
|
require('../../../../lib/auth/v4/createCanonicalRequest');
|
||||||
|
|
||||||
|
@ -45,6 +46,50 @@ describe('createCanonicalRequest function', () => {
|
||||||
assert.strictEqual(actualOutput, expectedOutput);
|
assert.strictEqual(actualOutput, expectedOutput);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const msg = 'S3C-820: aws java sdk should not encode * ' +
|
||||||
|
'character for signature';
|
||||||
|
it(msg, () => {
|
||||||
|
const doc = JSON.stringify({
|
||||||
|
Statement: [{
|
||||||
|
Action: 's3:*',
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
const params = {
|
||||||
|
pHttpVerb: 'POST',
|
||||||
|
pResource: '/',
|
||||||
|
pQuery: {
|
||||||
|
PolicyDocument: doc,
|
||||||
|
},
|
||||||
|
pHeaders: {
|
||||||
|
'host': 'examplebucket.s3.amazonaws.com',
|
||||||
|
'x-amz-date': '20130524T000000Z',
|
||||||
|
'user-agent': 'aws-sdk-java/1.11',
|
||||||
|
'authorization': 'AWS4-HMAC-SHA256 Credential' +
|
||||||
|
'=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/' +
|
||||||
|
's3/aws4_request,SignedHeaders=host;user-agent' +
|
||||||
|
'x-amz-content-sha256;x-amz-date,Signature=' +
|
||||||
|
'f0e8bdb87c964420e857bd35b5d6ed310bd44f' +
|
||||||
|
'0170aba48dd91039c6036bdb41',
|
||||||
|
'x-amz-content-sha256': 'e3b0c44298fc1c149afbf4c' +
|
||||||
|
'8996fb92427ae41e4649b934ca495991b7852b855',
|
||||||
|
},
|
||||||
|
pSignedHeaders: 'host;user-agent;x-amz-content-sha256;x-amz-date',
|
||||||
|
};
|
||||||
|
const expectedOutput = 'POST\n' +
|
||||||
|
'/\n' +
|
||||||
|
`PolicyDocument=${awsURIencode(doc)}\n` +
|
||||||
|
'host:examplebucket.s3.amazonaws.com\n' +
|
||||||
|
'user-agent:aws-sdk-java/1.11\n' +
|
||||||
|
'x-amz-content-sha256:e3b0c44298fc1c149afbf4c' +
|
||||||
|
'8996fb92427ae41e4649b934ca495991b7852b855\n' +
|
||||||
|
'x-amz-date:20130524T000000Z\n\n' +
|
||||||
|
'host;user-agent;x-amz-content-sha256;x-amz-date\n' +
|
||||||
|
'25775fcf6b536b361aadce0c5f1afb46eb945dbdd6c3a7723b18300234a89588';
|
||||||
|
const actualOutput = createCanonicalRequest(params);
|
||||||
|
assert.strictEqual(actualOutput, expectedOutput);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Example taken from: http://docs.aws.amazon.com/AmazonS3/
|
// Example taken from: http://docs.aws.amazon.com/AmazonS3/
|
||||||
// latest/API/sig-v4-header-based-auth.html
|
// latest/API/sig-v4-header-based-auth.html
|
||||||
it('should construct a canonical request in accordance ' +
|
it('should construct a canonical request in accordance ' +
|
||||||
|
|
|
@ -199,4 +199,30 @@ describe('v4 queryAuthCheck', () => {
|
||||||
assert.strictEqual(res.params.version, 4);
|
assert.strictEqual(res.params.version, 4);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should successfully return v4 and no error if X-Amz-Expires param ' +
|
||||||
|
'is 604800 (7 days)', done => {
|
||||||
|
// Freezes time so date created within function will be Feb 8, 2016
|
||||||
|
const clock = lolex.install(1454974984001);
|
||||||
|
const alteredRequest = createAlteredRequest({ 'X-Amz-Expires':
|
||||||
|
604800 }, 'query', request, query);
|
||||||
|
const res = queryAuthCheck(alteredRequest, log, alteredRequest.query);
|
||||||
|
clock.uninstall();
|
||||||
|
assert.deepStrictEqual(res.err, null);
|
||||||
|
assert.strictEqual(res.params.version, 4);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should successfully return v4 and no error if X-Amz-Expires param ' +
|
||||||
|
'is less thant 604800 (7 days)', done => {
|
||||||
|
// Freezes time so date created within function will be Feb 8, 2016
|
||||||
|
const clock = lolex.install(1454974984001);
|
||||||
|
const alteredRequest = createAlteredRequest({ 'X-Amz-Expires':
|
||||||
|
604799 }, 'query', request, query);
|
||||||
|
const res = queryAuthCheck(alteredRequest, log, alteredRequest.query);
|
||||||
|
clock.uninstall();
|
||||||
|
assert.deepStrictEqual(res.err, null);
|
||||||
|
assert.strictEqual(res.params.version, 4);
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue