Compare commits

..

No commits in common. "321e449a12dcaef9c0d39586bfa8a41571d7a2cb" and "fe656e511dfc8cae191ec5b2cf3cd23c5e458aaf" have entirely different histories.

36 changed files with 584 additions and 572 deletions

View File

@ -1,14 +1,18 @@
export * as auth from './lib/auth/auth' export const auth = require('./lib/auth/auth');
export * as constants from './lib/constants'; export * as constants from './lib/constants';
export * as https from './lib/https'
export const db = require('./lib/db'); export const db = require('./lib/db');
export const errors = require('./lib/errors.js') export const errors = require('./lib/errors.js');
export const shuffle = require('./lib/shuffle'); export const shuffle = require('./lib/shuffle');
export const stringHash = require('./lib/stringHash'); export const stringHash = require('./lib/stringHash');
export const ipCheck = require('./lib/ipCheck'); export const ipCheck = require('./lib/ipCheck');
export const jsutil = require('./lib/jsutil'); export const jsutil = require('./lib/jsutil');
export const Clustering = require('./lib/Clustering'); export const Clustering = require('./lib/Clustering');
export const https = {
ciphers: require('./lib/https/ciphers.js'),
dhparam: require('./lib/https/dh2048.js'),
};
export const algorithms = { export const algorithms = {
list: { list: {
Basic: require('./lib/algos/list/basic').List, Basic: require('./lib/algos/list/basic').List,

View File

@ -1,4 +1,6 @@
import * as constants from '../constants'; 'use strict'; // eslint-disable-line strict
const constants = require('../constants');
/** /**
* Class containing requester's information received from Vault * Class containing requester's information received from Vault
@ -6,15 +8,9 @@ import * as constants from '../constants';
* shortid, email, accountDisplayName and IAMdisplayName (if applicable) * shortid, email, accountDisplayName and IAMdisplayName (if applicable)
* @return {AuthInfo} an AuthInfo instance * @return {AuthInfo} an AuthInfo instance
*/ */
export default class AuthInfo {
arn: string;
canonicalID: string;
shortid: string;
email: string;
accountDisplayName: string;
IAMdisplayName: string;
constructor(objectFromVault: any) { class AuthInfo {
constructor(objectFromVault) {
// amazon resource name for IAM user (if applicable) // amazon resource name for IAM user (if applicable)
this.arn = objectFromVault.arn; this.arn = objectFromVault.arn;
// account canonicalID // account canonicalID
@ -57,8 +53,10 @@ export default class AuthInfo {
return this.canonicalID.startsWith( return this.canonicalID.startsWith(
`${constants.zenkoServiceAccount}/`); `${constants.zenkoServiceAccount}/`);
} }
isRequesterThisServiceAccount(serviceName: string) { isRequesterThisServiceAccount(serviceName) {
const computedCanonicalID = `${constants.zenkoServiceAccount}/${serviceName}`; return this.canonicalID ===
return this.canonicalID === computedCanonicalID; `${constants.zenkoServiceAccount}/${serviceName}`;
} }
} }
module.exports = AuthInfo;

View File

@ -1,22 +1,16 @@
import { Logger } from 'werelogs'; const errors = require('../errors');
import errors from '../errors'; const AuthInfo = require('./AuthInfo');
import AuthInfo from './AuthInfo';
/** vaultSignatureCb parses message from Vault and instantiates /** vaultSignatureCb parses message from Vault and instantiates
* @param err - error from vault * @param {object} err - error from vault
* @param authInfo - info from vault * @param {object} authInfo - info from vault
* @param log - log for request * @param {object} log - log for request
* @param callback - callback to authCheck functions * @param {function} callback - callback to authCheck functions
* @param [streamingV4Params] - present if v4 signature; * @param {object} [streamingV4Params] - present if v4 signature;
* items used to calculate signature on chunks if streaming auth * items used to calculate signature on chunks if streaming auth
* @return {undefined}
*/ */
function vaultSignatureCb( function vaultSignatureCb(err, authInfo, log, callback, streamingV4Params) {
err: Error | null,
authInfo: { message: { body: any } },
log: Logger,
callback: (err: Error | null, data?: any, results?: any, params?: any) => void,
streamingV4Params?: any
) {
// vaultclient API guarantees that it returns: // vaultclient API guarantees that it returns:
// - either `err`, an Error object with `code` and `message` properties set // - either `err`, an Error object with `code` and `message` properties set
// - or `err == null` and `info` is an object with `message.code` and // - or `err == null` and `info` is an object with `message.code` and
@ -30,13 +24,11 @@ function vaultSignatureCb(
const info = authInfo.message.body; const info = authInfo.message.body;
const userInfo = new AuthInfo(info.userInfo); const userInfo = new AuthInfo(info.userInfo);
const authorizationResults = info.authorizationResults; const authorizationResults = info.authorizationResults;
const auditLog: { accountDisplayName: string, IAMdisplayName?: string } = const auditLog = { accountDisplayName: userInfo.getAccountDisplayName() };
{ accountDisplayName: userInfo.getAccountDisplayName() };
const iamDisplayName = userInfo.getIAMdisplayName(); const iamDisplayName = userInfo.getIAMdisplayName();
if (iamDisplayName) { if (iamDisplayName) {
auditLog.IAMdisplayName = iamDisplayName; auditLog.IAMdisplayName = iamDisplayName;
} }
// @ts-ignore
log.addDefaultFields(auditLog); log.addDefaultFields(auditLog);
return callback(null, userInfo, authorizationResults, streamingV4Params); return callback(null, userInfo, authorizationResults, streamingV4Params);
} }
@ -47,63 +39,43 @@ function vaultSignatureCb(
* authentication backends. * authentication backends.
* @class Vault * @class Vault
*/ */
export default class Vault { class Vault {
client: any;
implName: string;
/** /**
* @constructor * @constructor
* @param {object} client - authentication backend or vault client * @param {object} client - authentication backend or vault client
* @param {string} implName - implementation name for auth backend * @param {string} implName - implementation name for auth backend
*/ */
constructor(client: any, implName: string) { constructor(client, implName) {
this.client = client; this.client = client;
this.implName = implName; this.implName = implName;
} }
/** /**
* authenticateV2Request * authenticateV2Request
* *
* @param params - the authentication parameters as returned by * @param {string} params - the authentication parameters as returned by
* auth.extractParams * auth.extractParams
* @param params.version - shall equal 2 * @param {number} params.version - shall equal 2
* @param params.data.accessKey - the user's accessKey * @param {string} params.data.accessKey - the user's accessKey
* @param params.data.signatureFromRequest - the signature read * @param {string} params.data.signatureFromRequest - the signature read
* from the request * from the request
* @param params.data.stringToSign - the stringToSign * @param {string} params.data.stringToSign - the stringToSign
* @param params.data.algo - the hashing algorithm used for the * @param {string} params.data.algo - the hashing algorithm used for the
* signature * signature
* @param params.data.authType - the type of authentication (query * @param {string} params.data.authType - the type of authentication (query
* or header) * or header)
* @param params.data.signatureVersion - the version of the * @param {string} params.data.signatureVersion - the version of the
* signature (AWS or AWS4) * signature (AWS or AWS4)
* @param [params.data.signatureAge] - the age of the signature in * @param {number} [params.data.signatureAge] - the age of the signature in
* ms * ms
* @param params.data.log - the logger object * @param {string} params.data.log - the logger object
* @param {RequestContext []} requestContexts - an array of RequestContext * @param {RequestContext []} requestContexts - an array of RequestContext
* instances which contain information for policy authorization check * instances which contain information for policy authorization check
* @param callback - callback with either error or user info * @param {function} callback - callback with either error or user info
* @returns {undefined}
*/ */
authenticateV2Request( authenticateV2Request(params, requestContexts, callback) {
params: {
version: 2;
log: Logger;
data: {
securityToken: string;
accessKey: string;
signatureFromRequest: string;
stringToSign: string;
algo: string;
authType: 'query' | 'header';
signatureVersion: string;
signatureAge?: number;
log: Logger;
};
},
requestContexts: any[],
callback: (err: Error | null, data?: any) => void
) {
params.log.debug('authenticating V2 request'); params.log.debug('authenticating V2 request');
let serializedRCsArr: any; let serializedRCsArr;
if (requestContexts) { if (requestContexts) {
serializedRCsArr = requestContexts.map(rc => rc.serialize()); serializedRCsArr = requestContexts.map(rc => rc.serialize());
} }
@ -113,66 +85,44 @@ export default class Vault {
params.data.accessKey, params.data.accessKey,
{ {
algo: params.data.algo, algo: params.data.algo,
// @ts-ignore
reqUid: params.log.getSerializedUids(), reqUid: params.log.getSerializedUids(),
logger: params.log, logger: params.log,
securityToken: params.data.securityToken, securityToken: params.data.securityToken,
requestContext: serializedRCsArr, requestContext: serializedRCsArr,
}, },
(err: Error | null, userInfo?: any) => vaultSignatureCb(err, userInfo, (err, userInfo) => vaultSignatureCb(err, userInfo,
params.log, callback), params.log, callback)
); );
} }
/** authenticateV4Request /** authenticateV4Request
* @param params - the authentication parameters as returned by * @param {object} params - the authentication parameters as returned by
* auth.extractParams * auth.extractParams
* @param params.version - shall equal 4 * @param {number} params.version - shall equal 4
* @param params.data.log - the logger object * @param {string} params.data.log - the logger object
* @param params.data.accessKey - the user's accessKey * @param {string} params.data.accessKey - the user's accessKey
* @param params.data.signatureFromRequest - the signature read * @param {string} params.data.signatureFromRequest - the signature read
* from the request * from the request
* @param params.data.region - the AWS region * @param {string} params.data.region - the AWS region
* @param params.data.stringToSign - the stringToSign * @param {string} params.data.stringToSign - the stringToSign
* @param params.data.scopeDate - the timespan to allow the request * @param {string} params.data.scopeDate - the timespan to allow the request
* @param params.data.authType - the type of authentication (query * @param {string} params.data.authType - the type of authentication (query
* or header) * or header)
* @param params.data.signatureVersion - the version of the * @param {string} params.data.signatureVersion - the version of the
* signature (AWS or AWS4) * signature (AWS or AWS4)
* @param params.data.signatureAge - the age of the signature in ms * @param {number} params.data.signatureAge - the age of the signature in ms
* @param params.data.timestamp - signaure timestamp * @param {number} params.data.timestamp - signaure timestamp
* @param params.credentialScope - credentialScope for signature * @param {string} params.credentialScope - credentialScope for signature
* @param {RequestContext [] | null} requestContexts - * @param {RequestContext [] | null} requestContexts -
* an array of RequestContext or null if authenticaiton of a chunk * an array of RequestContext or null if authenticaiton of a chunk
* in streamingv4 auth * in streamingv4 auth
* instances which contain information for policy authorization check * instances which contain information for policy authorization check
* @param callback - callback with either error or user info * @param {function} callback - callback with either error or user info
* @return {undefined}
*/ */
authenticateV4Request( authenticateV4Request(params, requestContexts, callback) {
params: {
version: 4;
log: Logger;
data: {
accessKey: string;
signatureFromRequest: string;
region: string;
stringToSign: string;
scopeDate: string;
authType: 'query' | 'header';
signatureVersion: string;
signatureAge?: number;
timestamp: number;
credentialScope: string;
securityToken: string;
algo: string;
log: Logger;
};
},
requestContexts: any[],
callback: (err: Error | null, data?: any) => void
) {
params.log.debug('authenticating V4 request'); params.log.debug('authenticating V4 request');
let serializedRCs: any; let serializedRCs;
if (requestContexts) { if (requestContexts) {
serializedRCs = requestContexts.map(rc => rc.serialize()); serializedRCs = requestContexts.map(rc => rc.serialize());
} }
@ -190,39 +140,31 @@ export default class Vault {
params.data.region, params.data.region,
params.data.scopeDate, params.data.scopeDate,
{ {
// @ts-ignore
reqUid: params.log.getSerializedUids(), reqUid: params.log.getSerializedUids(),
logger: params.log, logger: params.log,
securityToken: params.data.securityToken, securityToken: params.data.securityToken,
requestContext: serializedRCs, requestContext: serializedRCs,
}, },
(err: Error | null, userInfo?: any) => vaultSignatureCb(err, userInfo, (err, userInfo) => vaultSignatureCb(err, userInfo,
params.log, callback, streamingV4Params), params.log, callback, streamingV4Params)
); );
} }
/** getCanonicalIds -- call Vault to get canonicalIDs based on email /** getCanonicalIds -- call Vault to get canonicalIDs based on email
* addresses * addresses
* @param emailAddresses - list of emailAddresses * @param {array} emailAddresses - list of emailAddresses
* @param log - log object * @param {object} log - log object
* @param callback - callback with either error or an array * @param {function} callback - callback with either error or an array
* of objects with each object containing the canonicalID and emailAddress * of objects with each object containing the canonicalID and emailAddress
* of an account as properties * of an account as properties
* @return {undefined}
*/ */
getCanonicalIds( getCanonicalIds(emailAddresses, log, callback) {
emailAddresses: string[],
log: Logger,
callback: (
err: Error | null,
data?: { canonicalID: string; email: string }[]
) => void
) {
log.trace('getting canonicalIDs from Vault based on emailAddresses', log.trace('getting canonicalIDs from Vault based on emailAddresses',
{ emailAddresses }); { emailAddresses });
this.client.getCanonicalIds(emailAddresses, this.client.getCanonicalIds(emailAddresses,
// @ts-ignore
{ reqUid: log.getSerializedUids() }, { reqUid: log.getSerializedUids() },
(err: Error | null, info?: any) => { (err, info) => {
if (err) { if (err) {
log.debug('received error message from auth provider', log.debug('received error message from auth provider',
{ errorMessage: err }); { errorMessage: err });
@ -230,17 +172,17 @@ export default class Vault {
} }
const infoFromVault = info.message.body; const infoFromVault = info.message.body;
log.trace('info received from vault', { infoFromVault }); log.trace('info received from vault', { infoFromVault });
const foundIds: { canonicalID: string; email: string }[] = []; const foundIds = [];
for (let i = 0; i < Object.keys(infoFromVault).length; i++) { for (let i = 0; i < Object.keys(infoFromVault).length; i++) {
const key = Object.keys(infoFromVault)[i]; const key = Object.keys(infoFromVault)[i];
if (infoFromVault[key] === 'WrongFormat' if (infoFromVault[key] === 'WrongFormat'
|| infoFromVault[key] === 'NotFound') { || infoFromVault[key] === 'NotFound') {
return callback(errors.UnresolvableGrantByEmailAddress); return callback(errors.UnresolvableGrantByEmailAddress);
} }
foundIds.push({ const obj = {};
email: key, obj.email = key;
canonicalID: infoFromVault[key], obj.canonicalID = infoFromVault[key];
}) foundIds.push(obj);
} }
return callback(null, foundIds); return callback(null, foundIds);
}); });
@ -248,22 +190,18 @@ export default class Vault {
/** getEmailAddresses -- call Vault to get email addresses based on /** getEmailAddresses -- call Vault to get email addresses based on
* canonicalIDs * canonicalIDs
* @param canonicalIDs - list of canonicalIDs * @param {array} canonicalIDs - list of canonicalIDs
* @param log - log object * @param {object} log - log object
* @param callback - callback with either error or an object * @param {function} callback - callback with either error or an object
* with canonicalID keys and email address values * with canonicalID keys and email address values
* @return {undefined}
*/ */
getEmailAddresses( getEmailAddresses(canonicalIDs, log, callback) {
canonicalIDs: string[],
log: Logger,
callback: (err: Error | null, data?: { [key: string]: any }) => void
) {
log.trace('getting emailAddresses from Vault based on canonicalIDs', log.trace('getting emailAddresses from Vault based on canonicalIDs',
{ canonicalIDs }); { canonicalIDs });
this.client.getEmailAddresses(canonicalIDs, this.client.getEmailAddresses(canonicalIDs,
// @ts-ignore
{ reqUid: log.getSerializedUids() }, { reqUid: log.getSerializedUids() },
(err: Error | null, info?: any) => { (err, info) => {
if (err) { if (err) {
log.debug('received error message from vault', log.debug('received error message from vault',
{ errorMessage: err }); { errorMessage: err });
@ -286,31 +224,27 @@ export default class Vault {
/** getAccountIds -- call Vault to get accountIds based on /** getAccountIds -- call Vault to get accountIds based on
* canonicalIDs * canonicalIDs
* @param canonicalIDs - list of canonicalIDs * @param {array} canonicalIDs - list of canonicalIDs
* @param log - log object * @param {object} log - log object
* @param callback - callback with either error or an object * @param {function} callback - callback with either error or an object
* with canonicalID keys and accountId values * with canonicalID keys and accountId values
* @return {undefined}
*/ */
getAccountIds( getAccountIds(canonicalIDs, log, callback) {
canonicalIDs: string[],
log: Logger,
callback: (err: Error | null, data?: { [key: string]: string }) => void
) {
log.trace('getting accountIds from Vault based on canonicalIDs', log.trace('getting accountIds from Vault based on canonicalIDs',
{ canonicalIDs }); { canonicalIDs });
this.client.getAccountIds(canonicalIDs, this.client.getAccountIds(canonicalIDs,
// @ts-expect-error { reqUid: log.getSerializedUids() },
{ reqUid: log.getSerializedUids() }, (err, info) => {
(err: Error | null, info?: any) => { if (err) {
if (err) { log.debug('received error message from vault',
log.debug('received error message from vault', { errorMessage: err });
{ errorMessage: err }); return callback(err);
return callback(err); }
} const infoFromVault = info.message.body;
const infoFromVault = info.message.body; log.trace('info received from vault', { infoFromVault });
log.trace('info received from vault', { infoFromVault }); const result = {};
const result = {}; /* If the accountId was not found in Vault, do not
/* If the accountId was not found in Vault, do not
send the canonicalID back to the API */ send the canonicalID back to the API */
Object.keys(infoFromVault).forEach(key => { Object.keys(infoFromVault).forEach(key => {
if (infoFromVault[key] !== 'NotFound' && if (infoFromVault[key] !== 'NotFound' &&
@ -334,19 +268,14 @@ export default class Vault {
* @param {object} log - log object * @param {object} log - log object
* @param {function} callback - callback with either error or an array * @param {function} callback - callback with either error or an array
* of authorization results * of authorization results
* @return {undefined}
*/ */
checkPolicies( checkPolicies(requestContextParams, userArn, log, callback) {
requestContextParams: any[],
userArn: string,
log: Logger,
callback: (err: Error | null, data?: any[]) => void
) {
log.trace('sending request context params to vault to evaluate' + log.trace('sending request context params to vault to evaluate' +
'policies'); 'policies');
this.client.checkPolicies(requestContextParams, userArn, { this.client.checkPolicies(requestContextParams, userArn, {
// @ts-ignore
reqUid: log.getSerializedUids(), reqUid: log.getSerializedUids(),
}, (err: Error | null, info?: any) => { }, (err, info) => {
if (err) { if (err) {
log.debug('received error message from auth provider', log.debug('received error message from auth provider',
{ error: err }); { error: err });
@ -357,14 +286,13 @@ export default class Vault {
}); });
} }
checkHealth(log: Logger, callback: (err: Error | null, data?: any) => void) { checkHealth(log, callback) {
if (!this.client.healthcheck) { if (!this.client.healthcheck) {
const defResp = {}; const defResp = {};
defResp[this.implName] = { code: 200, message: 'OK' }; defResp[this.implName] = { code: 200, message: 'OK' };
return callback(null, defResp); return callback(null, defResp);
} }
// @ts-ignore return this.client.healthcheck(log.getSerializedUids(), (err, obj) => {
return this.client.healthcheck(log.getSerializedUids(), (err: Error | null, obj?: any) => {
const respBody = {}; const respBody = {};
if (err) { if (err) {
log.debug(`error from ${this.implName}`, { error: err }); log.debug(`error from ${this.implName}`, { error: err });
@ -384,3 +312,5 @@ export default class Vault {
}); });
} }
} }
module.exports = Vault;

View File

@ -1,21 +1,22 @@
import * as crypto from 'crypto'; 'use strict'; // eslint-disable-line strict
import { Logger } from 'werelogs';
import errors from '../errors';
import * as queryString from 'querystring';
import AuthInfo from './AuthInfo';
import * as v2 from './v2/authV2';
import * as v4 from './v4/authV4';
import * as constants from '../constants';
import constructStringToSignV2 from './v2/constructStringToSign';
import constructStringToSignV4 from './v4/constructStringToSign';
import { convertUTCtoISO8601 } from './v4/timeUtils';
import * as vaultUtilities from './in_memory/vaultUtilities';
import * as backend from './in_memory/Backend';
import validateAuthConfig from './in_memory/validateAuthConfig';
import AuthLoader from './in_memory/AuthLoader';
import Vault from './Vault';
let vault: Vault | null = null; const crypto = require('crypto');
const errors = require('../errors');
const queryString = require('querystring');
const AuthInfo = require('./AuthInfo');
const v2 = require('./v2/authV2');
const v4 = require('./v4/authV4');
const constants = require('../constants');
const constructStringToSignV2 = require('./v2/constructStringToSign');
const constructStringToSignV4 = require('./v4/constructStringToSign');
const convertUTCtoISO8601 = require('./v4/timeUtils').convertUTCtoISO8601;
const vaultUtilities = require('./in_memory/vaultUtilities');
const backend = require('./in_memory/Backend');
const validateAuthConfig = require('./in_memory/validateAuthConfig');
const AuthLoader = require('./in_memory/AuthLoader');
const Vault = require('./Vault');
let vault = null;
const auth = {}; const auth = {};
const checkFunctions = { const checkFunctions = {
v2: { v2: {
@ -32,7 +33,7 @@ const checkFunctions = {
// 'All Users Group' so use this group as the canonicalID for the publicUser // 'All Users Group' so use this group as the canonicalID for the publicUser
const publicUserInfo = new AuthInfo({ canonicalID: constants.publicId }); const publicUserInfo = new AuthInfo({ canonicalID: constants.publicId });
function setAuthHandler(handler: Vault) { function setAuthHandler(handler) {
vault = handler; vault = handler;
return auth; return auth;
} }
@ -40,30 +41,25 @@ function setAuthHandler(handler: Vault) {
/** /**
* This function will check validity of request parameters to authenticate * This function will check validity of request parameters to authenticate
* *
* @param request - Http request object * @param {Http.Request} request - Http request object
* @param log - Logger object * @param {object} log - Logger object
* @param awsService - Aws service related * @param {string} awsService - Aws service related
* @param data - Parameters from queryString parsing or body of * @param {object} data - Parameters from queryString parsing or body of
* POST request * POST request
* *
* @return ret * @return {object} ret
* @return ret.err - arsenal.errors object if any error was found * @return {object} ret.err - arsenal.errors object if any error was found
* @return ret.params - auth parameters to use later on for signature * @return {object} ret.params - auth parameters to use later on for signature
* computation and check * computation and check
* @return ret.params.version - the auth scheme version * @return {object} ret.params.version - the auth scheme version
* (undefined, 2, 4) * (undefined, 2, 4)
* @return ret.params.data - the auth scheme's specific data * @return {object} ret.params.data - the auth scheme's specific data
*/ */
function extractParams( function extractParams(request, log, awsService, data) {
request: any,
log: Logger,
awsService: string,
data: { [key: string]: string }
) {
log.trace('entered', { method: 'Arsenal.auth.server.extractParams' }); log.trace('entered', { method: 'Arsenal.auth.server.extractParams' });
const authHeader = request.headers.authorization; const authHeader = request.headers.authorization;
let version: 'v2' |'v4' | null = null; let version = null;
let method: 'query' | 'headers' | null = null; let method = null;
// Identify auth version and method to dispatch to the right check function // Identify auth version and method to dispatch to the right check function
if (authHeader) { if (authHeader) {
@ -106,21 +102,16 @@ function extractParams(
/** /**
* This function will check validity of request parameters to authenticate * This function will check validity of request parameters to authenticate
* *
* @param request - Http request object * @param {Http.Request} request - Http request object
* @param log - Logger object * @param {object} log - Logger object
* @param cb - the callback * @param {function} cb - the callback
* @param awsService - Aws service related * @param {string} awsService - Aws service related
* @param {RequestContext[] | null} requestContexts - array of RequestContext * @param {RequestContext[] | null} requestContexts - array of RequestContext
* or null if no requestContexts to be sent to Vault (for instance, * or null if no requestContexts to be sent to Vault (for instance,
* in multi-object delete request) * in multi-object delete request)
* @return {undefined}
*/ */
function doAuth( function doAuth(request, log, cb, awsService, requestContexts) {
request: any,
log: Logger,
cb: (err: Error | null, data?: any) => void,
awsService: string,
requestContexts: any[] | null
) {
const res = extractParams(request, log, awsService, request.query); const res = extractParams(request, log, awsService, request.query);
if (res.err) { if (res.err) {
return cb(res.err); return cb(res.err);
@ -128,31 +119,23 @@ function doAuth(
return cb(null, res.params); return cb(null, res.params);
} }
if (requestContexts) { if (requestContexts) {
requestContexts.forEach((requestContext) => { requestContexts.forEach(requestContext => {
const { params } = res requestContext.setAuthType(res.params.data.authType);
if ('data' in params) { requestContext.setSignatureVersion(res.params
const { data } = params .data.signatureVersion);
requestContext.setAuthType(data.authType); requestContext.setSignatureAge(res.params.data.signatureAge);
requestContext.setSignatureVersion(data.signatureVersion); requestContext.setSecurityToken(res.params.data.securityToken);
requestContext.setSecurityToken(data.securityToken);
if ('signatureAge' in data) {
requestContext.setSignatureAge(data.signatureAge);
}
}
}); });
} }
// Corner cases managed, we're left with normal auth // Corner cases managed, we're left with normal auth
// TODO What's happening here?
// @ts-ignore
res.params.log = log; res.params.log = log;
if (res.params.version === 2) { if (res.params.version === 2) {
// @ts-ignore return vault.authenticateV2Request(res.params, requestContexts, cb);
return vault!.authenticateV2Request(res.params, requestContexts, cb);
} }
if (res.params.version === 4) { if (res.params.version === 4) {
// @ts-ignore return vault.authenticateV4Request(res.params, requestContexts, cb,
return vault!.authenticateV4Request(res.params, requestContexts, cb); awsService);
} }
log.error('authentication method not found', { log.error('authentication method not found', {
@ -164,25 +147,19 @@ function doAuth(
/** /**
* This function will generate a version 4 header * This function will generate a version 4 header
* *
* @param request - Http request object * @param {Http.Request} request - Http request object
* @param data - Parameters from queryString parsing or body of * @param {object} data - Parameters from queryString parsing or body of
* POST request * POST request
* @param accessKey - the accessKey * @param {string} accessKey - the accessKey
* @param secretKeyValue - the secretKey * @param {string} secretKeyValue - the secretKey
* @param awsService - Aws service related * @param {string} awsService - Aws service related
* @param [proxyPath] - path that gets proxied by reverse proxy * @param {sting} [proxyPath] - path that gets proxied by reverse proxy
* @param [sessionToken] - security token if the access/secret keys * @param {string} [sessionToken] - security token if the access/secret keys
* are temporary credentials from STS * are temporary credentials from STS
* @return {undefined}
*/ */
function generateV4Headers( function generateV4Headers(request, data, accessKey, secretKeyValue,
request: any, awsService, proxyPath, sessionToken) {
data: { [key: string]: string },
accessKey: string,
secretKeyValue: string,
awsService: string,
proxyPath: string,
sessionToken: string
) {
Object.assign(request, { headers: {} }); Object.assign(request, { headers: {} });
const amzDate = convertUTCtoISO8601(Date.now()); const amzDate = convertUTCtoISO8601(Date.now());
// get date without time // get date without time
@ -196,7 +173,7 @@ function generateV4Headers(
let payload = ''; let payload = '';
if (request.method === 'POST') { if (request.method === 'POST') {
payload = queryString.stringify(data, undefined, undefined, { payload = queryString.stringify(data, null, null, {
encodeURIComponent, encodeURIComponent,
}); });
} }
@ -226,7 +203,7 @@ function generateV4Headers(
scopeDate, scopeDate,
service); service);
const signature = crypto.createHmac('sha256', signingKey) const signature = crypto.createHmac('sha256', signingKey)
.update(stringToSign as string, 'binary').digest('hex'); .update(stringToSign, 'binary').digest('hex');
const authorizationHeader = `${algorithm} Credential=${accessKey}` + const authorizationHeader = `${algorithm} Credential=${accessKey}` +
`/${credentialScope}, SignedHeaders=${signedHeaders}, ` + `/${credentialScope}, SignedHeaders=${signedHeaders}, ` +
`Signature=${signature}`; `Signature=${signature}`;
@ -234,11 +211,21 @@ function generateV4Headers(
Object.assign(request, { headers: {} }); Object.assign(request, { headers: {} });
} }
export const server = { extractParams, doAuth } module.exports = {
export const client = { generateV4Headers, constructStringToSignV2 } setHandler: setAuthHandler,
export const inMemory = { backend, validateAuthConfig, AuthLoader } server: {
export { extractParams,
setAuthHandler as setHandler, doAuth,
},
client: {
generateV4Headers,
constructStringToSignV2,
},
inMemory: {
backend,
validateAuthConfig,
AuthLoader,
},
AuthInfo, AuthInfo,
Vault Vault,
} };

View File

@ -1,10 +1,13 @@
import * as crypto from 'crypto'; 'use strict'; // eslint-disable-line strict
import errors from '../../errors';
import { calculateSigningKey, hashSignature } from './vaultUtilities';
import Indexer from './Indexer';
import { Accounts } from './types';
function _formatResponse(userInfoToSend: any) { const crypto = require('crypto');
const errors = require('../../errors');
const calculateSigningKey = require('./vaultUtilities').calculateSigningKey;
const hashSignature = require('./vaultUtilities').hashSignature;
const Indexer = require('./Indexer');
function _formatResponse(userInfoToSend) {
return { return {
message: { message: {
body: { userInfo: userInfoToSend }, body: { userInfo: userInfoToSend },
@ -15,27 +18,33 @@ function _formatResponse(userInfoToSend: any) {
/** /**
* Class that provides a memory backend for verifying signatures and getting * Class that provides a memory backend for verifying signatures and getting
* emails and canonical ids associated with an account. * emails and canonical ids associated with an account.
*
* @class Backend
*/ */
class Backend { class Backend {
indexer: Indexer; /**
service: string; * @constructor
* @param {string} service - service identifer for construction arn
constructor(service: string, indexer: Indexer) { * @param {Indexer} indexer - indexer instance for retrieving account info
* @param {function} formatter - function which accepts user info to send
* back and returns it in an object
*/
constructor(service, indexer, formatter) {
this.service = service; this.service = service;
this.indexer = indexer; this.indexer = indexer;
this.formatResponse = formatter;
} }
// CODEQUALITY-TODO-SYNC Should be synchronous /** verifySignatureV2
verifySignatureV2( * @param {string} stringToSign - string to sign built per AWS rules
stringToSign: string, * @param {string} signatureFromRequest - signature sent with request
signatureFromRequest: string, * @param {string} accessKey - account accessKey
accessKey: string, * @param {object} options - contains algorithm (SHA1 or SHA256)
options: { algo: 'SHA256' | 'SHA1' }, * @param {function} callback - callback with either error or user info
callback: ( * @return {function} calls callback
error: Error | null, */
data?: ReturnType<typeof _formatResponse> verifySignatureV2(stringToSign, signatureFromRequest,
) => void accessKey, options, callback) {
) {
const entity = this.indexer.getEntityByKey(accessKey); const entity = this.indexer.getEntityByKey(accessKey);
if (!entity) { if (!entity) {
return callback(errors.InvalidAccessKeyId); return callback(errors.InvalidAccessKeyId);
@ -50,28 +59,26 @@ class Backend {
accountDisplayName: this.indexer.getAcctDisplayName(entity), accountDisplayName: this.indexer.getAcctDisplayName(entity),
canonicalID: entity.canonicalID, canonicalID: entity.canonicalID,
arn: entity.arn, arn: entity.arn,
// TODO Why?
// @ts-ignore
IAMdisplayName: entity.IAMdisplayName, IAMdisplayName: entity.IAMdisplayName,
}; };
const vaultReturnObject = _formatResponse(userInfoToSend); const vaultReturnObject = this.formatResponse(userInfoToSend);
return callback(null, vaultReturnObject); return callback(null, vaultReturnObject);
} }
// TODO Options not used. Why ?
// CODEQUALITY-TODO-SYNC Should be synchronous /** verifySignatureV4
verifySignatureV4( * @param {string} stringToSign - string to sign built per AWS rules
stringToSign: string, * @param {string} signatureFromRequest - signature sent with request
signatureFromRequest: string, * @param {string} accessKey - account accessKey
accessKey: string, * @param {string} region - region specified in request credential
region: string, * @param {string} scopeDate - date specified in request credential
scopeDate: string, * @param {object} options - options to send to Vault
_options: { algo: 'SHA256' | 'SHA1' }, * (just contains reqUid for logging in Vault)
callback: ( * @param {function} callback - callback with either error or user info
err: Error | null, * @return {function} calls callback
data?: ReturnType<typeof _formatResponse> */
) => void verifySignatureV4(stringToSign, signatureFromRequest, accessKey,
) { region, scopeDate, options, callback) {
const entity = this.indexer.getEntityByKey(accessKey); const entity = this.indexer.getEntityByKey(accessKey);
if (!entity) { if (!entity) {
return callback(errors.InvalidAccessKeyId); return callback(errors.InvalidAccessKeyId);
@ -87,21 +94,23 @@ class Backend {
accountDisplayName: this.indexer.getAcctDisplayName(entity), accountDisplayName: this.indexer.getAcctDisplayName(entity),
canonicalID: entity.canonicalID, canonicalID: entity.canonicalID,
arn: entity.arn, arn: entity.arn,
// TODO Why?
// @ts-ignore
IAMdisplayName: entity.IAMdisplayName, IAMdisplayName: entity.IAMdisplayName,
}; };
const vaultReturnObject = _formatResponse(userInfoToSend); const vaultReturnObject = this.formatResponse(userInfoToSend);
return callback(null, vaultReturnObject); return callback(null, vaultReturnObject);
} }
// TODO log not used. Why ? /**
// CODEQUALITY-TODO-SYNC Should be synchronous * Gets canonical ID's for a list of accounts
getCanonicalIds( * based on email associated with account
emails: string[], * @param {array} emails - list of email addresses
_log: any, * @param {object} log - log object
cb: (err: null, data: { message: { body: any } }) => void * @param {function} cb - callback to calling function
) { * @returns {function} callback with either error or
* object with email addresses as keys and canonical IDs
* as values
*/
getCanonicalIds(emails, log, cb) {
const results = {}; const results = {};
emails.forEach(email => { emails.forEach(email => {
const lowercasedEmail = email.toLowerCase(); const lowercasedEmail = email.toLowerCase();
@ -121,13 +130,17 @@ class Backend {
return cb(null, vaultReturnObject); return cb(null, vaultReturnObject);
} }
// TODO options not used. Why ? /**
// CODEQUALITY-TODO-SYNC Should be synchronous * Gets email addresses (referred to as diplay names for getACL's)
getEmailAddresses( * for a list of accounts based on canonical IDs associated with account
canonicalIDs: string[], * @param {array} canonicalIDs - list of canonicalIDs
_options: any, * @param {object} options - to send log id to vault
cb: (err: null, data: { message: { body: any } }) => void * @param {function} cb - callback to calling function
) { * @returns {function} callback with either error or
* an object from Vault containing account canonicalID
* as each object key and an email address as the value (or "NotFound")
*/
getEmailAddresses(canonicalIDs, options, cb) {
const results = {}; const results = {};
canonicalIDs.forEach(canonicalId => { canonicalIDs.forEach(canonicalId => {
const foundEntity = this.indexer.getEntityByCanId(canonicalId); const foundEntity = this.indexer.getEntityByCanId(canonicalId);
@ -145,24 +158,17 @@ class Backend {
return cb(null, vaultReturnObject); return cb(null, vaultReturnObject);
} }
// TODO options not used. Why ?
// CODEQUALITY-TODO-SYNC Should be synchronous
/** /**
* Gets accountIds for a list of accounts based on * Gets accountIds for a list of accounts based on
* the canonical IDs associated with the account * the canonical IDs associated with the account
* @param canonicalIDs - list of canonicalIDs * @param {array} canonicalIDs - list of canonicalIDs
* @param _options - to send log id to vault * @param {object} options - to send log id to vault
* @param cb - callback to calling function * @param {function} cb - callback to calling function
* @returns The next is wrong. Here to keep archives. * @returns {function} callback with either error or
* callback with either error or
* an object from Vault containing account canonicalID * an object from Vault containing account canonicalID
* as each object key and an accountId as the value (or "NotFound") * as each object key and an accountId as the value (or "NotFound")
*/ */
getAccountIds( getAccountIds(canonicalIDs, options, cb) {
canonicalIDs: string[],
_options: any,
cb: (err: null, data: { message: { body: any } }) => void
) {
const results = {}; const results = {};
canonicalIDs.forEach(canonicalID => { canonicalIDs.forEach(canonicalID => {
const foundEntity = this.indexer.getEntityByCanId(canonicalID); const foundEntity = this.indexer.getEntityByCanId(canonicalID);
@ -181,14 +187,31 @@ class Backend {
} }
} }
class S3AuthBackend extends Backend { class S3AuthBackend extends Backend {
constructor(authdata: Accounts) { /**
super('s3', new Indexer(authdata)); * @constructor
* @param {object} authdata - the authentication config file's data
* @param {object[]} authdata.accounts - array of account objects
* @param {string=} authdata.accounts[].name - account name
* @param {string} authdata.accounts[].email - account email
* @param {string} authdata.accounts[].arn - IAM resource name
* @param {string} authdata.accounts[].canonicalID - account canonical ID
* @param {string} authdata.accounts[].shortid - short account ID
* @param {object[]=} authdata.accounts[].keys - array of key objects
* @param {string} authdata.accounts[].keys[].access - access key
* @param {string} authdata.accounts[].keys[].secret - secret key
* @return {undefined}
*/
constructor(authdata) {
super('s3', new Indexer(authdata), _formatResponse);
} }
refreshAuthData(authData: Accounts) { refreshAuthData(authData) {
this.indexer = new Indexer(authData); this.indexer = new Indexer(authData);
} }
} }
export { S3AuthBackend as s3 }; module.exports = {
s3: S3AuthBackend,
};

View File

@ -1,19 +1,27 @@
import { Accounts, Account, Entity } from './types';
/** /**
* Class that provides an internal indexing over the simple data provided by * Class that provides an internal indexing over the simple data provided by
* the authentication configuration file for the memory backend. This allows * the authentication configuration file for the memory backend. This allows
* accessing the different authentication entities through various types of * accessing the different authentication entities through various types of
* keys. * keys.
*
* @class Indexer
*/ */
export default class Indexer { class Indexer {
accountsBy: { /**
canId: { [id: string]: Entity | undefined }, * @constructor
accessKey: { [id: string]: Entity | undefined }, * @param {object} authdata - the authentication config file's data
email: { [id: string]: Entity | undefined }, * @param {object[]} authdata.accounts - array of account objects
} * @param {string=} authdata.accounts[].name - account name
* @param {string} authdata.accounts[].email - account email
constructor(authdata?: Accounts) { * @param {string} authdata.accounts[].arn - IAM resource name
* @param {string} authdata.accounts[].canonicalID - account canonical ID
* @param {string} authdata.accounts[].shortid - short account ID
* @param {object[]=} authdata.accounts[].keys - array of key objects
* @param {string} authdata.accounts[].keys[].access - access key
* @param {string} authdata.accounts[].keys[].secret - secret key
* @return {undefined}
*/
constructor(authdata) {
this.accountsBy = { this.accountsBy = {
canId: {}, canId: {},
accessKey: {}, accessKey: {},
@ -29,11 +37,11 @@ export default class Indexer {
return; return;
} }
this.#build(authdata); this._build(authdata);
} }
#indexAccount(account: Account) { _indexAccount(account) {
const accountData: Entity = { const accountData = {
arn: account.arn, arn: account.arn,
canonicalID: account.canonicalID, canonicalID: account.canonicalID,
shortid: account.shortid, shortid: account.shortid,
@ -51,43 +59,87 @@ export default class Indexer {
} }
} }
#build(authdata: Accounts) { _build(authdata) {
authdata.accounts.forEach(account => { authdata.accounts.forEach(account => {
this.#indexAccount(account); this._indexAccount(account);
}); });
} }
/** This method returns the account associated to a canonical ID. */ /**
getEntityByCanId(canId: string): Entity | undefined { * This method returns the account associated to a canonical ID.
*
* @param {string} canId - The canonicalId of the account
* @return {Object} account - The account object
* @return {Object} account.arn - The account's ARN
* @return {Object} account.canonicalID - The account's canonical ID
* @return {Object} account.shortid - The account's internal shortid
* @return {Object} account.accountDisplayName - The account's display name
* @return {Object} account.email - The account's lowercased email
*/
getEntityByCanId(canId) {
return this.accountsBy.canId[canId]; return this.accountsBy.canId[canId];
} }
/** /**
* This method returns the entity (either an account or a user) associated * This method returns the entity (either an account or a user) associated
* to a canonical ID. * to a canonical ID.
*
* @param {string} key - The accessKey of the entity * @param {string} key - The accessKey of the entity
* @return {Object} entity - The entity object
* @return {Object} entity.arn - The entity's ARN
* @return {Object} entity.canonicalID - The canonical ID for the entity's
* account
* @return {Object} entity.shortid - The entity's internal shortid
* @return {Object} entity.accountDisplayName - The entity's account
* display name
* @return {Object} entity.IAMDisplayName - The user's display name
* (if the entity is an user)
* @return {Object} entity.email - The entity's lowercased email
*/ */
getEntityByKey(key: string): Entity | undefined { getEntityByKey(key) {
return this.accountsBy.accessKey[key]; return this.accountsBy.accessKey[key];
} }
/** /**
* This method returns the entity (either an account or a user) associated * This method returns the entity (either an account or a user) associated
* to an email address. * to an email address.
*
* @param {string} email - The email address
* @return {Object} entity - The entity object
* @return {Object} entity.arn - The entity's ARN
* @return {Object} entity.canonicalID - The canonical ID for the entity's
* account
* @return {Object} entity.shortid - The entity's internal shortid
* @return {Object} entity.accountDisplayName - The entity's account
* display name
* @return {Object} entity.IAMDisplayName - The user's display name
* (if the entity is an user)
* @return {Object} entity.email - The entity's lowercased email
*/ */
getEntityByEmail(email: string): Entity | undefined { getEntityByEmail(email) {
const lowerCasedEmail = email.toLowerCase(); const lowerCasedEmail = email.toLowerCase();
return this.accountsBy.email[lowerCasedEmail]; return this.accountsBy.email[lowerCasedEmail];
} }
/** This method returns the secret key associated with the entity. */ /**
getSecretKey(entity: Entity, accessKey: string) { * This method returns the secret key associated with the entity.
const keys = entity.keys.filter(kv => kv.access === accessKey); * @param {Object} entity - the entity object
return keys[0].secret; * @param {string} accessKey - access key
* @returns {string} secret key
*/
getSecretKey(entity, accessKey) {
return entity.keys
.filter(kv => kv.access === accessKey)[0].secret;
} }
/** This method returns the account display name associated with the entity. */ /**
getAcctDisplayName(entity: Entity) { * This method returns the account display name associated with the entity.
* @param {Object} entity - the entity object
* @returns {string} account display name
*/
getAcctDisplayName(entity) {
return entity.accountDisplayName; return entity.accountDisplayName;
} }
} }
module.exports = Indexer;

View File

@ -1,16 +1,18 @@
import { Logger } from 'werelogs'; const AuthLoader = require('./AuthLoader');
import AuthLoader from './AuthLoader';
import { Accounts } from './types';
/** /**
* @deprecated please use {@link AuthLoader} class instead * @deprecated please use {@link AuthLoader} class instead
* @return true on erroneous data false on success *
* @param {object} authdata - the authentication config file's data
* @param {werelogs.API} logApi - object providing a constructor function
* for the Logger object
* @return {boolean} true on erroneous data
* false on success
*/ */
export default function validateAuthConfig( function validateAuthConfig(authdata, logApi) {
authdata: Accounts,
logApi?: { Logger: typeof Logger }
) {
const authLoader = new AuthLoader(logApi); const authLoader = new AuthLoader(logApi);
authLoader.addAccounts(authdata); authLoader.addAccounts(authdata);
return !authLoader.validate(); return !authLoader.validate();
} }
module.exports = validateAuthConfig;

View File

@ -1,5 +1,7 @@
export default function algoCheck(signatureLength: number) { 'use strict'; // eslint-disable-line strict
let algo: 'sha256' | 'sha1';
function algoCheck(signatureLength) {
let algo;
// If the signature sent is 44 characters, // If the signature sent is 44 characters,
// this means that sha256 was used: // this means that sha256 was used:
// 44 characters in base64 // 44 characters in base64
@ -11,6 +13,7 @@ export default function algoCheck(signatureLength: number) {
if (signatureLength === SHA1LEN) { if (signatureLength === SHA1LEN) {
algo = 'sha1'; algo = 'sha1';
} }
// @ts-ignore
return algo; return algo;
} }
module.exports = algoCheck;

View File

@ -1,2 +1,11 @@
export * as header from './headerAuthCheck'; 'use strict'; // eslint-disable-line strict
export * as query from './queryAuthCheck';
const headerAuthCheck = require('./headerAuthCheck');
const queryAuthCheck = require('./queryAuthCheck');
const authV2 = {
header: headerAuthCheck,
query: queryAuthCheck,
};
module.exports = authV2;

View File

@ -1,9 +1,9 @@
import { Logger } from 'werelogs'; 'use strict'; // eslint-disable-line strict
import errors from '../../errors'; const errors = require('../../errors');
const epochTime = new Date('1970-01-01').getTime(); const epochTime = new Date('1970-01-01').getTime();
export default function checkRequestExpiry(timestamp: number, log: Logger) { function checkRequestExpiry(timestamp, log) {
// If timestamp is before epochTime, the request is invalid and return // If timestamp is before epochTime, the request is invalid and return
// errors.AccessDenied // errors.AccessDenied
if (timestamp < epochTime) { if (timestamp < epochTime) {
@ -32,3 +32,5 @@ export default function checkRequestExpiry(timestamp: number, log: Logger) {
return undefined; return undefined;
} }
module.exports = checkRequestExpiry;

View File

@ -1,14 +1,11 @@
import { Logger } from 'werelogs'; 'use strict'; // eslint-disable-line strict
import utf8 from 'utf8';
import getCanonicalizedAmzHeaders from './getCanonicalizedAmzHeaders';
import getCanonicalizedResource from './getCanonicalizedResource';
export default function constructStringToSign( const utf8 = require('utf8');
request: any,
data: { [key: string]: string }, const getCanonicalizedAmzHeaders = require('./getCanonicalizedAmzHeaders');
log: Logger, const getCanonicalizedResource = require('./getCanonicalizedResource');
clientType?: any
) { function constructStringToSign(request, data, log, clientType) {
/* /*
Build signature per AWS requirements: Build signature per AWS requirements:
StringToSign = HTTP-Verb + '\n' + StringToSign = HTTP-Verb + '\n' +
@ -45,3 +42,5 @@ export default function constructStringToSign(
+ getCanonicalizedResource(request, clientType); + getCanonicalizedResource(request, clientType);
return utf8.encode(stringToSign); return utf8.encode(stringToSign);
} }
module.exports = constructStringToSign;

View File

@ -1,12 +1,14 @@
export default function getCanonicalizedAmzHeaders(headers: Headers, clientType: string) { 'use strict'; // eslint-disable-line strict
function getCanonicalizedAmzHeaders(headers, clientType) {
/* /*
Iterate through headers and pull any headers that are x-amz headers. Iterate through headers and pull any headers that are x-amz headers.
Need to include 'x-amz-date' here even though AWS docs Need to include 'x-amz-date' here even though AWS docs
ambiguous on this. ambiguous on this.
*/ */
const filterFn = clientType === 'GCP' ? const filterFn = clientType === 'GCP' ?
(val: string) => val.substr(0, 7) === 'x-goog-' : val => val.substr(0, 7) === 'x-goog-' :
(val: string) => val.substr(0, 6) === 'x-amz-'; val => val.substr(0, 6) === 'x-amz-';
const amzHeaders = Object.keys(headers) const amzHeaders = Object.keys(headers)
.filter(filterFn) .filter(filterFn)
.map(val => [val.trim(), headers[val].trim()]); .map(val => [val.trim(), headers[val].trim()]);
@ -41,3 +43,5 @@ export default function getCanonicalizedAmzHeaders(headers: Headers, clientType:
`${headerStr}${current[0]}:${current[1]}\n`, `${headerStr}${current[0]}:${current[1]}\n`,
''); '');
} }
module.exports = getCanonicalizedAmzHeaders;

View File

@ -1,4 +1,6 @@
import * as url from 'url'; 'use strict'; // eslint-disable-line strict
const url = require('url');
const gcpSubresources = [ const gcpSubresources = [
'acl', 'acl',
@ -39,7 +41,7 @@ const awsSubresources = [
'website', 'website',
]; ];
export default function getCanonicalizedResource(request: any, clientType: string) { function getCanonicalizedResource(request, clientType) {
/* /*
This variable is used to determine whether to insert This variable is used to determine whether to insert
a '?' or '&'. Once a query parameter is added to the resourceString, a '?' or '&'. Once a query parameter is added to the resourceString,
@ -115,3 +117,5 @@ export default function getCanonicalizedResource(request: any, clientType: strin
} }
return resourceString; return resourceString;
} }
module.exports = getCanonicalizedResource;

View File

@ -1,11 +1,12 @@
import { Logger } from 'werelogs'; 'use strict'; // eslint-disable-line strict
import errors from '../../errors';
import * as constants from '../../constants';
import constructStringToSign from './constructStringToSign';
import checkRequestExpiry from './checkRequestExpiry';
import algoCheck from './algoCheck';
export function check(request: any, log: Logger, data: { [key: string]: string }) { const errors = require('../../errors');
const constants = require('../../constants');
const constructStringToSign = require('./constructStringToSign');
const checkRequestExpiry = require('./checkRequestExpiry');
const algoCheck = require('./algoCheck');
function check(request, log, data) {
log.trace('running header auth check'); log.trace('running header auth check');
const headers = request.headers; const headers = request.headers;
@ -51,7 +52,6 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
log.trace('invalid authorization header', { authInfo }); log.trace('invalid authorization header', { authInfo });
return { err: errors.MissingSecurityHeader }; return { err: errors.MissingSecurityHeader };
} }
// @ts-ignore
log.addDefaultFields({ accessKey }); log.addDefaultFields({ accessKey });
const signatureFromRequest = authInfo.substring(semicolonIndex + 1).trim(); const signatureFromRequest = authInfo.substring(semicolonIndex + 1).trim();
@ -80,3 +80,5 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
}, },
}; };
} }
module.exports = { check };

View File

@ -1,10 +1,11 @@
import { Logger } from 'werelogs'; 'use strict'; // eslint-disable-line strict
import errors from '../../errors';
import * as constants from '../../constants';
import algoCheck from './algoCheck';
import constructStringToSign from './constructStringToSign';
export function check(request: any, log: Logger, data: { [key: string]: string }) { const errors = require('../../errors');
const constants = require('../../constants');
const algoCheck = require('./algoCheck');
const constructStringToSign = require('./constructStringToSign');
function check(request, log, data) {
log.trace('running query auth check'); log.trace('running query auth check');
if (request.method === 'POST') { if (request.method === 'POST') {
log.debug('query string auth not supported for post requests'); log.debug('query string auth not supported for post requests');
@ -50,7 +51,6 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
return { err: errors.RequestTimeTooSkewed }; return { err: errors.RequestTimeTooSkewed };
} }
const accessKey = data.AWSAccessKeyId; const accessKey = data.AWSAccessKeyId;
// @ts-ignore
log.addDefaultFields({ accessKey }); log.addDefaultFields({ accessKey });
const signatureFromRequest = decodeURIComponent(data.Signature); const signatureFromRequest = decodeURIComponent(data.Signature);
@ -82,3 +82,5 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
}, },
}; };
} }
module.exports = { check };

View File

@ -1,2 +1,11 @@
export * as header from './headerAuthCheck'; 'use strict'; // eslint-disable-line strict
export * as query from './queryAuthCheck';
const headerAuthCheck = require('./headerAuthCheck');
const queryAuthCheck = require('./queryAuthCheck');
const authV4 = {
header: headerAuthCheck,
query: queryAuthCheck,
};
module.exports = authV4;

View File

@ -1,3 +1,5 @@
'use strict'; // eslint-disable-line strict
/* /*
AWS's URI encoding rules: AWS's URI encoding rules:
URI encode every byte. Uri-Encode() must enforce the following rules: URI encode every byte. Uri-Encode() must enforce the following rules:
@ -17,7 +19,7 @@ See http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
*/ */
// converts utf8 character to hex and pads "%" before every two hex digits // converts utf8 character to hex and pads "%" before every two hex digits
function _toHexUTF8(char: string) { function _toHexUTF8(char) {
const hexRep = Buffer.from(char, 'utf8').toString('hex').toUpperCase(); const hexRep = Buffer.from(char, 'utf8').toString('hex').toUpperCase();
let res = ''; let res = '';
hexRep.split('').forEach((v, n) => { hexRep.split('').forEach((v, n) => {
@ -30,11 +32,7 @@ function _toHexUTF8(char: string) {
return res; return res;
} }
export default function awsURIencode( function awsURIencode(input, encodeSlash, noEncodeStar) {
input: string,
encodeSlash?: boolean,
noEncodeStar?: boolean
) {
const encSlash = encodeSlash === undefined ? true : encodeSlash; const encSlash = encodeSlash === undefined ? true : encodeSlash;
let encoded = ''; let encoded = '';
/** /**
@ -64,3 +62,5 @@ export default function awsURIencode(
} }
return encoded; return encoded;
} }
module.exports = awsURIencode;

View File

@ -1,33 +1,17 @@
import * as crypto from 'crypto'; 'use strict'; // eslint-disable-line strict
import { Logger } from 'werelogs';
import createCanonicalRequest from './createCanonicalRequest'; const crypto = require('crypto');
const createCanonicalRequest = require('./createCanonicalRequest');
/** /**
* constructStringToSign - creates V4 stringToSign * constructStringToSign - creates V4 stringToSign
* @param {object} params - params object * @param {object} params - params object
* @returns {string} - stringToSign * @returns {string} - stringToSign
*/ */
export default function constructStringToSign(params: { function constructStringToSign(params) {
request: any; const { request, signedHeaders, payloadChecksum, credentialScope, timestamp,
signedHeaders: any; query, log, proxyPath } = params;
payloadChecksum: any;
credentialScope: string;
timestamp: string;
query: { [key: string]: string };
log?: Logger;
proxyPath?: string;
awsService: string;
}): string | Error {
const {
request,
signedHeaders,
payloadChecksum,
credentialScope,
timestamp,
query,
log,
proxyPath,
} = params;
const path = proxyPath || request.path; const path = proxyPath || request.path;
const canonicalReqResult = createCanonicalRequest({ const canonicalReqResult = createCanonicalRequest({
@ -40,8 +24,6 @@ export default function constructStringToSign(params: {
service: params.awsService, service: params.awsService,
}); });
// TODO Why that line?
// @ts-ignore
if (canonicalReqResult instanceof Error) { if (canonicalReqResult instanceof Error) {
if (log) { if (log) {
log.error('error creating canonicalRequest'); log.error('error creating canonicalRequest');
@ -58,3 +40,5 @@ export default function constructStringToSign(params: {
`${credentialScope}\n${canonicalHex}`; `${credentialScope}\n${canonicalHex}`;
return stringToSign; return stringToSign;
} }
module.exports = constructStringToSign;

View File

@ -1,33 +1,27 @@
import * as crypto from 'crypto'; 'use strict'; // eslint-disable-line strict
import * as queryString from 'querystring';
import awsURIencode from './awsURIencode'; const awsURIencode = require('./awsURIencode');
const crypto = require('crypto');
const queryString = require('querystring');
/** /**
* createCanonicalRequest - creates V4 canonical request * createCanonicalRequest - creates V4 canonical request
* @param params - contains pHttpVerb (request type), * @param {object} params - contains pHttpVerb (request type),
* pResource (parsed from URL), pQuery (request query), * pResource (parsed from URL), pQuery (request query),
* pHeaders (request headers), pSignedHeaders (signed headers from request), * pHeaders (request headers), pSignedHeaders (signed headers from request),
* payloadChecksum (from request) * payloadChecksum (from request)
* @returns - canonicalRequest * @returns {string} - canonicalRequest
*/ */
export default function createCanonicalRequest( function createCanonicalRequest(params) {
params: {
pHttpVerb: string;
pResource: string;
pQuery: { [key: string]: string };
pHeaders: any;
pSignedHeaders: any;
service: string;
payloadChecksum: string;
}
) {
const pHttpVerb = params.pHttpVerb; const pHttpVerb = params.pHttpVerb;
const pResource = params.pResource; const pResource = params.pResource;
const pQuery = params.pQuery; const pQuery = params.pQuery;
const pHeaders = params.pHeaders; const pHeaders = params.pHeaders;
const pSignedHeaders = params.pSignedHeaders; const pSignedHeaders = params.pSignedHeaders;
const service = params.service; const service = params.service;
let payloadChecksum = params.payloadChecksum; let payloadChecksum = params.payloadChecksum;
if (!payloadChecksum) { if (!payloadChecksum) {
if (pHttpVerb === 'GET') { if (pHttpVerb === 'GET') {
payloadChecksum = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b' + payloadChecksum = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b' +
@ -40,7 +34,7 @@ export default function createCanonicalRequest(
if (/aws-sdk-java\/[0-9.]+/.test(pHeaders['user-agent'])) { if (/aws-sdk-java\/[0-9.]+/.test(pHeaders['user-agent'])) {
notEncodeStar = true; notEncodeStar = true;
} }
let payload = queryString.stringify(pQuery, undefined, undefined, { let payload = queryString.stringify(pQuery, null, null, {
encodeURIComponent: input => awsURIencode(input, true, encodeURIComponent: input => awsURIencode(input, true,
notEncodeStar), notEncodeStar),
}); });
@ -67,11 +61,11 @@ export default function createCanonicalRequest(
// signed headers // signed headers
const signedHeadersList = pSignedHeaders.split(';'); const signedHeadersList = pSignedHeaders.split(';');
signedHeadersList.sort((a: any, b: any) => a.localeCompare(b)); signedHeadersList.sort((a, b) => a.localeCompare(b));
const signedHeaders = signedHeadersList.join(';'); const signedHeaders = signedHeadersList.join(';');
// canonical headers // canonical headers
const canonicalHeadersList = signedHeadersList.map((signedHeader: any) => { const canonicalHeadersList = signedHeadersList.map(signedHeader => {
if (pHeaders[signedHeader] !== undefined) { if (pHeaders[signedHeader] !== undefined) {
const trimmedHeader = pHeaders[signedHeader] const trimmedHeader = pHeaders[signedHeader]
.trim().replace(/\s+/g, ' '); .trim().replace(/\s+/g, ' ');
@ -93,3 +87,5 @@ export default function createCanonicalRequest(
`${signedHeaders}\n${payloadChecksum}`; `${signedHeaders}\n${payloadChecksum}`;
return canonicalRequest; return canonicalRequest;
} }
module.exports = createCanonicalRequest;

View File

@ -1,32 +1,27 @@
import { Logger } from 'werelogs'; 'use strict'; // eslint-disable-line strict
import errors from '../../../lib/errors';
import * as constants from '../../constants'; const errors = require('../../../lib/errors');
import constructStringToSign from './constructStringToSign'; const constants = require('../../constants');
import {
checkTimeSkew, const constructStringToSign = require('./constructStringToSign');
convertUTCtoISO8601, const checkTimeSkew = require('./timeUtils').checkTimeSkew;
convertAmzTimeToMs, const convertUTCtoISO8601 = require('./timeUtils').convertUTCtoISO8601;
} from './timeUtils'; const convertAmzTimeToMs = require('./timeUtils').convertAmzTimeToMs;
import { const extractAuthItems = require('./validateInputs').extractAuthItems;
extractAuthItems, const validateCredentials = require('./validateInputs').validateCredentials;
validateCredentials, const areSignedHeadersComplete =
areSignedHeadersComplete, require('./validateInputs').areSignedHeadersComplete;
} from './validateInputs';
/** /**
* V4 header auth check * V4 header auth check
* @param request - HTTP request object * @param {object} request - HTTP request object
* @param log - logging object * @param {object} log - logging object
* @param data - Parameters from queryString parsing or body of * @param {object} data - Parameters from queryString parsing or body of
* POST request * POST request
* @param awsService - Aws service ('iam' or 's3') * @param {string} awsService - Aws service ('iam' or 's3')
* @return {callback} calls callback
*/ */
export function check( function check(request, log, data, awsService) {
request: any,
log: Logger,
data: { [key: string]: string },
awsService: string
) {
log.trace('running header auth check'); log.trace('running header auth check');
const token = request.headers['x-amz-security-token']; const token = request.headers['x-amz-security-token'];
@ -67,16 +62,16 @@ export function check(
log.trace('authorization header from request', { authHeader }); log.trace('authorization header from request', { authHeader });
const signatureFromRequest = authHeaderItems.signatureFromRequest!; const signatureFromRequest = authHeaderItems.signatureFromRequest;
const credentialsArr = authHeaderItems.credentialsArr!; const credentialsArr = authHeaderItems.credentialsArr;
const signedHeaders = authHeaderItems.signedHeaders!; const signedHeaders = authHeaderItems.signedHeaders;
if (!areSignedHeadersComplete(signedHeaders, request.headers)) { if (!areSignedHeadersComplete(signedHeaders, request.headers)) {
log.debug('signedHeaders are incomplete', { signedHeaders }); log.debug('signedHeaders are incomplete', { signedHeaders });
return { err: errors.AccessDenied }; return { err: errors.AccessDenied };
} }
let timestamp: string | undefined; let timestamp;
// check request timestamp // check request timestamp
const xAmzDate = request.headers['x-amz-date']; const xAmzDate = request.headers['x-amz-date'];
if (xAmzDate) { if (xAmzDate) {
@ -171,3 +166,5 @@ export function check(
}, },
}; };
} }
module.exports = { check };

View File

@ -1,18 +1,24 @@
import { Logger } from 'werelogs'; 'use strict'; // eslint-disable-line strict
import * as constants from '../../constants';
import errors from '../../errors'; const constants = require('../../constants');
import constructStringToSign from './constructStringToSign'; const errors = require('../../errors');
import { checkTimeSkew, convertAmzTimeToMs } from './timeUtils';
import { validateCredentials, extractQueryParams } from './validateInputs'; const constructStringToSign = require('./constructStringToSign');
import { areSignedHeadersComplete } from './validateInputs'; const checkTimeSkew = require('./timeUtils').checkTimeSkew;
const convertAmzTimeToMs = require('./timeUtils').convertAmzTimeToMs;
const validateCredentials = require('./validateInputs').validateCredentials;
const extractQueryParams = require('./validateInputs').extractQueryParams;
const areSignedHeadersComplete =
require('./validateInputs').areSignedHeadersComplete;
/** /**
* V4 query auth check * V4 query auth check
* @param request - HTTP request object * @param {object} request - HTTP request object
* @param log - logging object * @param {object} log - logging object
* @param data - Contain authentification params (GET or POST data) * @param {object} data - Contain authentification params (GET or POST data)
* @return {callback} calls callback
*/ */
export function check(request: any, log: Logger, data: { [key: string]: string }) { function check(request, log, data) {
const authParams = extractQueryParams(data, log); const authParams = extractQueryParams(data, log);
if (Object.keys(authParams).length !== 5) { if (Object.keys(authParams).length !== 5) {
@ -27,11 +33,11 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
return { err: errors.InvalidToken }; return { err: errors.InvalidToken };
} }
const signedHeaders = authParams.signedHeaders!; const signedHeaders = authParams.signedHeaders;
const signatureFromRequest = authParams.signatureFromRequest!; const signatureFromRequest = authParams.signatureFromRequest;
const timestamp = authParams.timestamp!; const timestamp = authParams.timestamp;
const expiry = authParams.expiry!; const expiry = authParams.expiry;
const credential = authParams.credential!; const credential = authParams.credential;
if (!areSignedHeadersComplete(signedHeaders, request.headers)) { if (!areSignedHeadersComplete(signedHeaders, request.headers)) {
log.debug('signedHeaders are incomplete', { signedHeaders }); log.debug('signedHeaders are incomplete', { signedHeaders });
@ -104,3 +110,5 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
}, },
}; };
} }
module.exports = { check };

View File

@ -1,11 +1,12 @@
import { Logger } from 'werelogs'; 'use strict'; // eslint-disable-line strict
/** /**
* Convert timestamp to milliseconds since Unix Epoch * Convert timestamp to milliseconds since Unix Epoch
* @param timestamp of ISO8601Timestamp format without * @param {string} timestamp of ISO8601Timestamp format without
* dashes or colons, e.g. 20160202T220410Z * dashes or colons, e.g. 20160202T220410Z
* @return {number} number of milliseconds since Unix Epoch
*/ */
export function convertAmzTimeToMs(timestamp: string) { function convertAmzTimeToMs(timestamp) {
const arr = timestamp.split(''); const arr = timestamp.split('');
// Convert to YYYY-MM-DDTHH:mm:ss.sssZ // Convert to YYYY-MM-DDTHH:mm:ss.sssZ
const ISO8601time = `${arr.slice(0, 4).join('')}-${arr[4]}${arr[5]}` + const ISO8601time = `${arr.slice(0, 4).join('')}-${arr[4]}${arr[5]}` +
@ -14,12 +15,13 @@ export function convertAmzTimeToMs(timestamp: string) {
return Date.parse(ISO8601time); return Date.parse(ISO8601time);
} }
/** /**
* Convert UTC timestamp to ISO 8601 timestamp * Convert UTC timestamp to ISO 8601 timestamp
* @param timestamp of UTC form: Fri, 10 Feb 2012 21:34:55 GMT * @param {string} timestamp of UTC form: Fri, 10 Feb 2012 21:34:55 GMT
* @return ISO8601 timestamp of form: YYYYMMDDTHHMMSSZ * @return {string} ISO8601 timestamp of form: YYYYMMDDTHHMMSSZ
*/ */
export function convertUTCtoISO8601(timestamp: string | number) { function convertUTCtoISO8601(timestamp) {
// convert to ISO string: YYYY-MM-DDTHH:mm:ss.sssZ. // convert to ISO string: YYYY-MM-DDTHH:mm:ss.sssZ.
const converted = new Date(timestamp).toISOString(); const converted = new Date(timestamp).toISOString();
// Remove "-"s and "."s and milliseconds // Remove "-"s and "."s and milliseconds
@ -28,13 +30,13 @@ export function convertUTCtoISO8601(timestamp: string | number) {
/** /**
* Check whether timestamp predates request or is too old * Check whether timestamp predates request or is too old
* @param timestamp of ISO8601Timestamp format without * @param {string} timestamp of ISO8601Timestamp format without
* dashes or colons, e.g. 20160202T220410Z * dashes or colons, e.g. 20160202T220410Z
* @param expiry - number of seconds signature should be valid * @param {number} expiry - number of seconds signature should be valid
* @param log - log for request * @param {object} log - log for request
* @return true if there is a time problem * @return {boolean} true if there is a time problem
*/ */
export function checkTimeSkew(timestamp: string, expiry: number, log: Logger) { function checkTimeSkew(timestamp, expiry, log) {
const currentTime = Date.now(); const currentTime = Date.now();
const fifteenMinutes = (15 * 60 * 1000); const fifteenMinutes = (15 * 60 * 1000);
const parsedTimestamp = convertAmzTimeToMs(timestamp); const parsedTimestamp = convertAmzTimeToMs(timestamp);
@ -54,3 +56,5 @@ export function checkTimeSkew(timestamp: string, expiry: number, log: Logger) {
} }
return false; return false;
} }
module.exports = { convertAmzTimeToMs, convertUTCtoISO8601, checkTimeSkew };

View File

@ -1,19 +1,17 @@
import { Logger } from 'werelogs'; 'use strict'; // eslint-disable-line strict
import errors from '../../../lib/errors';
const errors = require('../../../lib/errors');
/** /**
* Validate Credentials * Validate Credentials
* @param credentials - contains accessKey, scopeDate, * @param {array} credentials - contains accessKey, scopeDate,
* region, service, requestType * region, service, requestType
* @param timestamp - timestamp from request in * @param {string} timestamp - timestamp from request in
* the format of ISO 8601: YYYYMMDDTHHMMSSZ * the format of ISO 8601: YYYYMMDDTHHMMSSZ
* @param log - logging object * @param {object} log - logging object
* @return {boolean} true if credentials are correct format, false if not
*/ */
export function validateCredentials( function validateCredentials(credentials, timestamp, log) {
credentials: [string, string, string, string, string],
timestamp: string,
log: Logger
): Error | {} {
if (!Array.isArray(credentials) || credentials.length !== 5) { if (!Array.isArray(credentials) || credentials.length !== 5) {
log.warn('credentials in improper format', { credentials }); log.warn('credentials in improper format', { credentials });
return errors.InvalidArgument; return errors.InvalidArgument;
@ -60,21 +58,12 @@ export function validateCredentials(
/** /**
* Extract and validate components from query object * Extract and validate components from query object
* @param queryObj - query object from request * @param {object} queryObj - query object from request
* @param log - logging object * @param {object} log - logging object
* @return object containing extracted query params for authV4 * @return {object} object containing extracted query params for authV4
*/ */
export function extractQueryParams( function extractQueryParams(queryObj, log) {
queryObj: { [key: string]: string | undefined }, const authParams = {};
log: Logger
) {
const authParams: {
signedHeaders?: string;
signatureFromRequest?: string;
timestamp?: string;
expiry?: number;
credential?: [string, string, string, string, string];
} = {};
// Do not need the algorithm sent back // Do not need the algorithm sent back
if (queryObj['X-Amz-Algorithm'] !== 'AWS4-HMAC-SHA256') { if (queryObj['X-Amz-Algorithm'] !== 'AWS4-HMAC-SHA256') {
@ -110,7 +99,7 @@ export function extractQueryParams(
return authParams; return authParams;
} }
const expiry = Number.parseInt(queryObj['X-Amz-Expires'] ?? 'nope', 10); const expiry = Number.parseInt(queryObj['X-Amz-Expires'], 10);
const sevenDays = 604800; const sevenDays = 604800;
if (expiry && (expiry > 0 && expiry <= sevenDays)) { if (expiry && (expiry > 0 && expiry <= sevenDays)) {
authParams.expiry = expiry; authParams.expiry = expiry;
@ -121,7 +110,6 @@ export function extractQueryParams(
const credential = queryObj['X-Amz-Credential']; const credential = queryObj['X-Amz-Credential'];
if (credential && credential.length > 28 && credential.indexOf('/') > -1) { if (credential && credential.length > 28 && credential.indexOf('/') > -1) {
// @ts-ignore
authParams.credential = credential.split('/'); authParams.credential = credential.split('/');
} else { } else {
log.warn('invalid credential param', { credential }); log.warn('invalid credential param', { credential });
@ -133,17 +121,14 @@ export function extractQueryParams(
/** /**
* Extract and validate components from auth header * Extract and validate components from auth header
* @param authHeader - authorization header from request * @param {string} authHeader - authorization header from request
* @param log - logging object * @param {object} log - logging object
* @return object containing extracted auth header items for authV4 * @return {object} object containing extracted auth header items for authV4
*/ */
export function extractAuthItems(authHeader: string, log: Logger) { function extractAuthItems(authHeader, log) {
const authItems: { const authItems = {};
credentialsArr?: [string, string, string, string, string]; const authArray = authHeader
signedHeaders?: string; .replace('AWS4-HMAC-SHA256 ', '').split(',');
signatureFromRequest?: string;
} = {};
const authArray = authHeader.replace('AWS4-HMAC-SHA256 ', '').split(',');
if (authArray.length < 3) { if (authArray.length < 3) {
return authItems; return authItems;
@ -153,12 +138,8 @@ export function extractAuthItems(authHeader: string, log: Logger) {
const signedHeadersStr = authArray[1]; const signedHeadersStr = authArray[1];
const signatureStr = authArray[2]; const signatureStr = authArray[2];
log.trace('credentials from request', { credentialStr }); log.trace('credentials from request', { credentialStr });
if ( if (credentialStr && credentialStr.trim().startsWith('Credential=')
credentialStr && && credentialStr.indexOf('/') > -1) {
credentialStr.trim().startsWith('Credential=') &&
credentialStr.indexOf('/') > -1
) {
// @ts-ignore
authItems.credentialsArr = credentialStr authItems.credentialsArr = credentialStr
.trim().replace('Credential=', '').split('/'); .trim().replace('Credential=', '').split('/');
} else { } else {
@ -185,11 +166,11 @@ export function extractAuthItems(authHeader: string, log: Logger) {
/** /**
* Checks whether the signed headers include the host header * Checks whether the signed headers include the host header
* and all x-amz- and x-scal- headers in request * and all x-amz- and x-scal- headers in request
* @param signedHeaders - signed headers sent with request * @param {string} signedHeaders - signed headers sent with request
* @param allHeaders - request.headers * @param {object} allHeaders - request.headers
* @return true if all x-amz-headers included and false if not * @return {boolean} true if all x-amz-headers included and false if not
*/ */
export function areSignedHeadersComplete(signedHeaders: string, allHeaders: Headers) { function areSignedHeadersComplete(signedHeaders, allHeaders) {
const signedHeadersList = signedHeaders.split(';'); const signedHeadersList = signedHeaders.split(';');
if (signedHeadersList.indexOf('host') === -1) { if (signedHeadersList.indexOf('host') === -1) {
return false; return false;
@ -204,3 +185,6 @@ export function areSignedHeadersComplete(signedHeaders: string, allHeaders: Head
} }
return true; return true;
} }
module.exports = { validateCredentials, extractQueryParams,
areSignedHeadersComplete, extractAuthItems };

View File

@ -1,4 +1,6 @@
export const ciphers = [ 'use strict'; // eslint-disable-line strict
const ciphers = [
'DHE-RSA-AES128-GCM-SHA256', 'DHE-RSA-AES128-GCM-SHA256',
'ECDHE-ECDSA-AES128-GCM-SHA256', 'ECDHE-ECDSA-AES128-GCM-SHA256',
'ECDHE-RSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES256-GCM-SHA384',
@ -26,3 +28,7 @@ export const ciphers = [
'!EDH-RSA-DES-CBC3-SHA', '!EDH-RSA-DES-CBC3-SHA',
'!KRB5-DES-CBC3-SHA', '!KRB5-DES-CBC3-SHA',
].join(':'); ].join(':');
module.exports = {
ciphers,
};

View File

@ -29,11 +29,16 @@ c2CNfUEqyRbJF4pE9ZcdQReT5p/llmyhQdvq6cHH+cKJk63C6DHRVoStsnsUcvKe
bLxKsygK77ttjr61cxLoDJeGd5L5h1CPmwIBAg== bLxKsygK77ttjr61cxLoDJeGd5L5h1CPmwIBAg==
-----END DH PARAMETERS----- -----END DH PARAMETERS-----
*/ */
'use strict'; // eslint-disable-line strict
export const dhparam = const dhparam =
'MIIBCAKCAQEAh99T77KGNuiY9N6xrCJ3QNv4SFADTa3CD+1VMTAdRJLHUNpglB+i' + 'MIIBCAKCAQEAh99T77KGNuiY9N6xrCJ3QNv4SFADTa3CD+1VMTAdRJLHUNpglB+i' +
'AoTYiLDFZgtTCpx0ZZUD+JM3qiCZy0OK5/ZGlVD7sZmxjRtdpVK4qIPtwav8t0J7' + 'AoTYiLDFZgtTCpx0ZZUD+JM3qiCZy0OK5/ZGlVD7sZmxjRtdpVK4qIPtwav8t0J7' +
'c2CNfUEqyRbJF4pE9ZcdQReT5p/llmyhQdvq6cHH+cKJk63C6DHRVoStsnsUcvKe' + 'c2CNfUEqyRbJF4pE9ZcdQReT5p/llmyhQdvq6cHH+cKJk63C6DHRVoStsnsUcvKe' +
'23PLGZulKg8H3eRBxHamHkmyuEVDtoNhMIoJONsdXSpo5GgcD4EQMM8xb/qsnCxn' + '23PLGZulKg8H3eRBxHamHkmyuEVDtoNhMIoJONsdXSpo5GgcD4EQMM8xb/qsnCxn' +
'6QIGTBvcHskxtlTZOfUPk4XQ6Yb3tQi2TurzkQHLln4U7p/GZs+D+6D3SgSPqr6P' + '6QIGTBvcHskxtlTZOfUPk4XQ6Yb3tQi2TurzkQHLln4U7p/GZs+D+6D3SgSPqr6P' +
'bLxKsygK77ttjr61cxLoDJeGd5L5h1CPmwIBAg=='; 'bLxKsygK77ttjr61cxLoDJeGd5L5h1CPmwIBAg==';
module.exports = {
dhparam,
};

View File

@ -1,2 +0,0 @@
export * as ciphers from './ciphers'
export * as dhparam from './dh2048'

View File

@ -2,7 +2,7 @@
const assert = require('assert'); const assert = require('assert');
const AuthInfo = require('../../../lib/auth/AuthInfo').default; const AuthInfo = require('../../../lib/auth/AuthInfo');
const constants = require('../../../lib/constants'); const constants = require('../../../lib/constants');
const arn = 'arn:aws:iam::123456789012:user/Fred'; const arn = 'arn:aws:iam::123456789012:user/Fred';

View File

@ -1,6 +1,6 @@
const assert = require('assert'); const assert = require('assert');
const Indexer = require('../../../../lib/auth/in_memory/Indexer').default; const Indexer = require('../../../../lib/auth/in_memory/Indexer');
const ref = require('./sample_authdata.json'); const ref = require('./sample_authdata.json');
const { should } = require('./AuthLoader.spec'); const { should } = require('./AuthLoader.spec');

View File

@ -3,9 +3,9 @@
const assert = require('assert'); const assert = require('assert');
const getCanonicalizedAmzHeaders = const getCanonicalizedAmzHeaders =
require('../../../../lib/auth/v2/getCanonicalizedAmzHeaders').default; require('../../../../lib/auth/v2/getCanonicalizedAmzHeaders');
const getCanonicalizedResource = const getCanonicalizedResource =
require('../../../../lib/auth/v2/getCanonicalizedResource').default; require('../../../../lib/auth/v2/getCanonicalizedResource');
const getCanonicalizedGcpHeaders = headers => const getCanonicalizedGcpHeaders = headers =>
getCanonicalizedAmzHeaders(headers, 'GCP'); getCanonicalizedAmzHeaders(headers, 'GCP');

View File

@ -3,7 +3,7 @@
const assert = require('assert'); const assert = require('assert');
const checkRequestExpiry = const checkRequestExpiry =
require('../../../../lib/auth/v2/checkRequestExpiry').default; require('../../../../lib/auth/v2/checkRequestExpiry');
const DummyRequestLogger = require('../../helpers').DummyRequestLogger; const DummyRequestLogger = require('../../helpers').DummyRequestLogger;
const errors = require('../../../../index').errors; const errors = require('../../../../index').errors;

View File

@ -3,7 +3,7 @@
const assert = require('assert'); const assert = require('assert');
const constructStringToSign = const constructStringToSign =
require('../../../../lib/auth/v2/constructStringToSign').default; require('../../../../lib/auth/v2/constructStringToSign');
const DummyRequestLogger = require('../../helpers').DummyRequestLogger; const DummyRequestLogger = require('../../helpers').DummyRequestLogger;
const log = new DummyRequestLogger(); const log = new DummyRequestLogger();

View File

@ -4,7 +4,7 @@ const assert = require('assert');
const errors = require('../../../../lib/errors'); const errors = require('../../../../lib/errors');
const auth = require('../../../../lib/auth/auth').server.doAuth; const auth = require('../../../../lib/auth/auth').server.doAuth;
const AuthInfo = require('../../../../lib/auth/AuthInfo').default; const AuthInfo = require('../../../../lib/auth/AuthInfo');
const constants = require('../../../../lib/constants'); const constants = require('../../../../lib/constants');
const DummyRequestLogger = require('../../helpers.js').DummyRequestLogger; const DummyRequestLogger = require('../../helpers.js').DummyRequestLogger;
const RequestContext = const RequestContext =

View File

@ -3,7 +3,7 @@
const assert = require('assert'); const assert = require('assert');
const constructStringToSign = const constructStringToSign =
require('../../../../lib/auth/v2/constructStringToSign').default; require('../../../../lib/auth/v2/constructStringToSign');
const hashSignature = const hashSignature =
require('../../../../lib/auth/in_memory/vaultUtilities').hashSignature; require('../../../../lib/auth/in_memory/vaultUtilities').hashSignature;
const DummyRequestLogger = require('../../helpers').DummyRequestLogger; const DummyRequestLogger = require('../../helpers').DummyRequestLogger;

View File

@ -2,7 +2,7 @@
const assert = require('assert'); const assert = require('assert');
const awsURIencode = require('../../../../lib/auth/v4/awsURIencode').default; const awsURIencode = require('../../../../lib/auth/v4/awsURIencode');
// Note that expected outputs came from running node aws-sdk's // Note that expected outputs came from running node aws-sdk's
// AWS.util.uriEscapePath and AWS.util.uriEscape functions // AWS.util.uriEscapePath and AWS.util.uriEscape functions

View File

@ -3,7 +3,7 @@
const assert = require('assert'); const assert = require('assert');
const constructStringToSign = const constructStringToSign =
require('../../../../lib/auth/v4/constructStringToSign').default; require('../../../../lib/auth/v4/constructStringToSign');
const DummyRequestLogger = require('../../helpers').DummyRequestLogger; const DummyRequestLogger = require('../../helpers').DummyRequestLogger;
const log = new DummyRequestLogger(); const log = new DummyRequestLogger();

View File

@ -2,9 +2,9 @@
const assert = require('assert'); const assert = require('assert');
const awsURIencode = const awsURIencode =
require('../../../../lib/auth/v4/awsURIencode').default; require('../../../../lib/auth/v4/awsURIencode');
const createCanonicalRequest = const createCanonicalRequest =
require('../../../../lib/auth/v4/createCanonicalRequest').default; require('../../../../lib/auth/v4/createCanonicalRequest');
describe('createCanonicalRequest function', () => { describe('createCanonicalRequest function', () => {
// Example taken from: http://docs.aws.amazon.com/AmazonS3/ // Example taken from: http://docs.aws.amazon.com/AmazonS3/