From 383e8a42c874e51246a725c57cb3451cffd60684 Mon Sep 17 00:00:00 2001 From: Will Toozs Date: Tue, 4 Jun 2024 12:39:31 +0200 Subject: [PATCH 1/3] ARSN-414: accomodate POST object for auth --- lib/auth/auth.ts | 18 ++- lib/auth/v4/authV4.ts | 1 + lib/auth/v4/formAuthCheck.ts | 186 +++++++++++++++++++++++++++++++ lib/auth/v4/validateInputs.ts | 67 +++++++++++ lib/s3routes/routes/routePOST.ts | 4 + 5 files changed, 274 insertions(+), 2 deletions(-) create mode 100644 lib/auth/v4/formAuthCheck.ts diff --git a/lib/auth/auth.ts b/lib/auth/auth.ts index 3344cd69e..ac47f42ec 100644 --- a/lib/auth/auth.ts +++ b/lib/auth/auth.ts @@ -21,10 +21,13 @@ const checkFunctions = { v2: { headers: v2.header.check, query: v2.query.check, + // TODO ARSN-414 check v2 auth for POST requests with form data + // form: v2.form.check, }, v4: { headers: v4.header.check, query: v4.query.check, + form: v4.form.check, }, }; @@ -63,7 +66,7 @@ function extractParams( log.trace('entered', { method: 'Arsenal.auth.server.extractParams' }); const authHeader = request.headers.authorization; let version: 'v2' |'v4' | null = null; - let method: 'query' | 'headers' | null = null; + let method: 'query' | 'headers' | 'form' | null = null; // Identify auth version and method to dispatch to the right check function if (authHeader) { @@ -85,6 +88,16 @@ function extractParams( } else if (data['X-Amz-Algorithm']) { method = 'query'; version = 'v4'; + } if (data.Policy) { + if (data['X-Amz-Algorithm']) { + method = 'form'; + version = 'v4'; + } + // TODO ARSN-414 check v2 auth for POST requests with form data + // if (formData.Signature) { + // method = 'form'; + // version = 'v2'; + // } } // Here, either both values are set, or none is set @@ -121,7 +134,8 @@ function doAuth( awsService: string, requestContexts: any[] | null ) { - const res = extractParams(request, log, awsService, request.query); + const data: { [key: string]: string; } = request.formData || request.query || {}; + const res = extractParams(request, log, awsService, data); if (res.err) { return cb(res.err); } else if (res.params instanceof AuthInfo) { diff --git a/lib/auth/v4/authV4.ts b/lib/auth/v4/authV4.ts index b968aca7d..d3c568b36 100644 --- a/lib/auth/v4/authV4.ts +++ b/lib/auth/v4/authV4.ts @@ -1,2 +1,3 @@ export * as header from './headerAuthCheck'; export * as query from './queryAuthCheck'; +export * as form from './formAuthCheck'; diff --git a/lib/auth/v4/formAuthCheck.ts b/lib/auth/v4/formAuthCheck.ts new file mode 100644 index 000000000..b057019ef --- /dev/null +++ b/lib/auth/v4/formAuthCheck.ts @@ -0,0 +1,186 @@ +import { Logger } from 'werelogs'; +import * as constants from '../../constants'; +import errors from '../../errors'; +import constructStringToSign from './constructStringToSign'; +import { checkTimeSkew, convertAmzTimeToMs } from './timeUtils'; +import { validateCredentials, extractFormParams } from './validateInputs'; +import { areSignedHeadersComplete } from './validateInputs'; + +/** + * V4 query auth check + * @param request - HTTP request object + * @param log - logging object + * @param data - Contain authentification params (GET or POST data) + */ +export function check(request: any, log: Logger, data: { [key: string]: string }) { + const authParams = extractFormParams(data, log); + + if (Object.keys(authParams).length !== 4) { + return { err: errors.InvalidArgument }; + } + + // Query params are not specified in AWS documentation as case-insensitive, + // so we use case-sensitive + const token = data['X-Amz-Security-Token']; + if (token && !constants.iamSecurityToken.pattern.test(token)) { + log.debug('invalid security token', { token }); + return { err: errors.InvalidToken }; + } + + const signedHeaders = authParams.signedHeaders!; + const signatureFromRequest = authParams.signatureFromRequest!; + const timestamp = authParams.timestamp!; + //const expiry = authParams.expiry!; + const credential = authParams.credential!; + + if (!areSignedHeadersComplete(signedHeaders, request.headers)) { + log.debug('signedHeaders are incomplete', { signedHeaders }); + return { err: errors.AccessDenied }; + } + + const validationResult = validateCredentials(credential, timestamp, + log); + if (validationResult instanceof Error) { + log.debug('credentials in improper format', { credential, + timestamp, validationResult }); + return { err: validationResult }; + } + const accessKey = credential[0]; + const scopeDate = credential[1]; + const region = credential[2]; + const service = credential[3]; + const requestType = credential[4]; + + // In query v4 auth, the canonical request needs + // to include the query params OTHER THAN + // the signature so create a + // copy of the query object and remove + // the X-Amz-Signature property. + const queryWithoutSignature = Object.assign({}, data); + delete queryWithoutSignature['X-Amz-Signature']; + + // For query auth, instead of a + // checksum of the contents, the + // string 'UNSIGNED-PAYLOAD' should be + // added to the canonicalRequest in + // building string to sign + const payloadChecksum = 'UNSIGNED-PAYLOAD'; + + // string to sign is the policy + const stringToSign = data['Policy']; + log.trace('constructed stringToSign', { stringToSign }); + return { + err: null, + params: { + version: 4, + data: { + accessKey, + signatureFromRequest, + region, + scopeDate, + stringToSign, + authType: 'REST-QUERY-STRING', + signatureVersion: 'AWS4-HMAC-SHA256', + signatureAge: Date.now() - convertAmzTimeToMs(timestamp), + securityToken: token, + }, + }, + }; +} + +/** + * V4 form auth check for POST Object request + * @param request - HTTP request object containing form data + * @param log - logging object + */ +export function checkPostObjectAuth(request: any, log: Logger, formData: { [key: string]: string }) { + // Assume form data is already parsed and attached to request.body + + // Extract authentication parameters from formData + const algorithm = formData['X-Amz-Algorithm']; + const credentials = formData['X-Amz-Credential']; + const date = formData['X-Amz-Date']; + const securityToken = formData['X-Amz-Security-Token']; + const signature = formData['X-Amz-Signature']; + + let splitCredentials : [string, string, string, string, string]; + if (credentials && credentials.length > 28 && credentials.indexOf('/') > -1) { + // @ts-ignore + splitCredentials = credentials.split('/'); + } else { + log.debug('invalid credential param', { credentials, + date }); + return { err: errors.InvalidArgument }; + } + + if (!algorithm || !splitCredentials || !date || !signature) { + return { err: errors.InvalidArgument }; + } + + // Validate the token if present + if (securityToken && !constants.iamSecurityToken.pattern.test(securityToken)) { + log.debug('invalid security token', { token: securityToken }); + return { err: errors.InvalidToken }; + } + + // Checking credential format + const validationResult = validateCredentials(splitCredentials, date, + log); + if (validationResult instanceof Error) { + log.debug('credentials in improper format', { splitCredentials, + date, validationResult }); + return { err: validationResult }; + } + + const accessKey = splitCredentials[0]; + const scopeDate = splitCredentials[1]; + const region = splitCredentials[2]; + const service = splitCredentials[3]; + const requestType = splitCredentials[4]; + + // Verifying the timestamp and potential expiration + const isTimeSkewed = checkTimeSkew(date, request.expiry, log); + if (isTimeSkewed) { + return { err: errors.RequestTimeTooSkewed }; + } + + // Extract signed headers + const signedHeaders = Object.keys(request.headers).map(key => key.toLowerCase()).sort().join(';'); + + + const stringToSign = constructStringToSign({ + request, + signedHeaders, + payloadChecksum: null, + credentialScope: + `${scopeDate}/${region}/${service}/${requestType}`, + timestamp: date, + query: formData, + log, + awsService: service, + }); + if (stringToSign instanceof Error) { + return { err: stringToSign }; + } + log.trace('constructed stringToSign', { stringToSign }); + + // If all checks are successful + return { + err: null, + params: { + version: 4, + data: { + accessKey: accessKey, + signatureFromRequest: signature, + date: date, + region: region, + scopeDate: scopeDate, + stringToSign: stringToSign, + authType: 'POST-OBJECT', + signatureVersion: 'AWS4-HMAC-SHA256', + signatureAge: Date.now() - convertAmzTimeToMs(date), + securityToken: securityToken, + } + } + }; +} diff --git a/lib/auth/v4/validateInputs.ts b/lib/auth/v4/validateInputs.ts index 4d83fba24..60193d55d 100644 --- a/lib/auth/v4/validateInputs.ts +++ b/lib/auth/v4/validateInputs.ts @@ -131,6 +131,73 @@ export function extractQueryParams( } +/** + * Extract and validate components from formData object + * @param formObj - formData object from request + * @param log - logging object + * @return object containing extracted query params for authV4 + */ +export function extractFormParams( + formObj: { [key: string]: string | undefined }, + 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 + if (formObj['X-Amz-Algorithm'] !== 'AWS4-HMAC-SHA256') { + log.warn('algorithm param incorrect', + { algo: formObj['X-Amz-Algorithm'] }); + return authParams; + } + + // adding placeholder for signedHeaders to satisfy Vault + // as this is not required for form auth + authParams.signedHeaders = 'content-type;host;x-amz-date;x-amz-security-token'; + + const signature = formObj['X-Amz-Signature']; + if (signature && signature.length === 64) { + authParams.signatureFromRequest = signature; + } else { + log.warn('missing signature'); + return authParams; + } + + const timestamp = formObj['X-Amz-Date']; + if (timestamp && timestamp.length === 16) { + authParams.timestamp = timestamp; + } else { + log.warn('missing or invalid timestamp', + { timestamp: formObj['X-Amz-Date'] }); + return authParams; + } + + // TODO? ARSN-414 Does not seem to be required for form auth + // const expiry = Number.parseInt(formObj['X-Amz-Expires'] ?? 'nope', 10); + // const sevenDays = 604800; + // if (expiry && (expiry > 0 && expiry <= sevenDays)) { + // authParams.expiry = expiry; + // } else { + // log.warn('invalid expiry', { expiry }); + // return authParams; + // } + + const credential = formObj['X-Amz-Credential']; + if (credential && credential.length > 28 && credential.indexOf('/') > -1) { + // @ts-ignore + authParams.credential = credential.split('/'); + } else { + log.warn('invalid credential param', { credential }); + return authParams; + } + return authParams; +} + /** * Extract and validate components from auth header * @param authHeader - authorization header from request diff --git a/lib/s3routes/routes/routePOST.ts b/lib/s3routes/routes/routePOST.ts index 1854d4b97..835d09915 100644 --- a/lib/s3routes/routes/routePOST.ts +++ b/lib/s3routes/routes/routePOST.ts @@ -58,6 +58,10 @@ export default function routePOST( corsHeaders)); } + if (objectKey === undefined && Object.keys(query).length === 0) { + return api.callApiMethod('objectPost', request, response, log, (err, resHeaders) => routesUtils.responseNoBody(err, resHeaders, response, 200, log)); + } + return routesUtils.responseNoBody(errors.NotImplemented, null, response, 200, log); } From 6738f39f1bca740d550199e0381f44798bc3ba1d Mon Sep 17 00:00:00 2001 From: Will Toozs Date: Wed, 5 Jun 2024 18:59:15 +0200 Subject: [PATCH 2/3] update --- lib/auth/v4/formAuthCheck.ts | 164 +++++++++++++++++------------------ 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/lib/auth/v4/formAuthCheck.ts b/lib/auth/v4/formAuthCheck.ts index b057019ef..b4bb7c451 100644 --- a/lib/auth/v4/formAuthCheck.ts +++ b/lib/auth/v4/formAuthCheck.ts @@ -6,94 +6,94 @@ import { checkTimeSkew, convertAmzTimeToMs } from './timeUtils'; import { validateCredentials, extractFormParams } from './validateInputs'; import { areSignedHeadersComplete } from './validateInputs'; -/** - * V4 query auth check - * @param request - HTTP request object - * @param log - logging object - * @param data - Contain authentification params (GET or POST data) - */ -export function check(request: any, log: Logger, data: { [key: string]: string }) { - const authParams = extractFormParams(data, log); - - if (Object.keys(authParams).length !== 4) { - return { err: errors.InvalidArgument }; - } - - // Query params are not specified in AWS documentation as case-insensitive, - // so we use case-sensitive - const token = data['X-Amz-Security-Token']; - if (token && !constants.iamSecurityToken.pattern.test(token)) { - log.debug('invalid security token', { token }); - return { err: errors.InvalidToken }; - } - - const signedHeaders = authParams.signedHeaders!; - const signatureFromRequest = authParams.signatureFromRequest!; - const timestamp = authParams.timestamp!; - //const expiry = authParams.expiry!; - const credential = authParams.credential!; - - if (!areSignedHeadersComplete(signedHeaders, request.headers)) { - log.debug('signedHeaders are incomplete', { signedHeaders }); - return { err: errors.AccessDenied }; - } - - const validationResult = validateCredentials(credential, timestamp, - log); - if (validationResult instanceof Error) { - log.debug('credentials in improper format', { credential, - timestamp, validationResult }); - return { err: validationResult }; - } - const accessKey = credential[0]; - const scopeDate = credential[1]; - const region = credential[2]; - const service = credential[3]; - const requestType = credential[4]; - - // In query v4 auth, the canonical request needs - // to include the query params OTHER THAN - // the signature so create a - // copy of the query object and remove - // the X-Amz-Signature property. - const queryWithoutSignature = Object.assign({}, data); - delete queryWithoutSignature['X-Amz-Signature']; - - // For query auth, instead of a - // checksum of the contents, the - // string 'UNSIGNED-PAYLOAD' should be - // added to the canonicalRequest in - // building string to sign - const payloadChecksum = 'UNSIGNED-PAYLOAD'; - - // string to sign is the policy - const stringToSign = data['Policy']; - log.trace('constructed stringToSign', { stringToSign }); - return { - err: null, - params: { - version: 4, - data: { - accessKey, - signatureFromRequest, - region, - scopeDate, - stringToSign, - authType: 'REST-QUERY-STRING', - signatureVersion: 'AWS4-HMAC-SHA256', - signatureAge: Date.now() - convertAmzTimeToMs(timestamp), - securityToken: token, - }, - }, - }; -} +// /** +// * V4 query auth check +// * @param request - HTTP request object +// * @param log - logging object +// * @param data - Contain authentification params (GET or POST data) +// */ +// export function check(request: any, log: Logger, data: { [key: string]: string }) { +// const authParams = extractFormParams(data, log); + +// if (Object.keys(authParams).length !== 4) { +// return { err: errors.InvalidArgument }; +// } + +// // Query params are not specified in AWS documentation as case-insensitive, +// // so we use case-sensitive +// const token = data['X-Amz-Security-Token']; +// if (token && !constants.iamSecurityToken.pattern.test(token)) { +// log.debug('invalid security token', { token }); +// return { err: errors.InvalidToken }; +// } + +// const signedHeaders = authParams.signedHeaders!; +// const signatureFromRequest = authParams.signatureFromRequest!; +// const timestamp = authParams.timestamp!; +// //const expiry = authParams.expiry!; +// const credential = authParams.credential!; + +// if (!areSignedHeadersComplete(signedHeaders, request.headers)) { +// log.debug('signedHeaders are incomplete', { signedHeaders }); +// return { err: errors.AccessDenied }; +// } + +// const validationResult = validateCredentials(credential, timestamp, +// log); +// if (validationResult instanceof Error) { +// log.debug('credentials in improper format', { credential, +// timestamp, validationResult }); +// return { err: validationResult }; +// } +// const accessKey = credential[0]; +// const scopeDate = credential[1]; +// const region = credential[2]; +// const service = credential[3]; +// const requestType = credential[4]; + +// // In query v4 auth, the canonical request needs +// // to include the query params OTHER THAN +// // the signature so create a +// // copy of the query object and remove +// // the X-Amz-Signature property. +// const queryWithoutSignature = Object.assign({}, data); +// delete queryWithoutSignature['X-Amz-Signature']; + +// // For query auth, instead of a +// // checksum of the contents, the +// // string 'UNSIGNED-PAYLOAD' should be +// // added to the canonicalRequest in +// // building string to sign +// const payloadChecksum = 'UNSIGNED-PAYLOAD'; + +// // string to sign is the policy +// const stringToSign = data['Policy']; +// log.trace('constructed stringToSign', { stringToSign }); +// return { +// err: null, +// params: { +// version: 4, +// data: { +// accessKey, +// signatureFromRequest, +// region, +// scopeDate, +// stringToSign, +// authType: 'REST-QUERY-STRING', +// signatureVersion: 'AWS4-HMAC-SHA256', +// signatureAge: Date.now() - convertAmzTimeToMs(timestamp), +// securityToken: token, +// }, +// }, +// }; +// } /** * V4 form auth check for POST Object request * @param request - HTTP request object containing form data * @param log - logging object */ -export function checkPostObjectAuth(request: any, log: Logger, formData: { [key: string]: string }) { +export function check(request: any, log: Logger, formData: { [key: string]: string }) { // Assume form data is already parsed and attached to request.body // Extract authentication parameters from formData From 3363bb4bc0f52d11c568b25b4fe566dbec880262 Mon Sep 17 00:00:00 2001 From: Will Toozs Date: Wed, 5 Jun 2024 19:12:33 +0200 Subject: [PATCH 3/3] update --- lib/auth/v4/formAuthCheck.ts | 313 ++++++++++++++++++----------------- 1 file changed, 157 insertions(+), 156 deletions(-) diff --git a/lib/auth/v4/formAuthCheck.ts b/lib/auth/v4/formAuthCheck.ts index b4bb7c451..262221a29 100644 --- a/lib/auth/v4/formAuthCheck.ts +++ b/lib/auth/v4/formAuthCheck.ts @@ -6,181 +6,182 @@ import { checkTimeSkew, convertAmzTimeToMs } from './timeUtils'; import { validateCredentials, extractFormParams } from './validateInputs'; import { areSignedHeadersComplete } from './validateInputs'; -// /** -// * V4 query auth check -// * @param request - HTTP request object -// * @param log - logging object -// * @param data - Contain authentification params (GET or POST data) -// */ -// export function check(request: any, log: Logger, data: { [key: string]: string }) { -// const authParams = extractFormParams(data, log); - -// if (Object.keys(authParams).length !== 4) { -// return { err: errors.InvalidArgument }; -// } - -// // Query params are not specified in AWS documentation as case-insensitive, -// // so we use case-sensitive -// const token = data['X-Amz-Security-Token']; -// if (token && !constants.iamSecurityToken.pattern.test(token)) { -// log.debug('invalid security token', { token }); -// return { err: errors.InvalidToken }; -// } - -// const signedHeaders = authParams.signedHeaders!; -// const signatureFromRequest = authParams.signatureFromRequest!; -// const timestamp = authParams.timestamp!; -// //const expiry = authParams.expiry!; -// const credential = authParams.credential!; - -// if (!areSignedHeadersComplete(signedHeaders, request.headers)) { -// log.debug('signedHeaders are incomplete', { signedHeaders }); -// return { err: errors.AccessDenied }; -// } - -// const validationResult = validateCredentials(credential, timestamp, -// log); -// if (validationResult instanceof Error) { -// log.debug('credentials in improper format', { credential, -// timestamp, validationResult }); -// return { err: validationResult }; -// } -// const accessKey = credential[0]; -// const scopeDate = credential[1]; -// const region = credential[2]; -// const service = credential[3]; -// const requestType = credential[4]; - -// // In query v4 auth, the canonical request needs -// // to include the query params OTHER THAN -// // the signature so create a -// // copy of the query object and remove -// // the X-Amz-Signature property. -// const queryWithoutSignature = Object.assign({}, data); -// delete queryWithoutSignature['X-Amz-Signature']; - -// // For query auth, instead of a -// // checksum of the contents, the -// // string 'UNSIGNED-PAYLOAD' should be -// // added to the canonicalRequest in -// // building string to sign -// const payloadChecksum = 'UNSIGNED-PAYLOAD'; - -// // string to sign is the policy -// const stringToSign = data['Policy']; -// log.trace('constructed stringToSign', { stringToSign }); -// return { -// err: null, -// params: { -// version: 4, -// data: { -// accessKey, -// signatureFromRequest, -// region, -// scopeDate, -// stringToSign, -// authType: 'REST-QUERY-STRING', -// signatureVersion: 'AWS4-HMAC-SHA256', -// signatureAge: Date.now() - convertAmzTimeToMs(timestamp), -// securityToken: token, -// }, -// }, -// }; -// } - /** - * V4 form auth check for POST Object request - * @param request - HTTP request object containing form data + * V4 query auth check + * @param request - HTTP request object * @param log - logging object + * @param data - Contain authentification params (GET or POST data) */ -export function check(request: any, log: Logger, formData: { [key: string]: string }) { - // Assume form data is already parsed and attached to request.body - - // Extract authentication parameters from formData - const algorithm = formData['X-Amz-Algorithm']; - const credentials = formData['X-Amz-Credential']; - const date = formData['X-Amz-Date']; - const securityToken = formData['X-Amz-Security-Token']; - const signature = formData['X-Amz-Signature']; - - let splitCredentials : [string, string, string, string, string]; - if (credentials && credentials.length > 28 && credentials.indexOf('/') > -1) { - // @ts-ignore - splitCredentials = credentials.split('/'); - } else { - log.debug('invalid credential param', { credentials, - date }); - return { err: errors.InvalidArgument }; - } +export function check(request: any, log: Logger, data: { [key: string]: string }) { + const authParams = extractFormParams(data, log); - if (!algorithm || !splitCredentials || !date || !signature) { + if (Object.keys(authParams).length !== 4) { return { err: errors.InvalidArgument }; } - // Validate the token if present - if (securityToken && !constants.iamSecurityToken.pattern.test(securityToken)) { - log.debug('invalid security token', { token: securityToken }); + // Query params are not specified in AWS documentation as case-insensitive, + // so we use case-sensitive + const token = data['X-Amz-Security-Token']; + if (token && !constants.iamSecurityToken.pattern.test(token)) { + log.debug('invalid security token', { token }); return { err: errors.InvalidToken }; } - // Checking credential format - const validationResult = validateCredentials(splitCredentials, date, - log); - if (validationResult instanceof Error) { - log.debug('credentials in improper format', { splitCredentials, - date, validationResult }); - return { err: validationResult }; - } - - const accessKey = splitCredentials[0]; - const scopeDate = splitCredentials[1]; - const region = splitCredentials[2]; - const service = splitCredentials[3]; - const requestType = splitCredentials[4]; - - // Verifying the timestamp and potential expiration - const isTimeSkewed = checkTimeSkew(date, request.expiry, log); - if (isTimeSkewed) { - return { err: errors.RequestTimeTooSkewed }; + const signedHeaders = authParams.signedHeaders!; + const signatureFromRequest = authParams.signatureFromRequest!; + const timestamp = authParams.timestamp!; + //const expiry = authParams.expiry!; + const credential = authParams.credential!; + + if (!areSignedHeadersComplete(signedHeaders, request.headers)) { + log.debug('signedHeaders are incomplete', { signedHeaders }); + return { err: errors.AccessDenied }; } - // Extract signed headers - const signedHeaders = Object.keys(request.headers).map(key => key.toLowerCase()).sort().join(';'); - - - const stringToSign = constructStringToSign({ - request, - signedHeaders, - payloadChecksum: null, - credentialScope: - `${scopeDate}/${region}/${service}/${requestType}`, - timestamp: date, - query: formData, - log, - awsService: service, - }); - if (stringToSign instanceof Error) { - return { err: stringToSign }; + const validationResult = validateCredentials(credential, timestamp, + log); + if (validationResult instanceof Error) { + log.debug('credentials in improper format', { credential, + timestamp, validationResult }); + return { err: validationResult }; } + const accessKey = credential[0]; + const scopeDate = credential[1]; + const region = credential[2]; + const service = credential[3]; + const requestType = credential[4]; + + // In query v4 auth, the canonical request needs + // to include the query params OTHER THAN + // the signature so create a + // copy of the query object and remove + // the X-Amz-Signature property. + const queryWithoutSignature = Object.assign({}, data); + delete queryWithoutSignature['X-Amz-Signature']; + + // For query auth, instead of a + // checksum of the contents, the + // string 'UNSIGNED-PAYLOAD' should be + // added to the canonicalRequest in + // building string to sign + const payloadChecksum = 'UNSIGNED-PAYLOAD'; + + // string to sign is the policy + const stringToSign = data['Policy']; log.trace('constructed stringToSign', { stringToSign }); - - // If all checks are successful return { err: null, params: { version: 4, data: { - accessKey: accessKey, - signatureFromRequest: signature, - date: date, - region: region, - scopeDate: scopeDate, - stringToSign: stringToSign, - authType: 'POST-OBJECT', + accessKey, + signatureFromRequest, + region, + scopeDate, + stringToSign, + service, + authType: 'REST-QUERY-STRING', signatureVersion: 'AWS4-HMAC-SHA256', - signatureAge: Date.now() - convertAmzTimeToMs(date), - securityToken: securityToken, - } - } + signatureAge: Date.now() - convertAmzTimeToMs(timestamp), + securityToken: token, + }, + }, }; } + +// /** +// * V4 form auth check for POST Object request +// * @param request - HTTP request object containing form data +// * @param log - logging object +// */ +// export function check(request: any, log: Logger, formData: { [key: string]: string }) { +// // Assume form data is already parsed and attached to request.body + +// // Extract authentication parameters from formData +// const algorithm = formData['X-Amz-Algorithm']; +// const credentials = formData['X-Amz-Credential']; +// const date = formData['X-Amz-Date']; +// const securityToken = formData['X-Amz-Security-Token']; +// const signature = formData['X-Amz-Signature']; + +// let splitCredentials : [string, string, string, string, string]; +// if (credentials && credentials.length > 28 && credentials.indexOf('/') > -1) { +// // @ts-ignore +// splitCredentials = credentials.split('/'); +// } else { +// log.debug('invalid credential param', { credentials, +// date }); +// return { err: errors.InvalidArgument }; +// } + +// if (!algorithm || !splitCredentials || !date || !signature) { +// return { err: errors.InvalidArgument }; +// } + +// // Validate the token if present +// if (securityToken && !constants.iamSecurityToken.pattern.test(securityToken)) { +// log.debug('invalid security token', { token: securityToken }); +// return { err: errors.InvalidToken }; +// } + +// // Checking credential format +// const validationResult = validateCredentials(splitCredentials, date, +// log); +// if (validationResult instanceof Error) { +// log.debug('credentials in improper format', { splitCredentials, +// date, validationResult }); +// return { err: validationResult }; +// } + +// const accessKey = splitCredentials[0]; +// const scopeDate = splitCredentials[1]; +// const region = splitCredentials[2]; +// const service = splitCredentials[3]; +// const requestType = splitCredentials[4]; + +// // Verifying the timestamp and potential expiration +// const isTimeSkewed = checkTimeSkew(date, request.expiry, log); +// if (isTimeSkewed) { +// return { err: errors.RequestTimeTooSkewed }; +// } + +// // Extract signed headers +// const signedHeaders = Object.keys(request.headers).map(key => key.toLowerCase()).sort().join(';'); + + +// const stringToSign = constructStringToSign({ +// request, +// signedHeaders, +// payloadChecksum: null, +// credentialScope: +// `${scopeDate}/${region}/${service}/${requestType}`, +// timestamp: date, +// query: formData, +// log, +// awsService: service, +// }); +// if (stringToSign instanceof Error) { +// return { err: stringToSign }; +// } +// log.trace('constructed stringToSign', { stringToSign }); + +// // If all checks are successful +// return { +// err: null, +// params: { +// version: 4, +// data: { +// accessKey: accessKey, +// signatureFromRequest: signature, +// date: date, +// region: region, +// scopeDate: scopeDate, +// stringToSign: stringToSign, +// authType: 'POST-OBJECT', +// signatureVersion: 'AWS4-HMAC-SHA256', +// signatureAge: Date.now() - convertAmzTimeToMs(date), +// securityToken: securityToken, +// } +// } +// }; +// }