Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 84 additions & 105 deletions lib/api/apiUtils/authorization/prepareRequestContexts.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ const apiMethodWithVersion = {
};

function isHeaderAcl(headers) {
return headers['x-amz-grant-read'] || headers['x-amz-grant-read-acp'] ||
headers['x-amz-grant-write-acp'] || headers['x-amz-grant-full-control'] ||
headers['x-amz-acl'];
return (
headers['x-amz-grant-read'] ||
headers['x-amz-grant-read-acp'] ||
headers['x-amz-grant-write-acp'] ||
headers['x-amz-grant-full-control'] ||
headers['x-amz-acl']
);
}

/**
Expand All @@ -32,8 +36,7 @@ function isHeaderAcl(headers) {
* @param {string} sourceVersionId - value of sourceVersionId if copy request
* @return {RequestContext []} array of requestContexts
*/
function prepareRequestContexts(apiMethod, request, sourceBucket,
sourceObject, sourceVersionId) {
function prepareRequestContexts(apiMethod, request, sourceBucket, sourceObject, sourceVersionId) {
// if multiObjectDelete request, we want to authenticate
// before parsing the post body and creating multiple requestContexts
// so send null as requestContexts to Vault to avoid authorization
Expand All @@ -48,17 +51,23 @@ function prepareRequestContexts(apiMethod, request, sourceBucket,
const isSecure = requestUtils.getHttpProtocolSecurity(request, config);

function generateRequestContext(apiMethod) {
return new RequestContext(request.headers,
request.query, request.bucketName, request.objectKey,
ip, isSecure, apiMethod, 's3');
return new RequestContext(
request.headers,
request.query,
request.bucketName,
request.objectKey,
ip,
isSecure,
apiMethod,
's3',
);
}

if (apiMethod === 'bucketPut') {
return null;
}

if (apiMethodWithVersion[apiMethod] && request.query &&
request.query.versionId) {
if (apiMethodWithVersion[apiMethod] && request.query && request.query.versionId) {
apiMethodAfterVersionCheck = `${apiMethod}Version`;
} else {
apiMethodAfterVersionCheck = apiMethod;
Expand All @@ -75,181 +84,155 @@ function prepareRequestContexts(apiMethod, request, sourceBucket,
// In the API, we then ignore these authorization results, and we can use
// any information returned, e.g., the quota.
const requestContextMultiObjectDelete = generateRequestContext('objectDelete');
requestContexts.push(requestContextMultiObjectDelete);
} else if (apiMethodAfterVersionCheck === 'objectCopy'
|| apiMethodAfterVersionCheck === 'objectPutCopyPart') {
const objectGetAction = sourceVersionId ? 'objectGetVersion' :
'objectGet';
const reqQuery = Object.assign({}, request.query,
{ versionId: sourceVersionId });
const getRequestContext = new RequestContext(request.headers,
reqQuery, sourceBucket, sourceObject,
ip, isSecure,
objectGetAction, 's3');
const putRequestContext = generateRequestContext('objectPut');
requestContexts.push(requestContextMultiObjectDelete);
} else if (apiMethodAfterVersionCheck === 'objectCopy' || apiMethodAfterVersionCheck === 'objectPutCopyPart') {
const objectGetAction = sourceVersionId ? 'objectGetVersion' : 'objectGet';
const reqQuery = Object.assign({}, request.query, { versionId: sourceVersionId });
const getRequestContext = new RequestContext(
request.headers,
reqQuery,
sourceBucket,
sourceObject,
ip,
isSecure,
objectGetAction,
's3',
);
// Same API method as the one checked on the destination by the API
const objectPutAction = apiMethodAfterVersionCheck === 'objectPutCopyPart' ? 'objectPutPart' : 'objectPut';
const putRequestContext = generateRequestContext(objectPutAction);
requestContexts.push(getRequestContext, putRequestContext);
if (apiMethodAfterVersionCheck === 'objectCopy') {
// if tagging directive is COPY, "s3:PutObjectTagging" don't need
// to be included in the list of permitted actions in IAM policy
if (request.headers['x-amz-tagging'] &&
request.headers['x-amz-tagging-directive'] === 'REPLACE') {
const putTaggingRequestContext =
generateRequestContext('objectPutTagging');
if (request.headers['x-amz-tagging'] && request.headers['x-amz-tagging-directive'] === 'REPLACE') {
const putTaggingRequestContext = generateRequestContext('objectPutTagging');
requestContexts.push(putTaggingRequestContext);
}
if (isHeaderAcl(request.headers)) {
const putAclRequestContext =
generateRequestContext('objectPutACL');
const putAclRequestContext = generateRequestContext('objectPutACL');
requestContexts.push(putAclRequestContext);
}
}
} else if (apiMethodAfterVersionCheck === 'objectGet'
|| apiMethodAfterVersionCheck === 'objectGetVersion') {
const objectGetTaggingAction = (request.query &&
request.query.versionId) ? 'objectGetTaggingVersion' :
'objectGetTagging';
} else if (apiMethodAfterVersionCheck === 'objectGet' || apiMethodAfterVersionCheck === 'objectGetVersion') {
const objectGetTaggingAction =
request.query && request.query.versionId ? 'objectGetTaggingVersion' : 'objectGetTagging';
if (request.headers['x-amz-version-id']) {
const objectGetVersionAction = 'objectGetVersion';
const getVersionResourceVersion =
generateRequestContext(objectGetVersionAction);
const getVersionResourceVersion = generateRequestContext(objectGetVersionAction);
requestContexts.push(getVersionResourceVersion);
}
const getRequestContext =
generateRequestContext(apiMethodAfterVersionCheck);
const getTaggingRequestContext =
generateRequestContext(objectGetTaggingAction);
const getRequestContext = generateRequestContext(apiMethodAfterVersionCheck);
const getTaggingRequestContext = generateRequestContext(objectGetTaggingAction);
requestContexts.push(getRequestContext, getTaggingRequestContext);
} else if (apiMethodAfterVersionCheck === 'objectGetTagging') {
const objectGetTaggingAction = 'objectGetTagging';
const getTaggingResourceVersion =
generateRequestContext(objectGetTaggingAction);
const getTaggingResourceVersion = generateRequestContext(objectGetTaggingAction);
requestContexts.push(getTaggingResourceVersion);
if (request.headers['x-amz-version-id']) {
const objectGetTaggingVersionAction = 'objectGetTaggingVersion';
const getTaggingVersionResourceVersion =
generateRequestContext(objectGetTaggingVersionAction);
const getTaggingVersionResourceVersion = generateRequestContext(objectGetTaggingVersionAction);
requestContexts.push(getTaggingVersionResourceVersion);
}
} else if (apiMethodAfterVersionCheck === 'objectHead') {
const objectHeadAction = 'objectHead';
const headObjectAction =
generateRequestContext(objectHeadAction);
const headObjectAction = generateRequestContext(objectHeadAction);
requestContexts.push(headObjectAction);
if (request.headers['x-amz-version-id']) {
const objectHeadVersionAction = 'objectGetVersion';
const headObjectVersion =
generateRequestContext(objectHeadVersionAction);
const headObjectVersion = generateRequestContext(objectHeadVersionAction);
requestContexts.push(headObjectVersion);
}
if (request.headers['x-amz-scal-archive-info']) {
const coldStatus =
generateRequestContext('objectGetArchiveInfo');
const coldStatus = generateRequestContext('objectGetArchiveInfo');
requestContexts.push(coldStatus);
}
} else if (apiMethodAfterVersionCheck === 'objectPutTagging') {
const putObjectTaggingRequestContext =
generateRequestContext('objectPutTagging');
const putObjectTaggingRequestContext = generateRequestContext('objectPutTagging');
requestContexts.push(putObjectTaggingRequestContext);
if (request.headers['x-amz-version-id']) {
const putObjectVersionRequestContext =
generateRequestContext('objectPutTaggingVersion');
const putObjectVersionRequestContext = generateRequestContext('objectPutTaggingVersion');
requestContexts.push(putObjectVersionRequestContext);
}
} else if (apiMethodAfterVersionCheck === 'objectPut') {
// if put object with version
if (request.headers['x-scal-s3-version-id'] ||
request.headers['x-scal-s3-version-id'] === '') {
const putVersionRequestContext =
generateRequestContext('objectPutVersion');
if (request.headers['x-scal-s3-version-id'] || request.headers['x-scal-s3-version-id'] === '') {
const putVersionRequestContext = generateRequestContext('objectPutVersion');
requestContexts.push(putVersionRequestContext);
} else {
const putRequestContext =
generateRequestContext(apiMethodAfterVersionCheck);
const putRequestContext = generateRequestContext(apiMethodAfterVersionCheck);
requestContexts.push(putRequestContext);
// if put object (versioning) with tag set
if (request.headers['x-amz-tagging']) {
const putTaggingRequestContext =
generateRequestContext('objectPutTagging');
const putTaggingRequestContext = generateRequestContext('objectPutTagging');
requestContexts.push(putTaggingRequestContext);
}
if (['ON', 'OFF'].includes(request.headers['x-amz-object-lock-legal-hold-status'])) {
const putLegalHoldStatusAction =
generateRequestContext('objectPutLegalHold');
const putLegalHoldStatusAction = generateRequestContext('objectPutLegalHold');
requestContexts.push(putLegalHoldStatusAction);
}
// if put object (versioning) with ACL
if (isHeaderAcl(request.headers)) {
const putAclRequestContext =
generateRequestContext('objectPutACL');
const putAclRequestContext = generateRequestContext('objectPutACL');
requestContexts.push(putAclRequestContext);
}
if (request.headers['x-amz-object-lock-mode']) {
const putObjectLockRequestContext =
generateRequestContext('objectPutRetention');
const putObjectLockRequestContext = generateRequestContext('objectPutRetention');
requestContexts.push(putObjectLockRequestContext);
if (hasGovernanceBypassHeader(request.headers)) {
const checkUserGovernanceBypassRequestContext =
generateRequestContext('bypassGovernanceRetention');
const checkUserGovernanceBypassRequestContext = generateRequestContext('bypassGovernanceRetention');
requestContexts.push(checkUserGovernanceBypassRequestContext);
}
}
if (request.headers['x-amz-version-id']) {
const putObjectVersionRequestContext =
generateRequestContext('objectPutTaggingVersion');
const putObjectVersionRequestContext = generateRequestContext('objectPutTaggingVersion');
requestContexts.push(putObjectVersionRequestContext);
}
}
} else if (apiMethodAfterVersionCheck === 'objectPutRetention' ||
apiMethodAfterVersionCheck === 'objectPutRetentionVersion') {
const putRetentionRequestContext =
generateRequestContext(apiMethodAfterVersionCheck);
} else if (
apiMethodAfterVersionCheck === 'objectPutRetention' ||
apiMethodAfterVersionCheck === 'objectPutRetentionVersion'
) {
const putRetentionRequestContext = generateRequestContext(apiMethodAfterVersionCheck);
requestContexts.push(putRetentionRequestContext);
if (hasGovernanceBypassHeader(request.headers)) {
const checkUserGovernanceBypassRequestContext =
generateRequestContext('bypassGovernanceRetention');
const checkUserGovernanceBypassRequestContext = generateRequestContext('bypassGovernanceRetention');
requestContexts.push(checkUserGovernanceBypassRequestContext);
}
} else if (apiMethodAfterVersionCheck === 'initiateMultipartUpload' ||
apiMethodAfterVersionCheck === 'objectPutPart' ||
apiMethodAfterVersionCheck === 'completeMultipartUpload'
) {
if (request.headers['x-scal-s3-version-id'] ||
request.headers['x-scal-s3-version-id'] === '') {
const putVersionRequestContext =
generateRequestContext('objectPutVersion');
} else if (
apiMethodAfterVersionCheck === 'initiateMultipartUpload' ||
apiMethodAfterVersionCheck === 'objectPutPart' ||
apiMethodAfterVersionCheck === 'completeMultipartUpload'
) {
if (request.headers['x-scal-s3-version-id'] || request.headers['x-scal-s3-version-id'] === '') {
const putVersionRequestContext = generateRequestContext('objectPutVersion');
requestContexts.push(putVersionRequestContext);
} else {
const putRequestContext =
generateRequestContext(apiMethodAfterVersionCheck);
const putRequestContext = generateRequestContext(apiMethodAfterVersionCheck);
requestContexts.push(putRequestContext);
}

// if put object (versioning) with ACL
if (isHeaderAcl(request.headers)) {
const putAclRequestContext =
generateRequestContext('objectPutACL');
const putAclRequestContext = generateRequestContext('objectPutACL');
requestContexts.push(putAclRequestContext);
}

if (request.headers['x-amz-object-lock-mode']) {
const putObjectLockRequestContext =
generateRequestContext('objectPutRetention');
const putObjectLockRequestContext = generateRequestContext('objectPutRetention');
requestContexts.push(putObjectLockRequestContext);
}
if (request.headers['x-amz-version-id']) {
const putObjectVersionRequestContext =
generateRequestContext('objectPutTaggingVersion');
const putObjectVersionRequestContext = generateRequestContext('objectPutTaggingVersion');
requestContexts.push(putObjectVersionRequestContext);
}
// AWS only returns an object lock error if a version id
// is specified, else continue to create a delete marker
// AWS only returns an object lock error if a version id
// is specified, else continue to create a delete marker
} else if (sourceVersionId && apiMethodAfterVersionCheck === 'objectDeleteVersion') {
const deleteRequestContext =
generateRequestContext(apiMethodAfterVersionCheck);
const deleteRequestContext = generateRequestContext(apiMethodAfterVersionCheck);
requestContexts.push(deleteRequestContext);
if (hasGovernanceBypassHeader(request.headers)) {
const checkUserGovernanceBypassRequestContext =
generateRequestContext('bypassGovernanceRetention');
const checkUserGovernanceBypassRequestContext = generateRequestContext('bypassGovernanceRetention');
requestContexts.push(checkUserGovernanceBypassRequestContext);
}
} else if (apiMethodAfterVersionCheck === 'bucketGet') {
Expand All @@ -268,19 +251,15 @@ function prepareRequestContexts(apiMethod, request, sourceBucket,
generateRequestContext('objectGetVersionAttributes'),
);
} else {
requestContexts.push(
generateRequestContext('objectGet'),
generateRequestContext('objectGetAttributes'),
);
requestContexts.push(generateRequestContext('objectGet'), generateRequestContext('objectGetAttributes'));
}

const attributes = request.headers['x-amz-object-attributes']?.split(',') ?? [];
if (attributes.some(attr => attr.trim().toLowerCase().startsWith('x-amz-meta-'))) {
requestContexts.push(generateRequestContext('objectGetAttributesCustom'));
}
} else {
const requestContext =
generateRequestContext(apiMethodAfterVersionCheck);
const requestContext = generateRequestContext(apiMethodAfterVersionCheck);
requestContexts.push(requestContext);
}

Expand Down
Loading
Loading