Skip to content

Commit

Permalink
[Auth](ft): Allow custom object
Browse files Browse the repository at this point in the history
- Allow a custom object in the process, like the
  VaultRequest object
- Allow using another service than s3 in the
  signingKey
  • Loading branch information
alexandre-merle committed Jun 22, 2016
1 parent 6f57d8a commit 3d7a0b9
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 46 deletions.
13 changes: 7 additions & 6 deletions lib/auth/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ auth.setAuthHandler = handler => {
return auth;
};

auth.doAuth = (request, log, cb, awsService, data) => {
auth.doAuth = (request, log, cb, awsService, data, custom) => {
log.debug('running auth checks', { method: 'auth' });
const authHeader = request.headers.authorization;
// Check whether signature is in header
Expand All @@ -31,21 +31,21 @@ auth.doAuth = (request, log, cb, awsService, data) => {
// handle temporary security credentials
if (authHeader.startsWith('AWS ')) {
log.trace('authenticating request with auth v2 using headers');
authV2.headerAuthCheck.check(request, log, cb);
authV2.headerAuthCheck.check(request, log, cb, data, custom);
} else if (authHeader.startsWith('AWS4')) {
log.debug('authenticating request with Auth V4 using headers');
authV4.headerAuthCheck.check(request, log, cb, awsService);
authV4.headerAuthCheck.check(request, log, cb, awsService, custom);
} else {
log.warn('missing authorization security header');
return cb(errors.MissingSecurityHeader);
}
} else if (data.Signature) {
// Check whether signature is in query string
log.trace('authenticating request with auth v2 using query string');
authV2.queryAuthCheck.check(request, log, data, cb);
authV2.queryAuthCheck.check(request, log, data, cb, custom);
} else if (data['X-Amz-Algorithm']) {
log.debug('authenticating request with Auth v4 using query string');
authV4.queryAuthCheck.check(request, log, data, cb);
authV4.queryAuthCheck.check(request, log, data, cb, custom);
} else {
// If no auth information is provided in request, then
// user is part of 'All Users Group' so send back this
Expand Down Expand Up @@ -91,7 +91,8 @@ auth.generateV4Headers =
const stringToSign = constructStringToSignV4(params);
const signingKey = vaultUtilities.calculateSigningKey(secretKeyValue,
region,
scopeDate);
scopeDate,
service);
const signature = crypto.createHmac('sha256', signingKey)
.update(stringToSign).digest('hex');
const authorizationHeader = `${algorithm} Credential=${accessKey}` +
Expand Down
5 changes: 3 additions & 2 deletions lib/auth/in_memory/vaultUtilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ function hashSignature(stringToSign, secretKey, algorithm) {
* @param {string} secretKey - requester's secretKey
* @param {string} region - region included in request
* @param {string} scopeDate - scopeDate included in request
* @param {string} [service] - To specify another service than s3
* @return {string} signingKey - signingKey to calculate signature
*/
function calculateSigningKey(secretKey, region, scopeDate) {
function calculateSigningKey(secretKey, region, scopeDate, service) {
const dateKey = crypto.createHmac('sha256', `AWS4${secretKey}`)
.update(scopeDate).digest('binary');
const dateRegionKey = crypto.createHmac('sha256', dateKey)
.update(region).digest('binary');
const dateRegionServiceKey = crypto.createHmac('sha256', dateRegionKey)
.update('s3').digest('binary');
.update(service || 's3').digest('binary');
const signingKey = crypto.createHmac('sha256', dateRegionServiceKey)
.update('aws4_request').digest('binary');
return signingKey;
Expand Down
6 changes: 3 additions & 3 deletions lib/auth/v2/headerAuthCheck.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ headerAuthCheck.setAuthHandler = handler => {
return headerAuthCheck;
};

headerAuthCheck.check = (request, log, callback) => {
headerAuthCheck.check = (request, log, callback, data, custom) => {
log.trace('running header auth check');
const headers = request.headers;

Expand Down Expand Up @@ -55,7 +55,7 @@ headerAuthCheck.check = (request, log, callback) => {

const signatureFromRequest = authInfo.substring(semicolonIndex + 1).trim();
log.trace('signature from request', { signatureFromRequest });
const stringToSign = constructStringToSign(request, log);
const stringToSign = constructStringToSign(request, data, log);
log.trace('constructed string to sign', { stringToSign });
const algo = algoCheck(signatureFromRequest.length);
log.trace('algo for calculating signature', { algo });
Expand All @@ -68,7 +68,7 @@ headerAuthCheck.check = (request, log, callback) => {
return callback(err);
}
return callback(null, authInfo);
});
}, custom);
};

module.exports = headerAuthCheck;
8 changes: 3 additions & 5 deletions lib/auth/v2/queryAuthCheck.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'; // eslint-disable-line strict

const errors = require('../../../index').errors;
const errors = require('../../errors');

const algoCheck = require('./algoCheck');
const constructStringToSign = require('./constructStringToSign');
Expand All @@ -15,13 +15,12 @@ queryAuthCheck.setAuthHandler = handler => {
return queryAuthCheck;
};

queryAuthCheck.check = (request, log, data, callback) => {
queryAuthCheck.check = (request, log, data, callback, custom) => {
log.trace('running query auth check');
if (request.method === 'POST') {
log.warn('query string auth not supported for post requests');
return callback(errors.NotImplemented);
}

/*
Check whether request has expired or if
expires parameter is more than 15 minutes in the future.
Expand Down Expand Up @@ -61,8 +60,7 @@ queryAuthCheck.check = (request, log, data, callback) => {
return callback(err);
}
return callback(null, authInfo);
}
);
}, custom);
};

module.exports = queryAuthCheck;
5 changes: 3 additions & 2 deletions lib/auth/v4/headerAuthCheck.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ headerAuthCheck.setAuthHandler = handler => {
* @param {object} log - logging object
* @param {function} callback - callback to auth checking function
* @param {string} awsService - either 's3' or 'iam'
* @param {*} custom - Allow custom object
* @return {callback} calls callback
*/
headerAuthCheck.check = (request, log, callback, awsService) => {
headerAuthCheck.check = (request, log, callback, awsService, custom) => {
log.trace('running header auth check');
// authorization header
const authHeader = request.headers.authorization;
Expand Down Expand Up @@ -122,7 +123,7 @@ headerAuthCheck.check = (request, log, callback, awsService) => {
stringToSign,
log,
};
return vault.authenticateV4Request(vaultParams, callback);
return vault.authenticateV4Request(vaultParams, callback, custom);
};

module.exports = headerAuthCheck;
6 changes: 4 additions & 2 deletions lib/auth/v4/queryAuthCheck.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ queryAuthCheck.setAuthHandler = handler => {
* V4 query auth check
* @param {object} request - HTTP request object
* @param {object} log - logging object
* @param {object} data - Contain authentification params (GET or POST data)
* @param {function} callback - callback to auth checking function
* @param {*} custom - Allow a custom data (like vaultRequest in Vault)
* @return {callback} calls callback
*/
queryAuthCheck.check = (request, log, data, callback) => {
queryAuthCheck.check = (request, log, data, callback, custom) => {
const authParams = extractQueryParams(data, log);

if (Object.keys(authParams).length !== 5) {
Expand Down Expand Up @@ -87,7 +89,7 @@ queryAuthCheck.check = (request, log, data, callback) => {
stringToSign,
log,
};
return vault.authenticateV4Request(vaultParams, callback);
return vault.authenticateV4Request(vaultParams, callback, custom);
};

module.exports = queryAuthCheck;
12 changes: 6 additions & 6 deletions tests/unit/auth/v2/errorHandling.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('Error handling in checkAuth', () => {
auth(request, logger, err => {
assert.deepStrictEqual(err, errors.InvalidAccessKeyId);
done();
});
}, 's3', request.query);
});

it('should return an error message if no date header ' +
Expand All @@ -46,7 +46,7 @@ describe('Error handling in checkAuth', () => {
auth(request, logger, err => {
assert.deepStrictEqual(err, errors.MissingSecurityHeader);
done();
});
}, 's3', request.query);
});

it('should return an error message if the Expires ' +
Expand All @@ -67,7 +67,7 @@ describe('Error handling in checkAuth', () => {
auth(request, logger, err => {
assert.deepStrictEqual(err, errors.RequestTimeTooSkewed);
done();
});
}, 's3', request.query);
});

it('should return an error message if ' +
Expand All @@ -92,7 +92,7 @@ describe('Error handling in checkAuth', () => {
auth(request, logger, err => {
assert.deepStrictEqual(err, errors.SignatureDoesNotMatch);
done();
});
}, 's3', request.query);
});

it('should return an error message if the ' +
Expand All @@ -113,7 +113,7 @@ describe('Error handling in checkAuth', () => {
auth(request, logger, err => {
assert.deepStrictEqual(err, errors.SignatureDoesNotMatch);
done();
});
}, 's3', request.query);
});

it('should return an error message if accessKey is empty for' +
Expand All @@ -134,7 +134,7 @@ describe('Error handling in checkAuth', () => {
auth(request, logger, err => {
assert.deepStrictEqual(err, errors.MissingSecurityHeader);
done();
});
}, 's3', request.query);
});
});

