Compare commits
10 Commits
892dee6c13
...
d90bc4f741
Author | SHA1 | Date |
---|---|---|
Anurag Mittal | d90bc4f741 | |
Anurag Mittal | b9dd7139ad | |
Anurag Mittal | 6543d9f88d | |
Anurag Mittal | 44efcd625c | |
Anurag Mittal | c6bb489ade | |
Anurag Mittal | 76c4c2b2bb | |
Anurag Mittal | d15d6f8a06 | |
Anurag Mittal | 8d40bab08f | |
Anurag Mittal | 24f6d8374e | |
Anurag Mittal | bb3b448757 |
|
@ -68,6 +68,12 @@ function extractParams(
|
|||
} = oTel;
|
||||
activeSpan?.addEvent('Arsenal:: entered Arsenal.auth.server.extractParams');
|
||||
return tracer.startActiveSpan('Check validity of request parameters to authenticate using Arsenal', undefined, activeTracerContext, extractParamsSpan => {
|
||||
extractParamsSpan.setAttributes({
|
||||
'code.lineno': 75,
|
||||
'code.filename': 'lib/auth/auth.ts',
|
||||
'code.function': 'extractParams',
|
||||
'code.url': 'https://github.com/scality/arsenal/blob/892dee6c1333fcc25c88333ee991f02830cb3c51/lib/auth/auth.ts',
|
||||
});
|
||||
log.trace('entered', { method: 'Arsenal.auth.server.extractParams' });
|
||||
const authHeader = request.headers.authorization;
|
||||
let version: 'v2' |'v4' | null = null;
|
||||
|
@ -108,8 +114,7 @@ function extractParams(
|
|||
activeSpan?.addEvent(`Arsenal:: Identified auth method version: ${version} and method: ${method}`);
|
||||
activeSpan?.addEvent('Arsenal:: Checking if valid request headers and query are used to make request to vault');
|
||||
log.trace('identified auth method', { version, authMethod: method });
|
||||
extractParamsSpan.end();
|
||||
return checkFunctions[version][method](request, log, data, awsService, { activeSpan, activeTracerContext, tracer });
|
||||
return checkFunctions[version][method](request, log, data, awsService, { activeSpan, extractParamsSpan, activeTracerContext, tracer });
|
||||
}
|
||||
|
||||
// no auth info identified
|
||||
|
|
|
@ -6,24 +6,20 @@ import checkRequestExpiry from './checkRequestExpiry';
|
|||
import algoCheck from './algoCheck';
|
||||
|
||||
export function check(request: any, log: Logger, data: { [key: string]: string }, oTel: any) {
|
||||
const { activeSpan, activeTracerContext, tracer } = oTel;
|
||||
const { activeSpan, extractParamsSpan, activeTracerContext, tracer } = oTel;
|
||||
activeSpan?.addEvent('Entered V2 header auth check');
|
||||
return tracer.startActiveSpan('V2 Header Auth Check', undefined, activeTracerContext, authCheckSpan => {
|
||||
log.trace('running header auth check');
|
||||
activeSpan?.addEvent('Running header auth check');
|
||||
|
||||
const headers = request.headers;
|
||||
|
||||
activeSpan?.addEvent('Extracting security token');
|
||||
const token = headers['x-amz-security-token'];
|
||||
if (token && !constants.iamSecurityToken.pattern.test(token)) {
|
||||
log.debug('invalid security token', { token });
|
||||
activeSpan.recordException(errors.InvalidToken);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.InvalidToken };
|
||||
}
|
||||
activeSpan?.addEvent('Extracted security token');
|
||||
|
||||
activeSpan?.addEvent('Checking timestamp');
|
||||
// Check to make sure timestamp is within 15 minutes of current time
|
||||
let timestamp = headers['x-amz-date'] ? headers['x-amz-date'] : headers.date;
|
||||
|
@ -31,68 +27,61 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
if (!timestamp) {
|
||||
log.debug('missing or invalid date header', { method: 'auth/v2/headerAuthCheck.check' });
|
||||
activeSpan.recordException(errors.AccessDenied.customizeDescription('Authentication requires a valid Date or x-amz-date header'));
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.AccessDenied.customizeDescription('Authentication requires a valid Date or x-amz-date header') };
|
||||
}
|
||||
activeSpan?.addEvent('Checked timestamp');
|
||||
|
||||
activeSpan?.addEvent('Checking request expiry');
|
||||
const err = checkRequestExpiry(timestamp, log);
|
||||
if (err) {
|
||||
activeSpan.recordException(err);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err };
|
||||
}
|
||||
activeSpan?.addEvent('Checked request expiry');
|
||||
|
||||
activeSpan?.addEvent('Extracting authorization header');
|
||||
// Authorization Header should be in the format of 'AWS AccessKey:Signature'
|
||||
const authInfo = headers.authorization;
|
||||
activeSpan?.addEvent('Extracted authorization header');
|
||||
|
||||
if (!authInfo) {
|
||||
log.debug('missing authorization security header');
|
||||
activeSpan.recordException(errors.MissingSecurityHeader);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.MissingSecurityHeader };
|
||||
}
|
||||
const semicolonIndex = authInfo.indexOf(':');
|
||||
if (semicolonIndex < 0) {
|
||||
log.debug('invalid authorization header', { authInfo });
|
||||
activeSpan.recordException(errors.InvalidArgument);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.InvalidArgument };
|
||||
}
|
||||
const accessKey = semicolonIndex > 4 ? authInfo.substring(4, semicolonIndex).trim() : undefined;
|
||||
if (typeof accessKey !== 'string' || accessKey.length === 0) {
|
||||
log.trace('invalid authorization header', { authInfo });
|
||||
activeSpan.recordException(errors.MissingSecurityHeader);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.MissingSecurityHeader };
|
||||
}
|
||||
// @ts-ignore
|
||||
log.addDefaultFields({ accessKey });
|
||||
|
||||
const signatureFromRequest = authInfo.substring(semicolonIndex + 1).trim();
|
||||
log.trace('signature from request', { signatureFromRequest });
|
||||
activeSpan?.addEvent('Extracting signature from request');
|
||||
|
||||
activeSpan?.addEvent('Constructing string to sign');
|
||||
const stringToSign = constructStringToSign(request, data, log);
|
||||
log.trace('constructed string to sign', { stringToSign });
|
||||
activeSpan?.addEvent('Constructed string to sign');
|
||||
|
||||
activeSpan?.addEvent('Constructed string to sign v2 headers');
|
||||
const algo = algoCheck(signatureFromRequest.length);
|
||||
log.trace('algo for calculating signature', { algo });
|
||||
activeSpan?.addEvent('Checked algorithm for calculating signature');
|
||||
|
||||
if (algo === undefined) {
|
||||
activeSpan.recordException(errors.InvalidArgument);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.InvalidArgument };
|
||||
}
|
||||
|
||||
activeSpan?.addEvent('Exiting V2 header auth check');
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return {
|
||||
err: null,
|
||||
params: {
|
||||
|
@ -109,6 +98,5 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -5,29 +5,25 @@ import algoCheck from './algoCheck';
|
|||
import constructStringToSign from './constructStringToSign';
|
||||
|
||||
export function check(request: any, log: Logger, data: { [key: string]: string }, oTel: any) {
|
||||
const { activeSpan, activeTracerContext, tracer } = oTel;
|
||||
const { activeSpan, extractParamsSpan, activeTracerContext, tracer } = oTel;
|
||||
activeSpan?.addEvent('Entered query auth check');
|
||||
return tracer.startActiveSpan('Query Auth Check', undefined, activeTracerContext, authCheckSpan => {
|
||||
log.trace('running query auth check');
|
||||
activeSpan?.addEvent('Running query auth check');
|
||||
|
||||
if (request.method === 'POST') {
|
||||
log.debug('query string auth not supported for post requests');
|
||||
activeSpan.recordException(errors.NotImplemented);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.NotImplemented };
|
||||
}
|
||||
|
||||
const token = data.SecurityToken;
|
||||
activeSpan?.addEvent('Extracting security token');
|
||||
if (token && !constants.iamSecurityToken.pattern.test(token)) {
|
||||
log.debug('invalid security token', { token });
|
||||
activeSpan.recordException(errors.InvalidToken);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.InvalidToken };
|
||||
}
|
||||
activeSpan?.addEvent('Extracted security token');
|
||||
|
||||
/*
|
||||
Check whether request has expired or if
|
||||
expires parameter is more than 604800000 milliseconds
|
||||
|
@ -41,62 +37,52 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
if (Number.isNaN(expirationTime)) {
|
||||
log.debug('invalid expires parameter', { expires: data.Expires });
|
||||
activeSpan.recordException(errors.MissingSecurityHeader);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.MissingSecurityHeader };
|
||||
}
|
||||
activeSpan?.addEvent('Checked expiration time');
|
||||
|
||||
const currentTime = Date.now();
|
||||
|
||||
const preSignedURLExpiry = process.env.PRE_SIGN_URL_EXPIRY
|
||||
&& !Number.isNaN(process.env.PRE_SIGN_URL_EXPIRY)
|
||||
? Number.parseInt(process.env.PRE_SIGN_URL_EXPIRY, 10)
|
||||
: constants.defaultPreSignedURLExpiry * 1000;
|
||||
|
||||
if (expirationTime > currentTime + preSignedURLExpiry) {
|
||||
log.debug('expires parameter too far in future', { expires: request.query.Expires });
|
||||
activeSpan.recordException(errors.AccessDenied);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.AccessDenied };
|
||||
}
|
||||
if (currentTime > expirationTime) {
|
||||
log.debug('current time exceeds expires time', { expires: request.query.Expires });
|
||||
activeSpan.recordException(errors.RequestTimeTooSkewed);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.RequestTimeTooSkewed };
|
||||
}
|
||||
|
||||
const accessKey = data.AWSAccessKeyId;
|
||||
// @ts-ignore
|
||||
log.addDefaultFields({ accessKey });
|
||||
|
||||
const signatureFromRequest = decodeURIComponent(data.Signature);
|
||||
log.trace('signature from request', { signatureFromRequest });
|
||||
activeSpan?.addEvent('Extracting signature from request');
|
||||
|
||||
if (!accessKey || !signatureFromRequest) {
|
||||
log.debug('invalid access key/signature parameters');
|
||||
activeSpan.recordException(errors.MissingSecurityHeader);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.MissingSecurityHeader };
|
||||
}
|
||||
|
||||
const stringToSign = constructStringToSign(request, data, log);
|
||||
log.trace('constructed string to sign', { stringToSign });
|
||||
activeSpan?.addEvent('Constructed string to sign');
|
||||
|
||||
activeSpan?.addEvent('Constructed string to sign v2 query');
|
||||
const algo = algoCheck(signatureFromRequest.length);
|
||||
log.trace('algo for calculating signature', { algo });
|
||||
activeSpan?.addEvent('Checked algorithm for calculating signature');
|
||||
|
||||
if (algo === undefined) {
|
||||
activeSpan.recordException(errors.InvalidArgument);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.InvalidArgument };
|
||||
}
|
||||
|
||||
activeSpan?.addEvent('Exiting query auth check');
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return {
|
||||
err: null,
|
||||
params: {
|
||||
|
@ -112,6 +98,5 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ export default function constructStringToSign(params: {
|
|||
log?: Logger;
|
||||
proxyPath?: string;
|
||||
awsService: string;
|
||||
}): string | Error {
|
||||
}, oTel?: any,): string | Error {
|
||||
const {
|
||||
request,
|
||||
signedHeaders,
|
||||
|
@ -29,7 +29,12 @@ export default function constructStringToSign(params: {
|
|||
proxyPath,
|
||||
} = params;
|
||||
const path = proxyPath || request.path;
|
||||
|
||||
const {
|
||||
activeSpan,
|
||||
activeTracerContext,
|
||||
tracer,
|
||||
} = oTel;
|
||||
activeSpan?.addEvent('Constructing canonical request for Authv4');
|
||||
const canonicalReqResult = createCanonicalRequest({
|
||||
pHttpVerb: request.method,
|
||||
pResource: path,
|
||||
|
@ -38,8 +43,7 @@ export default function constructStringToSign(params: {
|
|||
pSignedHeaders: signedHeaders,
|
||||
payloadChecksum,
|
||||
service: params.awsService,
|
||||
});
|
||||
|
||||
}, oTel);
|
||||
// TODO Why that line?
|
||||
// @ts-ignore
|
||||
if (canonicalReqResult instanceof Error) {
|
||||
|
@ -51,9 +55,13 @@ export default function constructStringToSign(params: {
|
|||
if (log) {
|
||||
log.debug('constructed canonicalRequest', { canonicalReqResult });
|
||||
}
|
||||
const createSignatureSpan = tracer.startSpan('Creating signature hash for AuthV4 using crypto sha256');
|
||||
activeSpan?.addEvent('Creating signature hash for AuthV4 using crypto sha256');
|
||||
const sha256 = crypto.createHash('sha256');
|
||||
const canonicalHex = sha256.update(canonicalReqResult, 'binary')
|
||||
.digest('hex');
|
||||
activeSpan?.addEvent('Created signature hash for AuthV4 using crypto sha256');
|
||||
createSignatureSpan.end();
|
||||
const stringToSign = `AWS4-HMAC-SHA256\n${timestamp}\n` +
|
||||
`${credentialScope}\n${canonicalHex}`;
|
||||
return stringToSign;
|
||||
|
|
|
@ -19,8 +19,16 @@ export default function createCanonicalRequest(
|
|||
pSignedHeaders: any;
|
||||
service: string;
|
||||
payloadChecksum: string;
|
||||
}
|
||||
},
|
||||
oTel?: any,
|
||||
) {
|
||||
const {
|
||||
activeSpan,
|
||||
activeTracerContext,
|
||||
tracer,
|
||||
} = oTel;
|
||||
activeSpan?.addEvent('Entered createCanonicalRequest');
|
||||
|
||||
const pHttpVerb = params.pHttpVerb;
|
||||
const pResource = params.pResource;
|
||||
const pQuery = params.pQuery;
|
||||
|
@ -28,35 +36,34 @@ export default function createCanonicalRequest(
|
|||
const pSignedHeaders = params.pSignedHeaders;
|
||||
const service = params.service;
|
||||
let payloadChecksum = params.payloadChecksum;
|
||||
|
||||
const payloadChecksumSpan = tracer.startSpan('ComputePayloadChecksum');
|
||||
if (!payloadChecksum) {
|
||||
if (pHttpVerb === 'GET') {
|
||||
payloadChecksum = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b' +
|
||||
'934ca495991b7852b855';
|
||||
} else if (pHttpVerb === 'POST') {
|
||||
let notEncodeStar = false;
|
||||
// The java sdk does not encode the '*' parameter to compute the
|
||||
// signature, if the user-agent is recognized, we need to keep
|
||||
// the plain '*' as well.
|
||||
if (/aws-sdk-java\/[0-9.]+/.test(pHeaders['user-agent'])) {
|
||||
notEncodeStar = true;
|
||||
}
|
||||
let payload = queryString.stringify(pQuery, undefined, undefined, {
|
||||
encodeURIComponent: input => awsURIencode(input, true,
|
||||
notEncodeStar),
|
||||
encodeURIComponent: input => awsURIencode(input, true, notEncodeStar),
|
||||
});
|
||||
payload = payload.replace(/%20/g, '+');
|
||||
payloadChecksum = crypto.createHash('sha256')
|
||||
.update(payload, 'binary').digest('hex').toLowerCase();
|
||||
}
|
||||
}
|
||||
payloadChecksumSpan.end();
|
||||
|
||||
const canonicalURISpan = tracer.startSpan('ComputeCanonicalURI');
|
||||
const canonicalURI = !!pResource ? awsURIencode(pResource, false) : '/';
|
||||
canonicalURISpan.end();
|
||||
|
||||
// canonical query string
|
||||
const canonicalQueryStrSpan = tracer.startSpan('ComputeCanonicalQueryStr');
|
||||
let canonicalQueryStr = '';
|
||||
if (pQuery && !((service === 'iam' || service === 'ring' ||
|
||||
service === 'sts') &&
|
||||
pHttpVerb === 'POST')) {
|
||||
if (pQuery && !((service === 'iam' || service === 'ring' || service === 'sts') && pHttpVerb === 'POST')) {
|
||||
const sortedQueryParams = Object.keys(pQuery).sort().map(key => {
|
||||
const encodedKey = awsURIencode(key);
|
||||
const value = pQuery[key] ? awsURIencode(pQuery[key]) : '';
|
||||
|
@ -64,32 +71,54 @@ export default function createCanonicalRequest(
|
|||
});
|
||||
canonicalQueryStr = sortedQueryParams.join('&');
|
||||
}
|
||||
canonicalQueryStrSpan.end();
|
||||
|
||||
// signed headers
|
||||
const signedHeadersSpan = tracer.startSpan('SortSignedHeadersAlphabetically');
|
||||
activeSpan?.addEvent('Splitting signed headers using deliminator: ;');
|
||||
const signedHeadersList = pSignedHeaders.split(';');
|
||||
activeSpan?.addEvent('Split signed headers using ; as deliminator');
|
||||
activeSpan?.addEvent('Sorting signed headers alphabetically');
|
||||
signedHeadersList.sort((a: any, b: any) => a.localeCompare(b));
|
||||
activeSpan?.addEvent('Sorted signed headers alphabetically');
|
||||
activeSpan?.addEvent('Joining signed headers using deliminator: ;');
|
||||
const signedHeaders = signedHeadersList.join(';');
|
||||
activeSpan?.addEvent('Joined signed headers using ; as deliminator');
|
||||
activeSpan.setAttributes({
|
||||
'signedHeaders.request': pSignedHeaders,
|
||||
'signedHeaders.request.authv4': signedHeaders,
|
||||
});
|
||||
signedHeadersSpan.setAttributes({
|
||||
'signedHeaders.request': pSignedHeaders,
|
||||
'signedHeaders.request.authv4': signedHeaders,
|
||||
'code.url': 'https://github.com/scality/arsenal/blob/c6bb489adeb7419fdbcdf01db2b46a593747530d/lib/auth/v4/createCanonicalRequest.ts#L76',
|
||||
'code.function': 'createCanonicalRequest',
|
||||
'code.lineno': 76,
|
||||
'code.filename': 'lib/auth/v4/createCanonicalRequest.ts',
|
||||
});
|
||||
signedHeadersSpan.end();
|
||||
|
||||
// canonical headers
|
||||
const canonicalHeadersListSpan = tracer.startSpan('FormatHeadersToMatch CanonicalHeadersList');
|
||||
const canonicalHeadersList = signedHeadersList.map((signedHeader: any) => {
|
||||
if (pHeaders[signedHeader] !== undefined) {
|
||||
const trimmedHeader = pHeaders[signedHeader]
|
||||
.trim().replace(/\s+/g, ' ');
|
||||
return `${signedHeader}:${trimmedHeader}\n`;
|
||||
}
|
||||
// nginx will strip the actual expect header so add value of
|
||||
// header back here if it was included as a signed header
|
||||
if (signedHeader === 'expect') {
|
||||
return `${signedHeader}:100-continue\n`;
|
||||
}
|
||||
// handle case where signed 'header' is actually query param
|
||||
return `${signedHeader}:${pQuery[signedHeader]}\n`;
|
||||
});
|
||||
canonicalHeadersListSpan.end();
|
||||
|
||||
const canonicalHeadersSpan = tracer.startSpan('JoinAllCanonicalHeaders using no deliminator');
|
||||
const canonicalHeaders = canonicalHeadersList.join('');
|
||||
canonicalHeadersSpan.end();
|
||||
|
||||
const canonicalRequestSpan = tracer.startSpan('ConstructCanonicalRequest');
|
||||
const canonicalRequest = `${pHttpVerb}\n${canonicalURI}\n` +
|
||||
`${canonicalQueryStr}\n${canonicalHeaders}\n` +
|
||||
`${signedHeaders}\n${payloadChecksum}`;
|
||||
canonicalRequestSpan.end();
|
||||
return canonicalRequest;
|
||||
}
|
||||
|
|
|
@ -22,46 +22,41 @@ import {
|
|||
* @param awsService - Aws service ('iam' or 's3')
|
||||
*/
|
||||
export function check(request: any, log: Logger, data: { [key: string]: string }, awsService: string, oTel: any) {
|
||||
const { activeSpan, activeTracerContext, tracer } = oTel;
|
||||
const { activeSpan, extractParamsSpan, activeTracerContext, tracer } = oTel;
|
||||
activeSpan?.addEvent('Entered V4 header auth check');
|
||||
return tracer.startActiveSpan('V4 Header Auth Check', undefined, activeTracerContext, authCheckSpan => {
|
||||
log.trace('running header auth check');
|
||||
|
||||
activeSpan?.addEvent('Extracting security token');
|
||||
const token = request.headers['x-amz-security-token'];
|
||||
if (token && !constants.iamSecurityToken.pattern.test(token)) {
|
||||
log.debug('invalid security token', { token });
|
||||
activeSpan.recordException(errors.InvalidToken);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.InvalidToken };
|
||||
}
|
||||
activeSpan?.addEvent('Extracted security token');
|
||||
|
||||
activeSpan?.addEvent('Extracting authorization header');
|
||||
const authHeader = request.headers.authorization;
|
||||
if (!authHeader) {
|
||||
log.debug('missing authorization header');
|
||||
activeSpan.recordException(errors.MissingSecurityHeader);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.MissingSecurityHeader };
|
||||
}
|
||||
activeSpan?.addEvent('Extracted authorization header');
|
||||
|
||||
activeSpan?.addEvent('Extracting auth header items');
|
||||
const authHeaderItems = extractAuthItems(authHeader, log);
|
||||
if (Object.keys(authHeaderItems).length < 3) {
|
||||
log.debug('invalid authorization header', { authHeader });
|
||||
activeSpan.recordException(errors.InvalidArgument);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.InvalidArgument };
|
||||
}
|
||||
activeSpan?.addEvent('Extracted auth header items');
|
||||
|
||||
const payloadChecksum = request.headers['x-amz-content-sha256'];
|
||||
if (!payloadChecksum && awsService !== 'iam') {
|
||||
log.debug('missing payload checksum');
|
||||
activeSpan.recordException(errors.MissingSecurityHeader);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.MissingSecurityHeader };
|
||||
}
|
||||
if (payloadChecksum === 'STREAMING-AWS4-HMAC-SHA256-PAYLOAD') {
|
||||
|
@ -69,31 +64,27 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
if (request.method !== 'PUT') {
|
||||
log.debug('streaming v4 auth for put only', { method: 'auth/v4/headerAuthCheck.check' });
|
||||
activeSpan.recordException(errors.InvalidArgument);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.InvalidArgument };
|
||||
}
|
||||
if (!request.headers['x-amz-decoded-content-length']) {
|
||||
activeSpan.recordException(errors.MissingSecurityHeader);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.MissingSecurityHeader };
|
||||
}
|
||||
}
|
||||
|
||||
log.trace('authorization header from request', { authHeader });
|
||||
|
||||
const signatureFromRequest = authHeaderItems.signatureFromRequest!;
|
||||
const credentialsArr = authHeaderItems.credentialsArr!;
|
||||
const signedHeaders = authHeaderItems.signedHeaders!;
|
||||
|
||||
activeSpan.addEvent('Checking if signed headers are complete');
|
||||
if (!areSignedHeadersComplete(signedHeaders, request.headers)) {
|
||||
log.debug('signedHeaders are incomplete', { signedHeaders });
|
||||
activeSpan.recordException(errors.AccessDenied);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.AccessDenied };
|
||||
}
|
||||
activeSpan.addEvent('Signed headers are complete');
|
||||
|
||||
let timestamp: string | undefined;
|
||||
// check request timestamp
|
||||
activeSpan.addEvent('Checking request timestamp');
|
||||
|
@ -111,17 +102,16 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
if (!timestamp) {
|
||||
log.debug('missing or invalid date header', { method: 'auth/v4/headerAuthCheck.check' });
|
||||
activeSpan.recordException(errors.AccessDenied.customizeDescription('Authentication requires a valid Date or x-amz-date header'));
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.AccessDenied.customizeDescription('Authentication requires a valid Date or x-amz-date header') };
|
||||
}
|
||||
activeSpan.addEvent('Request timestamp is valid');
|
||||
|
||||
activeSpan.addEvent('Validating credentials');
|
||||
const validationResult = validateCredentials(credentialsArr, timestamp, log);
|
||||
if (validationResult instanceof Error) {
|
||||
log.debug('credentials in improper format', { credentialsArr, timestamp, validationResult });
|
||||
activeSpan.recordException(validationResult);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: validationResult };
|
||||
}
|
||||
activeSpan.addEvent('Credentials are valid');
|
||||
|
@ -131,7 +121,6 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
const service = credentialsArr[3];
|
||||
const accessKey = credentialsArr.shift();
|
||||
const credentialScope = credentialsArr.join('/');
|
||||
|
||||
// In AWS Signature Version 4, the signing key is valid for up to seven days
|
||||
// (see Introduction to Signing Requests.
|
||||
// Therefore, a signature is also valid for up to seven days or
|
||||
|
@ -143,18 +132,16 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
// TODO: When implementing bucket policies,
|
||||
// note that expiration can be shortened so
|
||||
// expiry is as set out in the policy.
|
||||
|
||||
// 15 minutes in seconds
|
||||
activeSpan.addEvent('checking if signature is expired')
|
||||
const expiry = (15 * 60);
|
||||
const isTimeSkewed = checkTimeSkew(timestamp, expiry, log);
|
||||
if (isTimeSkewed) {
|
||||
activeSpan.recordException(errors.RequestTimeTooSkewed);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.RequestTimeTooSkewed };
|
||||
}
|
||||
activeSpan.addEvent('signature is not expired');
|
||||
|
||||
activeSpan.addEvent('Constructing string to sign');
|
||||
const stringToSign = constructStringToSign({
|
||||
log,
|
||||
|
@ -165,18 +152,16 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
timestamp,
|
||||
payloadChecksum,
|
||||
awsService: service,
|
||||
});
|
||||
}, oTel);
|
||||
log.trace('constructed stringToSign', { stringToSign });
|
||||
if (stringToSign instanceof Error) {
|
||||
activeSpan.recordException(stringToSign);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: stringToSign };
|
||||
}
|
||||
|
||||
activeSpan.addEvent('Constructed string to sign');
|
||||
|
||||
activeSpan.addEvent('Constructed string to sign v4 headers');
|
||||
activeSpan.addEvent('Exiting V4 header auth check');
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return {
|
||||
err: null,
|
||||
params: {
|
||||
|
@ -197,6 +182,5 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -15,17 +15,17 @@ import { areSignedHeadersComplete } from './validateInputs';
|
|||
export function check(request: any, log: Logger, data: { [key: string]: string }, oTel: any) {
|
||||
const {
|
||||
activeSpan,
|
||||
extractParamsSpan,
|
||||
activeTracerContext,
|
||||
tracer,
|
||||
} = oTel;
|
||||
activeSpan?.addEvent('Arsenal:: entered Arsenal.auth.v4.queryAuthCheck');
|
||||
return tracer.startActiveSpan('Arsenal::Arsenal.auth.v4.queryAuthCheck', undefined, activeTracerContext, authCheckSpan => {
|
||||
activeSpan?.addEvent('Arsenal:: extracting query parameters')
|
||||
const authParams = extractQueryParams(data, log);
|
||||
activeSpan?.addEvent('Arsenal:: extracting query params');
|
||||
if (Object.keys(authParams).length !== 5) {
|
||||
activeSpan.recordException(errors.InvalidArgument);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.InvalidArgument };
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
if (token && !constants.iamSecurityToken.pattern.test(token)) {
|
||||
log.debug('invalid security token', { token });
|
||||
activeSpan.recordException(errors.InvalidToken);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.InvalidToken };
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
if (!areSignedHeadersComplete(signedHeaders, request.headers)) {
|
||||
log.debug('signedHeaders are incomplete', { signedHeaders });
|
||||
activeSpan.recordException(errors.AccessDenied);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.AccessDenied };
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
log.debug('credentials in improper format', { credential,
|
||||
timestamp, validationResult });
|
||||
activeSpan.recordException(validationResult);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: validationResult };
|
||||
}
|
||||
const accessKey = credential[0];
|
||||
|
@ -70,7 +70,7 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
const isTimeSkewed = checkTimeSkew(timestamp, expiry, log);
|
||||
if (isTimeSkewed) {
|
||||
activeSpan.recordException(errors.RequestTimeTooSkewed);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: errors.RequestTimeTooSkewed };
|
||||
}
|
||||
|
||||
|
@ -89,6 +89,7 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
// building string to sign
|
||||
const payloadChecksum = 'UNSIGNED-PAYLOAD';
|
||||
|
||||
activeSpan?.addEvent('Constructing string to sign');
|
||||
const stringToSign = constructStringToSign({
|
||||
log,
|
||||
request,
|
||||
|
@ -99,15 +100,16 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
credentialScope:
|
||||
`${scopeDate}/${region}/${service}/${requestType}`,
|
||||
awsService: service,
|
||||
});
|
||||
}, oTel);
|
||||
activeSpan?.addEvent('Constructed string to sign v4 query');
|
||||
if (stringToSign instanceof Error) {
|
||||
activeSpan.recordException(stringToSign);
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return { err: stringToSign };
|
||||
}
|
||||
log.trace('constructed stringToSign', { stringToSign });
|
||||
activeSpan.addEvent('Arsenal:: exiting Arsenal.auth.v4.queryAuthCheck');
|
||||
authCheckSpan.end();
|
||||
extractParamsSpan.end();
|
||||
return {
|
||||
err: null,
|
||||
params: {
|
||||
|
@ -125,5 +127,4 @@ export function check(request: any, log: Logger, data: { [key: string]: string }
|
|||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -23,11 +23,6 @@ export default function routerGET(
|
|||
} = dataRetrievalParams;
|
||||
return tracer.startActiveSpan('Arsenal:: Performing Get API related operations using Cloudserver, Vault and Metadata', undefined, activeTracerContext, cloudserverApiSpan => {
|
||||
activeSpan.addEvent('Request validated, routing request using routeGET() in arsenal');
|
||||
cloudserverApiSpan.setAttributes({
|
||||
'code.lineno': 9,
|
||||
'code.filename': 'lib/s3routes/routes/routeGET.ts',
|
||||
'code.function': 'routerGET()',
|
||||
})
|
||||
activeSpan.addEvent('Detecting which API to route to using arsenal routeGET()')
|
||||
log.debug('routing request', { method: 'routerGET' });
|
||||
|
||||
|
|
|
@ -638,7 +638,7 @@ export function responseStreamData(
|
|||
},
|
||||
} = retrieveDataParams;
|
||||
activeSpan.addEvent('Request processed, getting Data from sproxyd');
|
||||
return tracer.startActiveSpan('Getting Data From RING', undefined, activeTracerContext, sproxydSpan => {
|
||||
return tracer.startActiveSpan('Getting Object Data from RING', undefined, activeTracerContext, sproxydSpan => {
|
||||
sproxydSpan.setAttributes({
|
||||
'code.function': 'Arsenal:: responseStreamData()',
|
||||
'code.filepath': 'lib/s3routes/routesUtils.js',
|
||||
|
|
Loading…
Reference in New Issue