diff --git a/constants.js b/constants.js index d9c4f7274a..357ae9d3fd 100644 --- a/constants.js +++ b/constants.js @@ -176,6 +176,8 @@ const constants = { 'objectDeleteTagging', 'objectGetTagging', 'objectPutTagging', + 'objectPutLegalHold', + 'objectPutRetention', ], // response header to be sent when there are invalid // user metadata in the object's metadata diff --git a/lib/api/bucketPutACL.js b/lib/api/bucketPutACL.js index 741dbc0359..3340668132 100644 --- a/lib/api/bucketPutACL.js +++ b/lib/api/bucketPutACL.js @@ -6,7 +6,7 @@ const aclUtils = require('../utilities/aclUtils'); const { cleanUpBucket } = require('./apiUtils/bucket/bucketCreation'); const collectCorsHeaders = require('../utilities/collectCorsHeaders'); const constants = require('../../constants'); -const { metadataValidateBucket } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucket } = require('../metadata/metadataUtils'); const vault = require('../auth/vault'); const { pushMetric } = require('../utapi/utilities'); const monitoring = require('../utilities/monitoringHandler'); @@ -44,7 +44,7 @@ const monitoring = require('../utilities/monitoringHandler'); function bucketPutACL(authInfo, request, log, callback) { log.debug('processing request', { method: 'bucketPutACL' }); - const bucketName = request.bucketName; + const { bucketName } = request; const canonicalID = authInfo.getCanonicalID(); const newCannedACL = request.headers['x-amz-acl']; const possibleCannedACL = [ @@ -54,19 +54,6 @@ function bucketPutACL(authInfo, request, log, callback) { 'authenticated-read', 'log-delivery-write', ]; - if (newCannedACL && possibleCannedACL.indexOf(newCannedACL) === -1) { - log.trace('invalid canned acl argument', { - acl: newCannedACL, - method: 'bucketPutACL', - }); - monitoring.promMetrics('PUT', bucketName, 400, 'bucketPutACL'); - return callback(errors.InvalidArgument); - } - if (!aclUtils.checkGrantHeaderValidity(request.headers)) { - log.trace('invalid acl header'); - monitoring.promMetrics('PUT', bucketName, 400, 'bucketPutACL'); - return callback(errors.InvalidArgument); - } const possibleGroups = [constants.allAuthedUsersId, constants.publicId, constants.logId, @@ -74,7 +61,7 @@ function bucketPutACL(authInfo, request, log, callback) { const metadataValParams = { authInfo, bucketName, - requestType: 'bucketPutACL', + requestType: request.apiMethods || 'bucketPutACL', request, }; const possibleGrants = ['FULL_CONTROL', 'WRITE', @@ -105,7 +92,7 @@ function bucketPutACL(authInfo, request, log, callback) { return async.waterfall([ function waterfall1(next) { - metadataValidateBucket(metadataValParams, log, + standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log, (err, bucket) => { if (err) { log.trace('request authorization failed', { @@ -114,6 +101,18 @@ function bucketPutACL(authInfo, request, log, callback) { }); return next(err, bucket); } + // if the API call is allowed, ensure that the parameters are valid + if (newCannedACL && possibleCannedACL.indexOf(newCannedACL) === -1) { + log.trace('invalid canned acl argument', { + acl: newCannedACL, + method: 'bucketPutACL', + }); + return next(errors.InvalidArgument); + } + if (!aclUtils.checkGrantHeaderValidity(request.headers)) { + log.trace('invalid acl header'); + return next(errors.InvalidArgument); + } return next(null, bucket); }); }, diff --git a/lib/api/bucketPutCors.js b/lib/api/bucketPutCors.js index 49c5053891..e1ce6749d9 100644 --- a/lib/api/bucketPutCors.js +++ b/lib/api/bucketPutCors.js @@ -23,7 +23,7 @@ const requestType = 'bucketPutCors'; */ function bucketPutCors(authInfo, request, log, callback) { log.debug('processing request', { method: 'bucketPutCors' }); - const bucketName = request.bucketName; + const { bucketName } = request; const canonicalID = authInfo.getCanonicalID(); if (!request.post) { @@ -70,7 +70,8 @@ function bucketPutCors(authInfo, request, log, callback) { }); }, function validateBucketAuthorization(bucket, rules, corsHeaders, next) { - if (!isBucketAuthorized(bucket, requestType, canonicalID, authInfo, log, request)) { + if (!isBucketAuthorized(bucket, request.apiMethods || requestType, canonicalID, authInfo, + log, request, request.actionImplicitDenies)) { log.debug('access denied for account on bucket', { requestType, }); diff --git a/lib/api/bucketPutEncryption.js b/lib/api/bucketPutEncryption.js index 148c1ec3a3..5a407f2f63 100644 --- a/lib/api/bucketPutEncryption.js +++ b/lib/api/bucketPutEncryption.js @@ -3,7 +3,7 @@ const async = require('async'); const { parseEncryptionXml } = require('./apiUtils/bucket/bucketEncryption'); const { checkExpectedBucketOwner } = require('./apiUtils/authorization/bucketOwner'); const metadata = require('../metadata/wrapper'); -const { metadataValidateBucket } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucket } = require('../metadata/metadataUtils'); const kms = require('../kms/wrapper'); const { pushMetric } = require('../utapi/utilities'); const collectCorsHeaders = require('../utilities/collectCorsHeaders'); @@ -18,17 +18,17 @@ const collectCorsHeaders = require('../utilities/collectCorsHeaders'); */ function bucketPutEncryption(authInfo, request, log, callback) { - const bucketName = request.bucketName; + const { bucketName } = request; const metadataValParams = { authInfo, bucketName, - requestType: 'bucketPutEncryption', + requestType: request.apiMethods || 'bucketPutEncryption', request, }; return async.waterfall([ - next => metadataValidateBucket(metadataValParams, log, next), + next => standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log, next), (bucket, next) => checkExpectedBucketOwner(request.headers, bucket, log, err => next(err, bucket)), (bucket, next) => { log.trace('parsing encryption config', { method: 'bucketPutEncryption' }); diff --git a/lib/api/bucketPutLifecycle.js b/lib/api/bucketPutLifecycle.js index 9bfcc9ae8b..b1a30e27bf 100644 --- a/lib/api/bucketPutLifecycle.js +++ b/lib/api/bucketPutLifecycle.js @@ -7,7 +7,7 @@ const config = require('../Config').config; const parseXML = require('../utilities/parseXML'); const collectCorsHeaders = require('../utilities/collectCorsHeaders'); const metadata = require('../metadata/wrapper'); -const { metadataValidateBucket } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucket } = require('../metadata/metadataUtils'); const { pushMetric } = require('../utapi/utilities'); const monitoring = require('../utilities/monitoringHandler'); @@ -23,11 +23,11 @@ const monitoring = require('../utilities/monitoringHandler'); function bucketPutLifecycle(authInfo, request, log, callback) { log.debug('processing request', { method: 'bucketPutLifecycle' }); - const bucketName = request.bucketName; + const { bucketName } = request; const metadataValParams = { authInfo, bucketName, - requestType: 'bucketPutLifecycle', + requestType: request.apiMethods || 'bucketPutLifecycle', request, }; return waterfall([ @@ -45,7 +45,7 @@ function bucketPutLifecycle(authInfo, request, log, callback) { return next(null, configObj); }); }, - (lcConfig, next) => metadataValidateBucket(metadataValParams, log, + (lcConfig, next) => standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log, (err, bucket) => { if (err) { return next(err, bucket); diff --git a/lib/api/bucketPutNotification.js b/lib/api/bucketPutNotification.js index 3418ca5e2b..ab82b5109a 100644 --- a/lib/api/bucketPutNotification.js +++ b/lib/api/bucketPutNotification.js @@ -4,7 +4,7 @@ const parseXML = require('../utilities/parseXML'); const collectCorsHeaders = require('../utilities/collectCorsHeaders'); const getNotificationConfiguration = require('./apiUtils/bucket/getNotificationConfiguration'); const metadata = require('../metadata/wrapper'); -const { metadataValidateBucket } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucket } = require('../metadata/metadataUtils'); const { pushMetric } = require('../utapi/utilities'); /** @@ -19,11 +19,11 @@ const { pushMetric } = require('../utapi/utilities'); function bucketPutNotification(authInfo, request, log, callback) { log.debug('processing request', { method: 'bucketPutNotification' }); - const bucketName = request.bucketName; + const { bucketName } = request; const metadataValParams = { authInfo, bucketName, - requestType: 'bucketPutNotification', + requestType: request.apiMethods || 'bucketPutNotification', request, }; @@ -34,7 +34,7 @@ function bucketPutNotification(authInfo, request, log, callback) { const notifConfig = notificationConfig.error ? undefined : notificationConfig; process.nextTick(() => next(notificationConfig.error, notifConfig)); }, - (notifConfig, next) => metadataValidateBucket(metadataValParams, log, + (notifConfig, next) => standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log, (err, bucket) => next(err, bucket, notifConfig)), (bucket, notifConfig, next) => { bucket.setNotificationConfiguration(notifConfig); diff --git a/lib/api/bucketPutObjectLock.js b/lib/api/bucketPutObjectLock.js index ba240516f1..1b3a452640 100644 --- a/lib/api/bucketPutObjectLock.js +++ b/lib/api/bucketPutObjectLock.js @@ -1,13 +1,13 @@ const { waterfall } = require('async'); const arsenal = require('arsenal'); -const errors = arsenal.errors; -const ObjectLockConfiguration = arsenal.models.ObjectLockConfiguration; +const { errors } = arsenal; +const { models: { ObjectLockConfiguration } } = arsenal; const parseXML = require('../utilities/parseXML'); const collectCorsHeaders = require('../utilities/collectCorsHeaders'); const metadata = require('../metadata/wrapper'); -const { metadataValidateBucket } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucket } = require('../metadata/metadataUtils'); const { pushMetric } = require('../utapi/utilities'); /** @@ -41,7 +41,7 @@ function bucketPutObjectLock(authInfo, request, log, callback) { return next(configObj.error || null, configObj); }); }, - (objectLockConfig, next) => metadataValidateBucket(metadataValParams, + (objectLockConfig, next) => standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log, (err, bucket) => { if (err) { return next(err, bucket); diff --git a/lib/api/bucketPutPolicy.js b/lib/api/bucketPutPolicy.js index 328c98a306..024a69209f 100644 --- a/lib/api/bucketPutPolicy.js +++ b/lib/api/bucketPutPolicy.js @@ -3,7 +3,7 @@ const { errors, models } = require('arsenal'); const collectCorsHeaders = require('../utilities/collectCorsHeaders'); const metadata = require('../metadata/wrapper'); -const { metadataValidateBucket } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucket } = require('../metadata/metadataUtils'); const { validatePolicyResource } = require('./apiUtils/authorization/permissionChecks'); const { BucketPolicy } = models; @@ -37,7 +37,7 @@ function bucketPutPolicy(authInfo, request, log, callback) { const metadataValParams = { authInfo, bucketName, - requestType: 'bucketPutPolicy', + requestType: request.apiMethods || 'bucketPutPolicy', request, }; @@ -70,7 +70,7 @@ function bucketPutPolicy(authInfo, request, log, callback) { return next(null, bucketPolicy); }); }, - (bucketPolicy, next) => metadataValidateBucket(metadataValParams, log, + (bucketPolicy, next) => standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log, (err, bucket) => { if (err) { return next(err, bucket); diff --git a/lib/api/bucketPutReplication.js b/lib/api/bucketPutReplication.js index cbc64aa97c..b4955ea7d1 100644 --- a/lib/api/bucketPutReplication.js +++ b/lib/api/bucketPutReplication.js @@ -2,7 +2,7 @@ const { waterfall } = require('async'); const { errors } = require('arsenal'); const metadata = require('../metadata/wrapper'); -const { metadataValidateBucket } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucket } = require('../metadata/metadataUtils'); const { pushMetric } = require('../utapi/utilities'); const { getReplicationConfiguration } = require('./apiUtils/bucket/getReplicationConfiguration'); @@ -30,7 +30,7 @@ function bucketPutReplication(authInfo, request, log, callback) { const metadataValParams = { authInfo, bucketName, - requestType: 'bucketPutReplication', + requestType: request.apiMethods || 'bucketPutReplication', request, }; return waterfall([ @@ -39,7 +39,7 @@ function bucketPutReplication(authInfo, request, log, callback) { // Check bucket user privileges and ensure versioning is 'Enabled'. (config, next) => // TODO: Validate that destination bucket exists and has versioning. - metadataValidateBucket(metadataValParams, log, (err, bucket) => { + standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log, (err, bucket) => { if (err) { return next(err); } diff --git a/lib/api/bucketPutVersioning.js b/lib/api/bucketPutVersioning.js index 92785cf7c5..ac6e8f5bb6 100644 --- a/lib/api/bucketPutVersioning.js +++ b/lib/api/bucketPutVersioning.js @@ -4,7 +4,7 @@ const { errors } = require('arsenal'); const collectCorsHeaders = require('../utilities/collectCorsHeaders'); const metadata = require('../metadata/wrapper'); -const { metadataValidateBucket } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucket } = require('../metadata/metadataUtils'); const { pushMetric } = require('../utapi/utilities'); const versioningNotImplBackends = require('../../constants').versioningNotImplBackends; @@ -119,12 +119,12 @@ function bucketPutVersioning(authInfo, request, log, callback) { const metadataValParams = { authInfo, bucketName, - requestType: 'bucketPutVersioning', + requestType: request.apiMethods || 'bucketPutVersioning', request, }; return waterfall([ next => _parseXML(request, log, next), - next => metadataValidateBucket(metadataValParams, log, + next => standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log, (err, bucket) => next(err, bucket)), // ignore extra null object, (bucket, next) => parseString(request.post, (err, result) => { // just for linting; there should not be any parsing error here diff --git a/lib/api/bucketPutWebsite.js b/lib/api/bucketPutWebsite.js index 940ec8535c..611c6d0ad8 100644 --- a/lib/api/bucketPutWebsite.js +++ b/lib/api/bucketPutWebsite.js @@ -22,7 +22,7 @@ const requestType = 'bucketPutWebsite'; */ function bucketPutWebsite(authInfo, request, log, callback) { log.debug('processing request', { method: 'bucketPutWebsite' }); - const bucketName = request.bucketName; + const { bucketName } = request; const canonicalID = authInfo.getCanonicalID(); if (!request.post) { @@ -49,7 +49,8 @@ function bucketPutWebsite(authInfo, request, log, callback) { }); }, function validateBucketAuthorization(bucket, config, next) { - if (!isBucketAuthorized(bucket, requestType, canonicalID, authInfo, log, request)) { + if (!isBucketAuthorized(bucket, request.apiMethods || requestType, canonicalID, authInfo, + log, request, request.actionImplicitDenies)) { log.debug('access denied for user on bucket', { requestType, method: 'bucketPutWebsite', diff --git a/lib/api/objectPut.js b/lib/api/objectPut.js index 5a0c097d9b..42286a1ca4 100644 --- a/lib/api/objectPut.js +++ b/lib/api/objectPut.js @@ -8,7 +8,7 @@ const { getObjectSSEConfiguration } = require('./apiUtils/bucket/bucketEncryptio const collectCorsHeaders = require('../utilities/collectCorsHeaders'); const createAndStoreObject = require('./apiUtils/object/createAndStoreObject'); const { checkQueryVersionId, decodeVID } = require('./apiUtils/object/versioning'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const { pushMetric } = require('../utapi/utilities'); const { validateHeaders } = require('./apiUtils/object/objectLockHelpers'); const { hasNonPrintables } = require('../utilities/stringChecks'); @@ -96,7 +96,7 @@ function objectPut(authInfo, request, streamingV4Params, log, callback) { const invalidSSEError = errors.InvalidArgument.customizeDescription( 'The encryption method specified is not supported'); - const requestType = 'objectPut'; + const requestType = request.apiMethods || 'objectPut'; const valParams = { authInfo, bucketName, objectKey, versionId, requestType, request }; const canonicalID = authInfo.getCanonicalID(); @@ -114,7 +114,7 @@ function objectPut(authInfo, request, streamingV4Params, log, callback) { log.trace('owner canonicalID to send to data', { canonicalID }); - return metadataValidateBucketAndObj(valParams, log, + return standardMetadataValidateBucketAndObj(valParams, request.actionImplicitDenies, log, (err, bucket, objMD) => { const responseHeaders = collectCorsHeaders(headers.origin, method, bucket); diff --git a/lib/api/objectPutACL.js b/lib/api/objectPutACL.js index 0b814b5192..141fe4ec4a 100644 --- a/lib/api/objectPutACL.js +++ b/lib/api/objectPutACL.js @@ -9,7 +9,7 @@ const constants = require('../../constants'); const vault = require('../auth/vault'); const { decodeVersionId, getVersionIdResHeader, getVersionSpecificMetadataOptions } = require('./apiUtils/object/versioning'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const monitoring = require('../utilities/monitoringHandler'); const { config } = require('../Config'); @@ -45,8 +45,7 @@ const { config } = require('../Config'); */ function objectPutACL(authInfo, request, log, cb) { log.debug('processing request', { method: 'objectPutACL' }); - const bucketName = request.bucketName; - const objectKey = request.objectKey; + const { bucketName, objectKey } = request; const newCannedACL = request.headers['x-amz-acl']; const possibleCannedACL = [ 'private', @@ -88,7 +87,7 @@ function objectPutACL(authInfo, request, log, cb) { objectKey, versionId: reqVersionId, getDeleteMarker: true, - requestType: 'objectPutACL', + requestType: request.apiMethods || 'objectPutACL', }; const possibleGrants = ['FULL_CONTROL', 'WRITE_ACP', 'READ', 'READ_ACP']; @@ -112,7 +111,7 @@ function objectPutACL(authInfo, request, log, cb) { return async.waterfall([ function validateBucketAndObj(next) { - return metadataValidateBucketAndObj(metadataValParams, log, + return standardMetadataValidateBucketAndObj(metadataValParams, request.actionImplicitDenies, log, (err, bucket, objectMD) => { if (err) { return next(err); diff --git a/lib/api/objectPutCopyPart.js b/lib/api/objectPutCopyPart.js index 863e1ed1bf..a72536fb42 100644 --- a/lib/api/objectPutCopyPart.js +++ b/lib/api/objectPutCopyPart.js @@ -12,7 +12,7 @@ const { pushMetric } = require('../utapi/utilities'); const logger = require('../utilities/logger'); const services = require('../services'); const setUpCopyLocator = require('./apiUtils/object/setUpCopyLocator'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const monitoring = require('../utilities/monitoringHandler'); const { verifyColdObjectAvailable } = require('./apiUtils/object/coldStorage'); @@ -62,7 +62,7 @@ function objectPutCopyPart(authInfo, request, sourceBucket, // Note that keys in the query object retain their case, so // request.query.uploadId must be called with that exact // capitalization - const uploadId = request.query.uploadId; + const { query: { uploadId } } = request; const valPutParams = { authInfo, @@ -93,7 +93,7 @@ function objectPutCopyPart(authInfo, request, sourceBucket, return async.waterfall([ function checkDestAuth(next) { - return metadataValidateBucketAndObj(valPutParams, log, + return standardMetadataValidateBucketAndObj(valPutParams, request.actionImplicitDenies, log, (err, destBucketMD) => { if (err) { log.debug('error validating authorization for ' + @@ -112,7 +112,7 @@ function objectPutCopyPart(authInfo, request, sourceBucket, }); }, function checkSourceAuthorization(destBucketMD, next) { - return metadataValidateBucketAndObj(valGetParams, log, + return standardMetadataValidateBucketAndObj(valGetParams, request.actionImplicitDenies, log, (err, sourceBucketMD, sourceObjMD) => { if (err) { log.debug('error validating get part of request', @@ -256,6 +256,9 @@ function objectPutCopyPart(authInfo, request, sourceBucket, splitter, next, ) { + const originalIdentityAuthzResults = request.actionImplicitDenies; + // eslint-disable-next-line no-param-reassign + delete request.actionImplicitDenies; data.uploadPartCopy( request, log, @@ -266,6 +269,8 @@ function objectPutCopyPart(authInfo, request, sourceBucket, dataStoreContext, locationConstraintCheck, (error, eTag, lastModified, serverSideEncryption, locations) => { + // eslint-disable-next-line no-param-reassign + request.actionImplicitDenies = originalIdentityAuthzResults; if (error) { if (error.message === 'skip') { return next(skipError, destBucketMD, eTag, diff --git a/lib/api/objectPutLegalHold.js b/lib/api/objectPutLegalHold.js index 6d4c123de5..e5ba15b44b 100644 --- a/lib/api/objectPutLegalHold.js +++ b/lib/api/objectPutLegalHold.js @@ -6,7 +6,7 @@ const { decodeVersionId, getVersionIdResHeader, getVersionSpecificMetadataOption require('./apiUtils/object/versioning'); const getReplicationInfo = require('./apiUtils/object/getReplicationInfo'); const metadata = require('../metadata/wrapper'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const { pushMetric } = require('../utapi/utilities'); const { config } = require('../Config'); @@ -43,12 +43,12 @@ function objectPutLegalHold(authInfo, request, log, callback) { objectKey, versionId, getDeleteMarker: true, - requestType: 'objectPutLegalHold', + requestType: request.apiMethods || 'objectPutLegalHold', request, }; return async.waterfall([ - next => metadataValidateBucketAndObj(metadataValParams, log, + next => standardMetadataValidateBucketAndObj(metadataValParams, request.actionImplicitDenies, log, (err, bucket, objectMD) => { if (err) { log.trace('request authorization failed', diff --git a/lib/api/objectPutPart.js b/lib/api/objectPutPart.js index 3e5503f0a7..d669e2b727 100644 --- a/lib/api/objectPutPart.js +++ b/lib/api/objectPutPart.js @@ -100,9 +100,10 @@ function objectPutPart(authInfo, request, streamingV4Params, log, }); // Note that keys in the query object retain their case, so // `request.query.uploadId` must be called with that exact capitalization. - const uploadId = request.query.uploadId; + const { query: { uploadId } } = request; const mpuBucketName = `${constants.mpuBucketPrefix}${bucketName}`; - const objectKey = request.objectKey; + const { objectKey } = request; + const originalIdentityAuthzResults = request.actionImplicitDenies; return async.waterfall([ // Get the destination bucket. @@ -125,7 +126,8 @@ function objectPutPart(authInfo, request, streamingV4Params, log, // For validating the request at the destinationBucket level the // `requestType` is the general 'objectPut'. const requestType = 'objectPut'; - if (!isBucketAuthorized(destinationBucket, requestType, canonicalID, authInfo, log, request)) { + if (!isBucketAuthorized(destinationBucket, request.apiMethods || requestType, canonicalID, authInfo, + log, request, request.actionImplicitDenies)) { log.debug('access denied for user on bucket', { requestType }); return next(errors.AccessDenied, destinationBucket); } @@ -212,6 +214,8 @@ function objectPutPart(authInfo, request, streamingV4Params, log, partNumber, bucketName, }; + // eslint-disable-next-line no-param-reassign + delete request.actionImplicitDenies; writeContinue(request, request._response); return data.putPart(request, mpuInfo, streamingV4Params, objectLocationConstraint, locationConstraintCheck, log, @@ -397,6 +401,8 @@ function objectPutPart(authInfo, request, streamingV4Params, log, ], (err, destinationBucket, hexDigest, prevObjectSize) => { const corsHeaders = collectCorsHeaders(request.headers.origin, request.method, destinationBucket); + // eslint-disable-next-line no-param-reassign + request.actionImplicitDenies = originalIdentityAuthzResults; if (err) { if (err === skipError) { return cb(null, hexDigest, corsHeaders); diff --git a/lib/api/objectPutRetention.js b/lib/api/objectPutRetention.js index 1cbb8ac819..afb4c41968 100644 --- a/lib/api/objectPutRetention.js +++ b/lib/api/objectPutRetention.js @@ -5,7 +5,7 @@ const { decodeVersionId, getVersionIdResHeader, getVersionSpecificMetadataOption require('./apiUtils/object/versioning'); const { ObjectLockInfo, checkUserGovernanceBypass, hasGovernanceBypassHeader } = require('./apiUtils/object/objectLockHelpers'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const { pushMetric } = require('../utapi/utilities'); const getReplicationInfo = require('./apiUtils/object/getReplicationInfo'); const collectCorsHeaders = require('../utilities/collectCorsHeaders'); @@ -45,12 +45,12 @@ function objectPutRetention(authInfo, request, log, callback) { objectKey, versionId: reqVersionId, getDeleteMarker: true, - requestType: 'objectPutRetention', + requestType: request.apiMethods || 'objectPutRetention', request, }; return async.waterfall([ - next => metadataValidateBucketAndObj(metadataValParams, log, + next => standardMetadataValidateBucketAndObj(metadataValParams, request.actionImplicitDenies, log, (err, bucket, objectMD) => { if (err) { log.trace('request authorization failed', diff --git a/lib/api/objectPutTagging.js b/lib/api/objectPutTagging.js index 9b08d8818e..9781a441cc 100644 --- a/lib/api/objectPutTagging.js +++ b/lib/api/objectPutTagging.js @@ -4,7 +4,7 @@ const { errors, s3middleware } = require('arsenal'); const { decodeVersionId, getVersionIdResHeader, getVersionSpecificMetadataOptions } = require('./apiUtils/object/versioning'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const { pushMetric } = require('../utapi/utilities'); const monitoring = require('../utilities/monitoringHandler'); const getReplicationInfo = require('./apiUtils/object/getReplicationInfo'); @@ -26,8 +26,7 @@ const REPLICATION_ACTION = 'PUT_TAGGING'; function objectPutTagging(authInfo, request, log, callback) { log.debug('processing request', { method: 'objectPutTagging' }); - const bucketName = request.bucketName; - const objectKey = request.objectKey; + const { bucketName, objectKey } = request; const decodedVidResult = decodeVersionId(request.query); if (decodedVidResult instanceof Error) { @@ -45,12 +44,12 @@ function objectPutTagging(authInfo, request, log, callback) { objectKey, versionId: reqVersionId, getDeleteMarker: true, - requestType: 'objectPutTagging', + requestType: request.apiMethods || 'objectPutTagging', request, }; return async.waterfall([ - next => metadataValidateBucketAndObj(metadataValParams, log, + next => standardMetadataValidateBucketAndObj(metadataValParams, request.actionImplicitDenies, log, (err, bucket, objectMD) => { if (err) { log.trace('request authorization failed', diff --git a/lib/metadata/metadataUtils.js b/lib/metadata/metadataUtils.js index ef93f24b23..f01f62696d 100644 --- a/lib/metadata/metadataUtils.js +++ b/lib/metadata/metadataUtils.js @@ -133,7 +133,8 @@ function metadataGetObjects(bucketName, objectsKeys, log, cb) { * @param {string} params.requestType - type of request * @param {string} [params.preciseRequestType] - precise type of request * @param {object} params.request - http request object - * @param {RequestLogger} log - request logger + * @param {RequestLogger} log - request logger + * @param {object} actionImplicitDenies - identity authorization results * @return {ArsenalError|null} returns a validation error, or null if validation OK * The following errors may be returned: * - NoSuchBucket: bucket is shielded @@ -141,8 +142,9 @@ function metadataGetObjects(bucketName, objectsKeys, log, cb) { * bucket policy operation * - AccessDenied: bucket is not authorized */ -function validateBucket(bucket, params, log) { - const { authInfo, requestType, preciseRequestType, request } = params; +function validateBucket(bucket, params, log, actionImplicitDenies = {}) { + const { authInfo, preciseRequestType, request } = params; + let requestType = params.requestType; if (bucketShield(bucket, requestType)) { log.debug('bucket is shielded from request', { requestType, @@ -154,11 +156,14 @@ function validateBucket(bucket, params, log) { // MethodNotAllowed error const onlyOwnerAllowed = ['bucketDeletePolicy', 'bucketGetPolicy', 'bucketPutPolicy']; const canonicalID = authInfo.getCanonicalID(); - if (bucket.getOwner() !== canonicalID && onlyOwnerAllowed.includes(requestType)) { + if (!Array.isArray(requestType)) { + requestType = [requestType]; + } + if (bucket.getOwner() !== canonicalID && requestType.some(type => onlyOwnerAllowed.includes(type))) { return errors.MethodNotAllowed; } if (!isBucketAuthorized(bucket, (preciseRequestType || requestType), canonicalID, - authInfo, log, request)) { + authInfo, log, request, actionImplicitDenies)) { log.debug('access denied for user on bucket', { requestType }); return errors.AccessDenied; } @@ -228,6 +233,84 @@ function metadataValidateBucketAndObj(params, log, callback) { }); } +/** standardMetadataValidateBucketAndObj - retrieve bucket and object md from metadata + * and check if user is authorized to access them. + * @param {object} params - function parameters + * @param {AuthInfo} params.authInfo - AuthInfo class instance, requester's info + * @param {string} params.bucketName - name of bucket + * @param {string} params.objectKey - name of object + * @param {string} [params.versionId] - version id if getting specific version + * @param {string} params.requestType - type of request + * @param {object} params.request - http request object + * @param {boolean} actionImplicitDenies - identity authorization results + * @param {RequestLogger} log - request logger + * @param {function} callback - callback + * @return {undefined} - and call callback with params err, bucket md + */ +function standardMetadataValidateBucketAndObj(params, actionImplicitDenies, log, callback) { + const { authInfo, bucketName, objectKey, versionId, getDeleteMarker, request } = params; + let requestType = params.requestType; + if (!Array.isArray(requestType)) { + requestType = [requestType]; + } + async.waterfall([ + next => { + // versionId may be 'null', which asks metadata to fetch the null key specifically + const getOptions = { versionId }; + if (getDeleteMarker) { + getOptions.getDeleteMarker = true; + } + return metadata.getBucketAndObjectMD(bucketName, objectKey, getOptions, log, (err, getResult) => { + if (err) { + // if some implicit iamAuthzResults, return AccessDenied + // before leaking any state information + if (actionImplicitDenies && Object.values(actionImplicitDenies).some(v => v === true)) { + return next(errors.AccessDenied); + } + return next(err); + } + return next(null, getResult); + }); + }, + (getResult, next) => { + const bucket = getResult.bucket ? + BucketInfo.deSerialize(getResult.bucket) : undefined; + if (!bucket) { + log.debug('bucketAttrs is undefined', { + bucket: bucketName, + method: 'metadataValidateBucketAndObj', + }); + return next(errors.NoSuchBucket); + } + const validationError = validateBucket(bucket, params, log, actionImplicitDenies); + if (validationError) { + return next(validationError, bucket); + } + const objMD = getResult.obj ? JSON.parse(getResult.obj) : undefined; + if (!objMD && versionId === 'null') { + return getNullVersionFromMaster(bucketName, objectKey, log, + (err, nullVer) => next(err, bucket, nullVer)); + } + return next(null, bucket, objMD); + }, + (bucket, objMD, next) => { + const canonicalID = authInfo.getCanonicalID(); + if (!isObjAuthorized(bucket, objMD, requestType, canonicalID, authInfo, log, request, + actionImplicitDenies)) { + log.debug('access denied for user on object', { requestType }); + return next(errors.AccessDenied, bucket); + } + return next(null, bucket, objMD); + }, + ], (err, bucket, objMD) => { + if (err) { + // still return bucket for cors headers + return callback(err, bucket); + } + return callback(null, bucket, objMD); + }); +} + /** metadataValidateBucket - retrieve bucket from metadata and check if user * is authorized to access it * @param {object} params - function parameters @@ -251,10 +334,41 @@ function metadataValidateBucket(params, log, callback) { }); } +/** standardMetadataValidateBucket - retrieve bucket from metadata and check if user + * is authorized to access it + * @param {object} params - function parameters + * @param {AuthInfo} params.authInfo - AuthInfo class instance, requester's info + * @param {string} params.bucketName - name of bucket + * @param {string} params.requestType - type of request + * @param {string} params.request - http request object + * @param {boolean} actionImplicitDenies - identity authorization results + * @param {RequestLogger} log - request logger + * @param {function} callback - callback + * @return {undefined} - and call callback with params err, bucket md + */ +function standardMetadataValidateBucket(params, actionImplicitDenies, log, callback) { + const { bucketName } = params; + return metadata.getBucket(bucketName, log, (err, bucket) => { + if (err) { + // if some implicit actionImplicitDenies, return AccessDenied before + // leaking any state information + if (actionImplicitDenies && Object.values(actionImplicitDenies).some(v => v === true)) { + return callback(errors.AccessDenied); + } + log.debug('metadata getbucket failed', { error: err }); + return callback(err); + } + const validationError = validateBucket(bucket, params, log, actionImplicitDenies); + return callback(validationError, bucket); + }); +} + module.exports = { validateBucket, metadataGetObject, metadataGetObjects, metadataValidateBucketAndObj, + standardMetadataValidateBucketAndObj, metadataValidateBucket, + standardMetadataValidateBucket, }; diff --git a/package.json b/package.json index 067492c762..f702e41d10 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zenko/cloudserver", - "version": "8.7.31", + "version": "8.7.32", "description": "Zenko CloudServer, an open-source Node.js implementation of a server handling the Amazon S3 protocol", "main": "index.js", "engines": { diff --git a/tests/multipleBackend/objectPutCopyPart.js b/tests/multipleBackend/objectPutCopyPart.js index 2d7e942aad..f59a8f6c90 100644 --- a/tests/multipleBackend/objectPutCopyPart.js +++ b/tests/multipleBackend/objectPutCopyPart.js @@ -87,6 +87,7 @@ errorPutCopyPart) { objectKey: destObjName, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: `/${destObjName}?uploads`, + actionImplicitDenies: false, }; if (mpuLoc) { initiateReq.headers = { 'host': `${bucketName}.s3.amazonaws.com`, @@ -101,6 +102,7 @@ errorPutCopyPart) { objectKey: sourceObjName, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; if (srcObjLoc) { sourceObjPutParams.headers = { 'host': `${bucketName}.s3.amazonaws.com`, diff --git a/tests/multipleBackend/objectPutPart.js b/tests/multipleBackend/objectPutPart.js index bdc6345701..b418a1e47d 100644 --- a/tests/multipleBackend/objectPutPart.js +++ b/tests/multipleBackend/objectPutPart.js @@ -73,6 +73,7 @@ errorDescription) { objectKey: objectName, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: `/${objectName}?uploads`, + actionImplicitDenies: false, }; if (mpuLoc) { initiateReq.headers = { 'host': `${bucketName}.s3.amazonaws.com`, diff --git a/tests/unit/DummyRequest.js b/tests/unit/DummyRequest.js index e61c37feda..28b21337eb 100644 --- a/tests/unit/DummyRequest.js +++ b/tests/unit/DummyRequest.js @@ -16,7 +16,7 @@ class DummyRequest extends http.IncomingMessage { this.parsedContentLength = 0; } } - + this.actionImplicitDenies = false; if (Array.isArray(msg)) { msg.forEach(part => { this.push(part); diff --git a/tests/unit/api/apiUtils/tagConditionKeys.js b/tests/unit/api/apiUtils/tagConditionKeys.js index ff52d442a9..3a65340273 100644 --- a/tests/unit/api/apiUtils/tagConditionKeys.js +++ b/tests/unit/api/apiUtils/tagConditionKeys.js @@ -24,6 +24,7 @@ const bucketPutReq = { bucketName, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; const taggingUtil = new TaggingConfigTester(); diff --git a/tests/unit/api/bucketPutACL.js b/tests/unit/api/bucketPutACL.js index 9e8ac7c936..dfc507c2bd 100644 --- a/tests/unit/api/bucketPutACL.js +++ b/tests/unit/api/bucketPutACL.js @@ -71,6 +71,7 @@ describe('putBucketACL API', () => { }, url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { @@ -89,6 +90,7 @@ describe('putBucketACL API', () => { }, url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { assert.strictEqual(err, undefined); @@ -110,6 +112,7 @@ describe('putBucketACL API', () => { }, url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; const testACLRequest2 = { bucketName, @@ -120,6 +123,7 @@ describe('putBucketACL API', () => { }, url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { assert.strictEqual(err, undefined); @@ -148,6 +152,7 @@ describe('putBucketACL API', () => { }, url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; const testACLRequest2 = { bucketName, @@ -158,6 +163,7 @@ describe('putBucketACL API', () => { }, url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { @@ -196,6 +202,7 @@ describe('putBucketACL API', () => { }, url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { assert.strictEqual(err, undefined); @@ -237,6 +244,7 @@ describe('putBucketACL API', () => { }, url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { assert.strictEqual(err, undefined); @@ -270,6 +278,7 @@ describe('putBucketACL API', () => { }, url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; return bucketPutACL(authInfo, testACLRequest, log, err => { assert.strictEqual(err.is.InvalidArgument, true); @@ -291,6 +300,7 @@ describe('putBucketACL API', () => { }, url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { @@ -350,6 +360,7 @@ describe('putBucketACL API', () => { '', url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { @@ -385,6 +396,7 @@ describe('putBucketACL API', () => { '', url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { @@ -417,6 +429,7 @@ describe('putBucketACL API', () => { '', url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { @@ -460,6 +473,7 @@ describe('putBucketACL API', () => { '', url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { @@ -492,6 +506,7 @@ describe('putBucketACL API', () => { '', url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; return bucketPutACL(authInfo, testACLRequest, log, err => { @@ -524,6 +539,7 @@ describe('putBucketACL API', () => { '', url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { assert.strictEqual(err.is.UnresolvableGrantByEmailAddress, true); @@ -559,6 +575,7 @@ describe('putBucketACL API', () => { '', url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { @@ -604,6 +621,7 @@ describe('putBucketACL API', () => { '', url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { @@ -639,6 +657,7 @@ describe('putBucketACL API', () => { }, url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { @@ -673,6 +692,7 @@ describe('putBucketACL API', () => { '', url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { @@ -694,6 +714,7 @@ describe('putBucketACL API', () => { }, url: '/?acl', query: { acl: '' }, + actionImplicitDenies: false, }; bucketPutACL(authInfo, testACLRequest, log, err => { diff --git a/tests/unit/api/bucketPutCors.js b/tests/unit/api/bucketPutCors.js index 1ed6af33e1..343410f82b 100644 --- a/tests/unit/api/bucketPutCors.js +++ b/tests/unit/api/bucketPutCors.js @@ -19,6 +19,7 @@ const testBucketPutRequest = { bucketName, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; function _testPutBucketCors(authInfo, request, log, errCode, cb) { diff --git a/tests/unit/api/bucketPutEncryption.js b/tests/unit/api/bucketPutEncryption.js index bc83ef5fe3..592b25008e 100644 --- a/tests/unit/api/bucketPutEncryption.js +++ b/tests/unit/api/bucketPutEncryption.js @@ -14,6 +14,7 @@ const bucketPutRequest = { bucketName, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; describe('bucketPutEncryption API', () => { diff --git a/tests/unit/api/bucketPutLifecycle.js b/tests/unit/api/bucketPutLifecycle.js index 5df87bb21f..b3cd0071ec 100644 --- a/tests/unit/api/bucketPutLifecycle.js +++ b/tests/unit/api/bucketPutLifecycle.js @@ -17,6 +17,7 @@ const testBucketPutRequest = { bucketName, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; const expectedLifecycleConfig = { diff --git a/tests/unit/api/bucketPutNotification.js b/tests/unit/api/bucketPutNotification.js index e7ecceef3e..42456fba5b 100644 --- a/tests/unit/api/bucketPutNotification.js +++ b/tests/unit/api/bucketPutNotification.js @@ -15,6 +15,7 @@ const bucketPutRequest = { bucketName, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; const expectedNotifConfig = { @@ -52,6 +53,7 @@ function getNotifRequest(empty) { host: `${bucketName}.s3.amazonaws.com`, }, post: notifXml, + actionImplicitDenies: false, }; return putNotifConfigRequest; } diff --git a/tests/unit/api/bucketPutObjectLock.js b/tests/unit/api/bucketPutObjectLock.js index b70a42400b..e048bb40f2 100644 --- a/tests/unit/api/bucketPutObjectLock.js +++ b/tests/unit/api/bucketPutObjectLock.js @@ -15,6 +15,7 @@ const bucketPutRequest = { bucketName, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; const objectLockXml = ' { headers: { 'x-amz-acl': 'invalid-option' }, url: `/${bucketName}/${objectName}?acl`, query: { acl: '' }, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -77,6 +78,7 @@ describe('putObjectACL API', () => { headers: { 'x-amz-acl': 'public-read-write' }, url: `/${bucketName}/${objectName}?acl`, query: { acl: '' }, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -106,6 +108,7 @@ describe('putObjectACL API', () => { headers: { 'x-amz-acl': 'public-read' }, url: `/${bucketName}/${objectName}?acl`, query: { acl: '' }, + actionImplicitDenies: false, }; const testObjACLRequest2 = { @@ -115,6 +118,7 @@ describe('putObjectACL API', () => { headers: { 'x-amz-acl': 'authenticated-read' }, url: `/${bucketName}/${objectName}?acl`, query: { acl: '' }, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -160,6 +164,7 @@ describe('putObjectACL API', () => { }, url: `/${bucketName}/${objectName}?acl`, query: { acl: '' }, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { objectPut(authInfo, testPutObjectRequest, undefined, log, @@ -202,6 +207,7 @@ describe('putObjectACL API', () => { }, url: `/${bucketName}/${objectName}?acl`, query: { acl: '' }, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -232,6 +238,7 @@ describe('putObjectACL API', () => { url: `/${bucketName}/${objectName}?acl`, post: [Buffer.from(acp.getXml(), 'utf8')], query: { acl: '' }, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -269,6 +276,7 @@ describe('putObjectACL API', () => { url: `/${bucketName}/${objectName}?acl`, post: [Buffer.from(acp.getXml(), 'utf8')], query: { acl: '' }, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -296,6 +304,7 @@ describe('putObjectACL API', () => { url: `/${bucketName}/${objectName}?acl`, post: [Buffer.from(acp.getXml(), 'utf8')], query: { acl: '' }, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -334,6 +343,7 @@ describe('putObjectACL API', () => { url: `/${bucketName}/${objectName}?acl`, post: [Buffer.from(acp.getXml(), 'utf8')], query: { acl: '' }, + actionImplicitDenies: false, }; @@ -363,6 +373,7 @@ describe('putObjectACL API', () => { url: `/${bucketName}/${objectName}?acl`, post: [Buffer.from(modifiedXml, 'utf8')], query: { acl: '' }, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -390,6 +401,7 @@ describe('putObjectACL API', () => { url: `/${bucketName}/${objectName}?acl`, post: [Buffer.from(modifiedXml, 'utf8')], query: { acl: '' }, + actionImplicitDenies: false, }; @@ -418,6 +430,7 @@ describe('putObjectACL API', () => { url: `/${bucketName}/${objectName}?acl`, post: [Buffer.from(acp.getXml(), 'utf8')], query: { acl: '' }, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -446,6 +459,7 @@ describe('putObjectACL API', () => { }, url: `/${bucketName}/${objectName}?acl`, query: { acl: '' }, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { diff --git a/tests/unit/api/objectPutLegalHold.js b/tests/unit/api/objectPutLegalHold.js index 2ab27b8770..839d7d7edf 100644 --- a/tests/unit/api/objectPutLegalHold.js +++ b/tests/unit/api/objectPutLegalHold.js @@ -19,6 +19,7 @@ const putBucketRequest = { bucketName, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; const putObjectRequest = new DummyRequest({ @@ -39,6 +40,7 @@ const putLegalHoldReq = status => ({ objectKey: objectName, headers: { host: `${bucketName}.s3.amazonaws.com` }, post: objectLegalHoldXml(status), + actionImplicitDenies: false, }); describe('putObjectLegalHold API', () => { diff --git a/tests/unit/api/objectPutRetention.js b/tests/unit/api/objectPutRetention.js index 2fdf3a5cf8..ec14530ef5 100644 --- a/tests/unit/api/objectPutRetention.js +++ b/tests/unit/api/objectPutRetention.js @@ -22,6 +22,7 @@ const bucketPutRequest = { bucketName, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; const putObjectRequest = new DummyRequest({ @@ -67,6 +68,7 @@ const putObjRetRequestGovernance = { objectKey: objectName, headers: { host: `${bucketName}.s3.amazonaws.com` }, post: objectRetentionXmlGovernance, + actionImplicitDenies: false, }; const putObjRetRequestGovernanceWithHeader = { @@ -77,6 +79,7 @@ const putObjRetRequestGovernanceWithHeader = { 'x-amz-bypass-governance-retention': 'true', }, post: objectRetentionXmlGovernance, + actionImplicitDenies: false, }; const putObjRetRequestCompliance = { @@ -84,6 +87,7 @@ const putObjRetRequestCompliance = { objectKey: objectName, headers: { host: `${bucketName}.s3.amazonaws.com` }, post: objectRetentionXmlCompliance, + actionImplicitDenies: false, }; const putObjRetRequestComplianceShorter = { @@ -91,6 +95,7 @@ const putObjRetRequestComplianceShorter = { objectKey: objectName, headers: { host: `${bucketName}.s3.amazonaws.com` }, post: objectRetentionXmlComplianceShorter, + actionImplicitDenies: false, }; const putObjRetRequestGovernanceLonger = { @@ -98,6 +103,7 @@ const putObjRetRequestGovernanceLonger = { objectKey: objectName, headers: { host: `${bucketName}.s3.amazonaws.com` }, post: objectRetentionXmlGovernanceLonger, + actionImplicitDenies: false, }; const putObjRetRequestGovernanceShorter = { @@ -105,6 +111,7 @@ const putObjRetRequestGovernanceShorter = { objectKey: objectName, headers: { host: `${bucketName}.s3.amazonaws.com` }, post: objectRetentionXmlGovernanceShorter, + actionImplicitDenies: false, }; describe('putObjectRetention API', () => { diff --git a/tests/unit/api/objectPutTagging.js b/tests/unit/api/objectPutTagging.js index 72a0dbbb6b..faa6d9a188 100644 --- a/tests/unit/api/objectPutTagging.js +++ b/tests/unit/api/objectPutTagging.js @@ -25,6 +25,7 @@ const testBucketPutRequest = { bucketName, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; const testPutObjectRequest = new DummyRequest({ @@ -172,8 +173,7 @@ describe('PUT object tagging :: helper validation functions ', () => { taggingTests.forEach(taggingTest => { it(taggingTest.it, done => { - const key = taggingTest.tag.key; - const value = taggingTest.tag.value; + const { tag: { key, value } } = taggingTest; const xml = _generateSampleXml(key, value); parseTagXml(xml, log, (err, result) => { if (taggingTest.error) { diff --git a/tests/unit/helpers.js b/tests/unit/helpers.js index feb61612b7..619e64bc4c 100644 --- a/tests/unit/helpers.js +++ b/tests/unit/helpers.js @@ -336,6 +336,7 @@ class CorsConfigTester { }, url: '/?cors', query: { cors: '' }, + actionImplicitDenies: false, }; if (method === 'PUT') { request.post = body || this.constructXml(); @@ -377,6 +378,7 @@ const versioningTestUtils = { }, url: '/?versioning', query: { versioning: '' }, + actionImplicitDenies: false, }; const xml = '' + @@ -427,6 +429,7 @@ class TaggingConfigTester { objectKey: objectName, url: '/?tagging', query: { tagging: '' }, + actionImplicitDenies: false, }; if (method === 'PUT') { request.post = body || this.constructXml(); diff --git a/tests/unit/metadata/metadataUtils.spec.js b/tests/unit/metadata/metadataUtils.spec.js index ef83c607bb..5c85d9255b 100644 --- a/tests/unit/metadata/metadataUtils.spec.js +++ b/tests/unit/metadata/metadataUtils.spec.js @@ -23,7 +23,7 @@ describe('validateBucket', () => { authInfo, requestType: 'bucketPutPolicy', request: null, - }, log); + }, log, false); assert.ifError(validationResult); }); it('action bucketPutPolicy by other than bucket owner', () => { @@ -31,7 +31,7 @@ describe('validateBucket', () => { authInfo: otherAuthInfo, requestType: 'bucketPutPolicy', request: null, - }, log); + }, log, false); assert(validationResult); assert(validationResult.is.MethodNotAllowed); }); @@ -41,7 +41,7 @@ describe('validateBucket', () => { authInfo, requestType: 'bucketGet', request: null, - }, log); + }, log, false); assert.ifError(validationResult); }); @@ -50,7 +50,7 @@ describe('validateBucket', () => { authInfo: otherAuthInfo, requestType: 'bucketGet', request: null, - }, log); + }, log, false); assert(validationResult); assert(validationResult.is.AccessDenied); });