4 changes: 2 additions & 2 deletions tests/unit/auth/v2/publicAccess.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('Public Access', () => {
assert.strictEqual(authInfo.getCanonicalID(),
publicAuthInfo.getCanonicalID());
done();
});
}, 's3', request.query);
});

it('should not grant access to a request that contains ' +
Expand All @@ -45,6 +45,6 @@ describe('Public Access', () => {
auth(request, logger, err => {
assert.deepStrictEqual(err, errors.MissingSecurityHeader);
done();
});
}, 's3', request.query);
});
});
6 changes: 3 additions & 3 deletions tests/unit/auth/v2/signature.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('checkAuth reconstruction of signature', () => {
query: {},
};
const secretKey = 'verySecretKey1';
const stringToSign = constructStringToSign(request, log);
const stringToSign = constructStringToSign(request, request.query, log);
const reconstructedSig = hashSignature(stringToSign, secretKey, 'sha1');
assert.strictEqual(reconstructedSig, 'MJNF7AqNapSu32TlBOVkcAxj58c=');
});
Expand All @@ -50,7 +50,7 @@ describe('checkAuth reconstruction of signature', () => {
query: { 'max-keys': '1000', 'prefix': '', 'delimiter': '/' },
};
const secretKey = 'verySecretKey1';
const stringToSign = constructStringToSign(request, log);
const stringToSign = constructStringToSign(request, request.query, log);
const reconstructedSig = hashSignature(stringToSign, secretKey, 'sha1');
assert.strictEqual(reconstructedSig, 'V8g5UJUFmMzruMqUHVT6ZwvUw+M=');
});
Expand All @@ -77,7 +77,7 @@ describe('checkAuth reconstruction of signature', () => {
query: {},
};
const secretKey = 'verySecretKey1';
const stringToSign = constructStringToSign(request, log);
const stringToSign = constructStringToSign(request, request.query, log);
const reconstructedSig = hashSignature(stringToSign, secretKey, 'sha1');
assert.strictEqual(reconstructedSig, 'fWPcicKn7Fhzfje/0pRTifCxL44=');
});
Expand Down
Loading

0 comments on commit 3d7a0b9

Please sign in to comment.