diff --git a/lib/api/apiUtils/authorization/permissionChecks.js b/lib/api/apiUtils/authorization/permissionChecks.js index aae51f5040..4d0d4a7545 100644 --- a/lib/api/apiUtils/authorization/permissionChecks.js +++ b/lib/api/apiUtils/authorization/permissionChecks.js @@ -290,11 +290,11 @@ function _checkPrincipals(canonicalID, arn, principal) { return false; } -function checkBucketPolicy(policy, requestType, canonicalID, arn, bucketOwner, log, request) { +function checkBucketPolicy(policy, requestType, canonicalID, arn, bucketOwner, log, request, actionImplicitDenies) { let permission = 'defaultDeny'; // if requester is user within bucket owner account, actions should be // allowed unless explicitly denied (assumes allowed by IAM policy) - if (bucketOwner === canonicalID) { + if (bucketOwner === canonicalID && actionImplicitDenies[requestType] === false) { permission = 'allow'; } let copiedStatement = JSON.parse(JSON.stringify(policy.Statement)); @@ -324,7 +324,7 @@ function processBucketPolicy(requestType, bucket, canonicalID, arn, bucketOwner, processedResult = actionImplicitDenies[requestType] === false && aclPermission; } else { const bucketPolicyPermission = checkBucketPolicy(bucketPolicy, requestType, canonicalID, arn, - bucketOwner, log, request); + bucketOwner, log, request, actionImplicitDenies); if (bucketPolicyPermission === 'explicitDeny') { processedResult = false; diff --git a/lib/api/apiUtils/bucket/bucketDeletion.js b/lib/api/apiUtils/bucket/bucketDeletion.js index f9d9cd2d07..bd23226150 100644 --- a/lib/api/apiUtils/bucket/bucketDeletion.js +++ b/lib/api/apiUtils/bucket/bucketDeletion.js @@ -24,7 +24,7 @@ function _deleteMPUbucket(destinationBucketName, log, cb) { }); } -function _deleteOngoingMPUs(authInfo, bucketName, bucketMD, mpus, log, cb) { +function _deleteOngoingMPUs(authInfo, bucketName, bucketMD, mpus, request, log, cb) { async.mapLimit(mpus, 1, (mpu, next) => { const splitterChar = mpu.key.includes(oldSplitter) ? oldSplitter : splitter; @@ -40,7 +40,7 @@ function _deleteOngoingMPUs(authInfo, bucketName, bucketMD, mpus, log, cb) { byteLength: partSizeSum, }); next(err); - }); + }, request); }, cb); } /** @@ -49,11 +49,13 @@ function _deleteOngoingMPUs(authInfo, bucketName, bucketMD, mpus, log, cb) { * @param {object} bucketMD - bucket attributes/metadata * @param {string} bucketName - bucket in which objectMetadata is stored * @param {string} canonicalID - account canonicalID of requester + * @param {object} request - request object given by router + * including normalized headers * @param {object} log - Werelogs logger * @param {function} cb - callback from async.waterfall in bucketDelete * @return {undefined} */ -function deleteBucket(authInfo, bucketMD, bucketName, canonicalID, log, cb) { +function deleteBucket(authInfo, bucketMD, bucketName, canonicalID, request, log, cb) { log.trace('deleting bucket from metadata'); assert.strictEqual(typeof bucketName, 'string'); assert.strictEqual(typeof canonicalID, 'string'); @@ -100,7 +102,7 @@ function deleteBucket(authInfo, bucketMD, bucketName, canonicalID, log, cb) { } if (objectsListRes.Contents.length) { return _deleteOngoingMPUs(authInfo, bucketName, - bucketMD, objectsListRes.Contents, log, err => { + bucketMD, objectsListRes.Contents, request, log, err => { if (err) { return next(err); } diff --git a/lib/api/apiUtils/object/abortMultipartUpload.js b/lib/api/apiUtils/object/abortMultipartUpload.js index 59c93aaa35..6f04f4351d 100644 --- a/lib/api/apiUtils/object/abortMultipartUpload.js +++ b/lib/api/apiUtils/object/abortMultipartUpload.js @@ -3,7 +3,7 @@ const async = require('async'); const constants = require('../../../../constants'); const { data } = require('../../../data/wrapper'); const locationConstraintCheck = require('../object/locationConstraintCheck'); -const { metadataValidateBucketAndObj } = +const { standardMetadataValidateBucketAndObj } = require('../../../metadata/metadataUtils'); const services = require('../../../services'); @@ -22,10 +22,11 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log, // but the requestType is the more general 'objectDelete' const metadataValParams = Object.assign({}, metadataValMPUparams); metadataValParams.requestType = 'objectPut'; + const authzIdentityResult = request ? request.actionImplicitDenies : false; async.waterfall([ function checkDestBucketVal(next) { - metadataValidateBucketAndObj(metadataValParams, log, + standardMetadataValidateBucketAndObj(metadataValParams, authzIdentityResult, log, (err, destinationBucket) => { if (err) { return next(err, destinationBucket); @@ -56,9 +57,14 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log, function abortExternalMpu(mpuBucket, mpuOverviewObj, destBucket, next) { const location = mpuOverviewObj.controllingLocationConstraint; + const originalIdentityAuthzResults = request.actionImplicitDenies; + // eslint-disable-next-line no-param-reassign + delete request.actionImplicitDenies; return data.abortMPU(objectKey, uploadId, location, bucketName, request, destBucket, locationConstraintCheck, log, (err, skipDataDelete) => { + // eslint-disable-next-line no-param-reassign + request.actionImplicitDenies = originalIdentityAuthzResults; if (err) { return next(err, destBucket); } diff --git a/lib/api/apiUtils/object/objectLockHelpers.js b/lib/api/apiUtils/object/objectLockHelpers.js index 97b7583aef..e0ae0abc0f 100644 --- a/lib/api/apiUtils/object/objectLockHelpers.js +++ b/lib/api/apiUtils/object/objectLockHelpers.js @@ -3,6 +3,7 @@ const moment = require('moment'); const { config } = require('../../../Config'); const vault = require('../../../auth/vault'); +const { evaluateBucketPolicyWithIAM } = require('../authorization/permissionChecks'); const { scaledMsPerDay } = config.getTimeOptions(); /** @@ -304,7 +305,9 @@ function checkUserGovernanceBypass(request, authInfo, bucketMD, objectKey, log, if (err) { return cb(err); } - if (authorizationResults[0].isAllowed !== true) { + const explicitDenyExists = authorizationResults.some( + authzResult => authzResult.isAllowed === false && authzResult.isImplicit === false); + if (explicitDenyExists) { log.trace('authorization check failed for user', { 'method': 'checkUserPolicyGovernanceBypass', @@ -312,7 +315,25 @@ function checkUserGovernanceBypass(request, authInfo, bucketMD, objectKey, log, }); return cb(errors.AccessDenied); } - return cb(null); + // Convert authorization results into an easier to handle format + const actionImplicitDenies = authorizationResults.reduce((acc, curr, idx) => { + const apiMethod = authorizationResults[idx].action; + // eslint-disable-next-line no-param-reassign + acc[apiMethod] = curr.isImplicit; + return acc; + }, {}); + + // Evaluate against the bucket policies + const areAllActionsAllowed = evaluateBucketPolicyWithIAM( + bucketMD, + Object.keys(actionImplicitDenies), + authInfo.getCanonicalID(), + authInfo, + actionImplicitDenies, + log, + request); + + return cb(areAllActionsAllowed === true ? null : errors.AccessDenied); }); } diff --git a/lib/api/bucketDelete.js b/lib/api/bucketDelete.js index 5b4a3b4fee..78af94dec4 100644 --- a/lib/api/bucketDelete.js +++ b/lib/api/bucketDelete.js @@ -48,7 +48,7 @@ function bucketDelete(authInfo, request, log, cb) { log.trace('passed checks', { method: 'metadataValidateBucket' }); return deleteBucket(authInfo, bucketMD, bucketName, - authInfo.getCanonicalID(), log, err => { + authInfo.getCanonicalID(), request, log, err => { if (err) { monitoring.promMetrics( 'DELETE', bucketName, err.code, 'deleteBucket'); diff --git a/lib/api/bucketHead.js b/lib/api/bucketHead.js index 2faf8b9da4..97e460f698 100644 --- a/lib/api/bucketHead.js +++ b/lib/api/bucketHead.js @@ -1,5 +1,5 @@ const collectCorsHeaders = require('../utilities/collectCorsHeaders'); -const { metadataValidateBucket } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucket } = require('../metadata/metadataUtils'); const { pushMetric } = require('../utapi/utilities'); const monitoring = require('../utilities/monitoringHandler'); @@ -22,7 +22,7 @@ function bucketHead(authInfo, request, log, callback) { requestType: 'bucketHead', request, }; - metadataValidateBucket(metadataValParams, log, (err, bucket) => { + standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log, (err, bucket) => { const corsHeaders = collectCorsHeaders(request.headers.origin, request.method, bucket); if (err) { diff --git a/lib/api/completeMultipartUpload.js b/lib/api/completeMultipartUpload.js index 35d1b4dc6b..880388104e 100644 --- a/lib/api/completeMultipartUpload.js +++ b/lib/api/completeMultipartUpload.js @@ -12,7 +12,7 @@ const constants = require('../../constants'); const { versioningPreprocessing, checkQueryVersionId, decodeVID, overwritingVersioning } = require('./apiUtils/object/versioning'); const services = require('../services'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const locationConstraintCheck = require('./apiUtils/object/locationConstraintCheck'); const { skipMpuPartProcessing } = storage.data.external.backendUtils; @@ -136,7 +136,7 @@ function completeMultipartUpload(authInfo, request, log, callback) { requestType: 'objectPut', versionId, }; - metadataValidateBucketAndObj(metadataValParams, log, next); + standardMetadataValidateBucketAndObj(metadataValParams, request.actionImplicitDenies, log, next); }, function validateMultipart(destBucket, objMD, next) { if (objMD) { @@ -214,9 +214,14 @@ function completeMultipartUpload(authInfo, request, log, callback) { const mdInfo = { storedParts, mpuOverviewKey, splitter }; const mpuInfo = { objectKey, uploadId, jsonList, bucketName, destBucket }; + const originalIdentityImpDenies = request.actionImplicitDenies; + // eslint-disable-next-line no-param-reassign + delete request.actionImplicitDenies; return data.completeMPU(request, mpuInfo, mdInfo, location, null, null, null, locationConstraintCheck, log, (err, completeObjData) => { + // eslint-disable-next-line no-param-reassign + request.actionImplicitDenies = originalIdentityImpDenies; if (err) { return next(err, destBucket); } diff --git a/lib/api/initiateMultipartUpload.js b/lib/api/initiateMultipartUpload.js index a714f43e95..a7c5c71ff2 100644 --- a/lib/api/initiateMultipartUpload.js +++ b/lib/api/initiateMultipartUpload.js @@ -9,7 +9,7 @@ const { hasNonPrintables } = require('../utilities/stringChecks'); const { cleanUpBucket } = require('./apiUtils/bucket/bucketCreation'); const constants = require('../../constants'); const services = require('../services'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const locationConstraintCheck = require('./apiUtils/object/locationConstraintCheck'); const validateWebsiteHeader = require('./apiUtils/object/websiteServing') @@ -274,7 +274,7 @@ function initiateMultipartUpload(authInfo, request, log, callback) { } async.waterfall([ - next => metadataValidateBucketAndObj(metadataValParams, log, + next => standardMetadataValidateBucketAndObj(metadataValParams, request.actionImplicitDenies, log, (error, destinationBucket) => { const corsHeaders = collectCorsHeaders(request.headers.origin, request.method, destinationBucket); if (error) { diff --git a/lib/api/listMultipartUploads.js b/lib/api/listMultipartUploads.js index b88fd495e5..594186a12a 100644 --- a/lib/api/listMultipartUploads.js +++ b/lib/api/listMultipartUploads.js @@ -6,7 +6,7 @@ const convertToXml = s3middleware.convertToXml; const constants = require('../../constants'); const collectCorsHeaders = require('../utilities/collectCorsHeaders'); const services = require('../services'); -const { metadataValidateBucket } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucket } = require('../metadata/metadataUtils'); const { pushMetric } = require('../utapi/utilities'); const monitoring = require('../utilities/monitoringHandler'); @@ -105,7 +105,7 @@ function listMultipartUploads(authInfo, request, log, callback) { function waterfall1(next) { // Check final destination bucket for authorization rather // than multipart upload bucket - metadataValidateBucket(metadataValParams, log, + standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log, (err, bucket) => next(err, bucket)); }, function getMPUBucket(bucket, next) { diff --git a/lib/api/listParts.js b/lib/api/listParts.js index 521e26deff..eedb52a33d 100644 --- a/lib/api/listParts.js +++ b/lib/api/listParts.js @@ -8,7 +8,7 @@ const collectCorsHeaders = require('../utilities/collectCorsHeaders'); const locationConstraintCheck = require('./apiUtils/object/locationConstraintCheck'); const services = require('../services'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const escapeForXml = s3middleware.escapeForXml; const { pushMetric } = require('../utapi/utilities'); const monitoring = require('../utilities/monitoringHandler'); @@ -114,7 +114,7 @@ function listParts(authInfo, request, log, callback) { async.waterfall([ function checkDestBucketVal(next) { - metadataValidateBucketAndObj(metadataValParams, log, + standardMetadataValidateBucketAndObj(metadataValParams, request.actionImplicitDenies, log, (err, destinationBucket) => { if (err) { return next(err, destinationBucket, null); @@ -152,8 +152,13 @@ function listParts(authInfo, request, log, callback) { mpuOverviewObj, destBucket, }; + const originalIdentityImpDenies = request.actionImplicitDenies; + // eslint-disable-next-line no-param-reassign + delete request.actionImplicitDenies; return data.listParts(mpuInfo, request, locationConstraintCheck, log, (err, backendPartList) => { + // eslint-disable-next-line no-param-reassign + request.actionImplicitDenies = originalIdentityImpDenies; if (err) { return next(err, destBucket); } diff --git a/lib/api/objectCopy.js b/lib/api/objectCopy.js index 3348e2b754..cd4fddce38 100644 --- a/lib/api/objectCopy.js +++ b/lib/api/objectCopy.js @@ -16,7 +16,7 @@ const logger = require('../utilities/logger'); const services = require('../services'); const { pushMetric } = require('../utapi/utilities'); const removeAWSChunked = require('./apiUtils/object/removeAWSChunked'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const validateWebsiteHeader = require('./apiUtils/object/websiteServing') .validateWebsiteHeader; const { config } = require('../Config'); @@ -261,7 +261,7 @@ function objectCopy(authInfo, request, sourceBucket, } return async.waterfall([ function checkDestAuth(next) { - return metadataValidateBucketAndObj(valPutParams, log, + return standardMetadataValidateBucketAndObj(valPutParams, request.actionImplicitDenies, log, (err, destBucketMD, destObjMD) => { if (err) { log.debug('error validating put part of request', @@ -279,7 +279,7 @@ function objectCopy(authInfo, request, sourceBucket, }); }, function checkSourceAuthorization(destBucketMD, destObjMD, next) { - return metadataValidateBucketAndObj(valGetParams, log, + return standardMetadataValidateBucketAndObj(valGetParams, request.actionImplicitDenies, log, (err, sourceBucketMD, sourceObjMD) => { if (err) { log.debug('error validating get part of request', @@ -450,10 +450,15 @@ function objectCopy(authInfo, request, sourceBucket, return next(null, storeMetadataParams, dataLocator, destObjMD, serverSideEncryption, destBucketMD); } + const originalIdentityImpDenies = request.actionImplicitDenies; + // eslint-disable-next-line no-param-reassign + delete request.actionImplicitDenies; return data.copyObject(request, sourceLocationConstraintName, storeMetadataParams, dataLocator, dataStoreContext, backendInfoDest, sourceBucketMD, destBucketMD, serverSideEncryption, log, (err, results) => { + // eslint-disable-next-line no-param-reassign + request.actionImplicitDenies = originalIdentityImpDenies; if (err) { return next(err, destBucketMD); } diff --git a/lib/api/objectHead.js b/lib/api/objectHead.js index 0a6bbe513f..b67bf3ae66 100644 --- a/lib/api/objectHead.js +++ b/lib/api/objectHead.js @@ -13,7 +13,7 @@ const { getPartNumber, getPartSize, getPartCountFromMd5 } = const { config } = require('../Config'); const { locationConstraints } = config; -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const { maximumAllowedPartCount } = require('../../constants'); const { setExpirationHeaders } = require('./apiUtils/object/expirationHeaders'); @@ -52,7 +52,7 @@ function objectHead(authInfo, request, log, callback) { request, }; - return metadataValidateBucketAndObj(mdValParams, log, + return standardMetadataValidateBucketAndObj(mdValParams, request.actionImplicitDenies, log, (err, bucket, objMD) => { const corsHeaders = collectCorsHeaders(request.headers.origin, request.method, bucket); diff --git a/lib/api/websiteHead.js b/lib/api/websiteHead.js index dca9b8b36b..fa743f16e2 100644 --- a/lib/api/websiteHead.js +++ b/lib/api/websiteHead.js @@ -111,7 +111,7 @@ function websiteHead(request, log, callback) { { error: err }); let returnErr = err; const bucketAuthorized = isBucketAuthorized(bucket, - 'bucketGet', constants.publicId, null, log, request); + 'bucketGet', constants.publicId, null, log, request, request.actionImplicitDenies); // if index object does not exist and bucket is private AWS // returns 403 - AccessDenied error. if (err.is.NoSuchKey && !bucketAuthorized) { @@ -121,7 +121,7 @@ function websiteHead(request, log, callback) { reqObjectKey, corsHeaders, log, callback); } if (!isObjAuthorized(bucket, objMD, 'objectGet', - constants.publicId, null, log, request)) { + constants.publicId, null, log, request, request.actionImplicitDenies)) { const err = errors.AccessDenied; log.trace('request not authorized', { error: err }); return _errorActions(err, routingRules, reqObjectKey, diff --git a/lib/metadata/metadataUtils.js b/lib/metadata/metadataUtils.js index f01f62696d..d3eb365007 100644 --- a/lib/metadata/metadataUtils.js +++ b/lib/metadata/metadataUtils.js @@ -368,7 +368,7 @@ module.exports = { metadataGetObject, metadataGetObjects, metadataValidateBucketAndObj, - standardMetadataValidateBucketAndObj, metadataValidateBucket, + standardMetadataValidateBucketAndObj, standardMetadataValidateBucket, }; diff --git a/lib/routes/routeBackbeat.js b/lib/routes/routeBackbeat.js index 99769b713b..cc75771877 100644 --- a/lib/routes/routeBackbeat.js +++ b/lib/routes/routeBackbeat.js @@ -27,7 +27,7 @@ const prepareRequestContexts = require( const { decodeVersionId } = require('../api/apiUtils/object/versioning'); const locationKeysHaveChanged = require('../api/apiUtils/object/locationKeysHaveChanged'); -const { metadataValidateBucketAndObj, +const { standardMetadataValidateBucketAndObj, metadataGetObject } = require('../metadata/metadataUtils'); const { config } = require('../Config'); const constants = require('../../constants'); @@ -77,6 +77,7 @@ function _normalizeBackbeatRequest(req) { req.resourceType = pathArr[3]; req.bucketName = pathArr[4]; req.objectKey = pathArr.slice(5).join('/'); + req.actionImplicitDenies = false; /* eslint-enable no-param-reassign */ } @@ -1344,7 +1345,6 @@ function routeBackbeat(clientIP, request, response, log) { // Attach the apiMethod method to the request, so it can used by monitoring in the server // eslint-disable-next-line no-param-reassign request.apiMethod = 'routeBackbeat'; - log.debug('routing request', { method: 'routeBackbeat', url: request.url, @@ -1484,7 +1484,7 @@ function routeBackbeat(clientIP, request, response, log) { requestType: 'ReplicateObject', request, }; - return metadataValidateBucketAndObj(mdValParams, log, next); + return standardMetadataValidateBucketAndObj(mdValParams, request.actionImplicitDenies, log, next); }, (bucketInfo, objMd, next) => { if (!useMultipleBackend) { diff --git a/package.json b/package.json index eb2dbc9e8c..c655c0e921 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zenko/cloudserver", - "version": "8.7.35", + "version": "8.7.36", "description": "Zenko CloudServer, an open-source Node.js implementation of a server handling the Amazon S3 protocol", "main": "index.js", "engines": { @@ -21,7 +21,7 @@ "dependencies": { "@azure/storage-blob": "^12.12.0", "@hapi/joi": "^17.1.0", - "arsenal": "git+https://github.com/scality/arsenal#8.1.115", + "arsenal": "git+https://github.com/scality/arsenal#8.1.116", "async": "~2.5.0", "aws-sdk": "2.905.0", "bucketclient": "scality/bucketclient#8.1.9", diff --git a/tests/multipleBackend/multipartUpload.js b/tests/multipleBackend/multipartUpload.js index f2da85eb0a..24f7435467 100644 --- a/tests/multipleBackend/multipartUpload.js +++ b/tests/multipleBackend/multipartUpload.js @@ -61,6 +61,7 @@ const bucketPutRequest = { url: '/', post: '', parsedHost: 'localhost', + actionImplicitDenies: false, }; const awsETag = 'be747eb4b75517bf6b3cf7c5fbb62f3a'; @@ -80,6 +81,7 @@ const completeBody = '' + const basicParams = { bucketName, namespace, + actionImplicitDenies: false, }; function getObjectGetRequest(objectKey) { @@ -277,6 +279,7 @@ function mpuSetup(location, key, cb) { 'x-amz-meta-scal-location-constraint': location }, url: `/${key}?uploads`, parsedHost: 'localhost', + actionImplicitDenies: false, }; initiateMultipartUpload(authInfo, initiateRequest, log, (err, result) => { @@ -349,6 +352,7 @@ describe.skip('Multipart Upload API with AWS Backend', function mpuTestSuite() { 'x-amz-meta-scal-location-constraint': `${awsLocation}` }, url: `/${objectKey}?uploads`, parsedHost: 'localhost', + actionImplicitDenies: false, }; initiateMultipartUpload(authInfo, initiateRequest, log, @@ -372,6 +376,7 @@ describe.skip('Multipart Upload API with AWS Backend', function mpuTestSuite() { `${awsLocationMismatch}` }, url: `/${objectKey}?uploads`, parsedHost: 'localhost', + actionImplicitDenies: false, }; initiateMultipartUpload(authInfo, initiateRequest, log, @@ -396,6 +401,7 @@ describe.skip('Multipart Upload API with AWS Backend', function mpuTestSuite() { }, url: `/${objectKey}?uploads`, parsedHost: 'localhost', + actionImplicitDenies: false, }; initiateMultipartUpload(authInfo, initiateRequest, log, @@ -625,6 +631,7 @@ describe.skip('Multipart Upload API with AWS Backend', function mpuTestSuite() { 'x-amz-meta-scal-location-constraint': awsLocation }, url: `/${objectKey}?uploads`, parsedHost: 'localhost', + actionImplicitDenies: false, }; initiateMultipartUpload(authInfo, initiateRequest, log, err => { @@ -728,6 +735,7 @@ describe.skip('Multipart Upload API with AWS Backend', function mpuTestSuite() { headers: { host: '/' }, url: `/${bucketName}?uploads`, query: {}, + actionImplicitDenies: false, }; listMultipartUploads(authInfo, listMpuParams, log, (err, mpuListXml) => { diff --git a/tests/unit/api/bucketHead.js b/tests/unit/api/bucketHead.js index fe4cbd785e..3c006a549c 100644 --- a/tests/unit/api/bucketHead.js +++ b/tests/unit/api/bucketHead.js @@ -13,6 +13,7 @@ const testRequest = { namespace, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; describe('bucketHead API', () => { beforeEach(() => { diff --git a/tests/unit/api/deleteMarker.js b/tests/unit/api/deleteMarker.js index 9f11433df1..59df47a2c9 100644 --- a/tests/unit/api/deleteMarker.js +++ b/tests/unit/api/deleteMarker.js @@ -27,6 +27,7 @@ const testPutBucketRequest = new DummyRequest({ namespace, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }); const testDeleteRequest = new DummyRequest({ bucketName, @@ -34,6 +35,7 @@ const testDeleteRequest = new DummyRequest({ objectKey: objectName, headers: {}, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }); function _createBucketPutVersioningReq(status) { @@ -44,6 +46,7 @@ function _createBucketPutVersioningReq(status) { }, url: '/?versioning', query: { versioning: '' }, + actionImplicitDenies: false, }; const xml = '' + @@ -61,6 +64,7 @@ function _createMultiObjectDeleteRequest(numObjects) { }, url: '/?delete', query: { delete: '' }, + actionImplicitDenies: false, }; const xml = []; xml.push(''); diff --git a/tests/unit/api/deletedFlagBucket.js b/tests/unit/api/deletedFlagBucket.js index 4497fef250..83d699f4e2 100644 --- a/tests/unit/api/deletedFlagBucket.js +++ b/tests/unit/api/deletedFlagBucket.js @@ -58,11 +58,13 @@ const baseTestRequest = { post: '', headers: { host: `${bucketName}.s3.amazonaws.com` }, query: {}, + actionImplicitDenies: false, }; const serviceGetRequest = { parsedHost: 's3.amazonaws.com', headers: { host: 's3.amazonaws.com' }, url: '/', + actionImplicitDenies: false, }; const userBucketOwner = 'admin'; diff --git a/tests/unit/api/listMultipartUploads.js b/tests/unit/api/listMultipartUploads.js index c655aa8b3c..e24fc13f40 100644 --- a/tests/unit/api/listMultipartUploads.js +++ b/tests/unit/api/listMultipartUploads.js @@ -32,6 +32,7 @@ describe('listMultipartUploads API', () => { namespace, headers: {}, url: `/${bucketName}`, + actionImplicitDenies: false, }; const testInitiateMPURequest1 = { bucketName, @@ -39,6 +40,7 @@ describe('listMultipartUploads API', () => { objectKey: objectName1, headers: {}, url: `/${bucketName}/${objectName1}?uploads`, + actionImplicitDenies: false, }; const testInitiateMPURequest2 = { bucketName, @@ -46,6 +48,7 @@ describe('listMultipartUploads API', () => { objectKey: objectName2, headers: {}, url: `/${bucketName}/${objectName2}?uploads`, + actionImplicitDenies: false, }; const testInitiateMPURequest3 = { bucketName, @@ -53,6 +56,7 @@ describe('listMultipartUploads API', () => { objectKey: objectName3, headers: {}, url: `/${bucketName}/${objectName3}?uploads`, + actionImplicitDenies: false, }; it('should return the name of the common prefix ' + @@ -65,6 +69,7 @@ describe('listMultipartUploads API', () => { headers: { host: '/' }, url: `/${bucketName}?uploads&delimiter=/&prefix=sub`, query: { delimiter, prefix }, + actionImplicitDenies: false, }; async.waterfall([ @@ -94,6 +99,7 @@ describe('listMultipartUploads API', () => { headers: { host: '/' }, url: `/${bucketName}?uploads`, query: {}, + actionImplicitDenies: false, }; @@ -127,6 +133,7 @@ describe('listMultipartUploads API', () => { headers: { host: '/' }, url: `/${bucketName}?uploads`, query: { 'max-uploads': '1' }, + actionImplicitDenies: false, }; async.waterfall([ @@ -163,6 +170,7 @@ describe('listMultipartUploads API', () => { headers: { host: '/' }, url: `/${bucketName}?uploads`, query: { 'encoding-type': 'url' }, + actionImplicitDenies: false, }; async.waterfall([ @@ -195,6 +203,7 @@ describe('listMultipartUploads API', () => { headers: { host: '/' }, url: `/${bucketName}?uploads`, query: { 'key-marker': objectName1 }, + actionImplicitDenies: false, }; async.waterfall([ diff --git a/tests/unit/api/listParts.js b/tests/unit/api/listParts.js index 525085838f..48a9668e11 100644 --- a/tests/unit/api/listParts.js +++ b/tests/unit/api/listParts.js @@ -114,6 +114,7 @@ describe('List Parts API', () => { url: `/${uploadKey}?uploadId=${uploadId}`, headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId }, + actionImplicitDenies: false, }; listParts(authInfo, listRequest, log, (err, xml) => { @@ -160,6 +161,7 @@ describe('List Parts API', () => { uploadId, 'encoding-type': 'url', }, + actionImplicitDenies: false, }; const urlEncodedObjectKey = '%24makememulti'; @@ -185,6 +187,7 @@ describe('List Parts API', () => { uploadId, 'max-parts': '4', }, + actionImplicitDenies: false, }; listParts(authInfo, listRequest, log, (err, xml) => { @@ -226,6 +229,7 @@ describe('List Parts API', () => { uploadId, 'max-parts': '6', }, + actionImplicitDenies: false, }; listParts(authInfo, listRequest, log, (err, xml) => { @@ -267,6 +271,7 @@ describe('List Parts API', () => { uploadId, 'part-number-marker': '2', }, + actionImplicitDenies: false, }; listParts(authInfo, listRequest, log, (err, xml) => { @@ -312,6 +317,7 @@ describe('List Parts API', () => { 'part-number-marker': '2', 'max-parts': '2', }, + actionImplicitDenies: false, }; listParts(authInfo, listRequest, log, (err, xml) => { diff --git a/tests/unit/api/multipartDelete.js b/tests/unit/api/multipartDelete.js index c96ec26148..be9e9ec81e 100644 --- a/tests/unit/api/multipartDelete.js +++ b/tests/unit/api/multipartDelete.js @@ -22,6 +22,7 @@ const bucketPutRequest = { namespace, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; const objectKey = 'testObject'; const initiateRequest = { @@ -30,6 +31,7 @@ const initiateRequest = { objectKey, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: `/${objectKey}?uploads`, + actionImplicitDenies: false, }; const eastLocation = 'us-east-1'; const westLocation = 'scality-internal-file'; @@ -65,6 +67,7 @@ function _createAndAbortMpu(usEastSetting, fakeUploadID, locationConstraint, partNumber: '1', uploadId, }, + actionImplicitDenies: false, }, partBody); const testUploadId = fakeUploadID ? 'nonexistinguploadid' : uploadId; @@ -75,6 +78,7 @@ function _createAndAbortMpu(usEastSetting, fakeUploadID, locationConstraint, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: `/${objectKey}?uploadId=${testUploadId}`, query: { uploadId: testUploadId }, + actionImplicitDenies: false, }; next(null, partRequest, deleteMpuRequest); }, diff --git a/tests/unit/api/multipartUpload.js b/tests/unit/api/multipartUpload.js index a90e19a22c..90ab3c65e3 100644 --- a/tests/unit/api/multipartUpload.js +++ b/tests/unit/api/multipartUpload.js @@ -51,6 +51,7 @@ const bucketPutRequest = { 'xmlns="http://s3.amazonaws.com/doc/2006-03-01/">' + 'scality-internal-mem' + '', + actionImplicitDenies: false, }; const lockEnabledBucketRequest = Object.assign({}, bucketPutRequest); lockEnabledBucketRequest.bucketName = lockedBucket; @@ -64,6 +65,7 @@ const initiateRequest = { objectKey, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: `/${objectKey}?uploads`, + actionImplicitDenies: false, }; const retentionInitiateRequest = Object.assign({}, initiateRequest); retentionInitiateRequest.bucketName = lockedBucket; @@ -84,6 +86,7 @@ const getObjectLockInfoRequest = { namespace, objectKey, headers: { host: `${lockedBucket}.s3.amazonaws.com` }, + actionImplicitDenies: false, }; const expectedRetentionConfig = { $: { xmlns: 'http://s3.amazonaws.com/doc/2006-03-01/' }, @@ -108,6 +111,7 @@ function _createPutPartRequest(uploadId, partNumber, partBody) { uploadId, }, calculatedHash, + actionImplicitDenies: false, }, partBody); } @@ -130,6 +134,7 @@ function _createCompleteMpuRequest(uploadId, parts) { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId }, post: completeBody, + actionImplicitDenies: false, }; } @@ -562,6 +567,7 @@ describe('Multipart Upload API', () => { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: testUploadId }, post: completeBody, + actionImplicitDenies: false, }; const awsVerifiedETag = '"953e9e776f285afc0bfcf1ab4668299d-1"'; @@ -650,6 +656,7 @@ describe('Multipart Upload API', () => { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: testUploadId }, post: completeBody, + actionImplicitDenies: false, }; const awsVerifiedETag = '"953e9e776f285afc0bfcf1ab4668299d-1"'; @@ -722,6 +729,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, err => { @@ -777,6 +785,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, err => { assert(err.is.MalformedXML); @@ -849,6 +858,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, err => { @@ -907,6 +917,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, err => { assert(err.is.InvalidPart); @@ -978,6 +989,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; assert.strictEqual(metadata.keyMaps.get(mpuBucket).size, 3); completeMultipartUpload(authInfo, @@ -1060,6 +1072,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; assert.strictEqual(metadata.keyMaps.get(mpuBucket).size, 3); completeMultipartUpload(authInfo, @@ -1142,6 +1155,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, (err, result) => { @@ -1173,6 +1187,7 @@ describe('Multipart Upload API', () => { 'x-amz-acl': 'authenticated-read', }, url: `/${objectKey}?uploads`, + actionImplicitDenies: false, }; async.waterfall([ @@ -1241,6 +1256,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, (err, result) => { @@ -1275,6 +1291,7 @@ describe('Multipart Upload API', () => { 'x-amz-grant-read': `emailAddress="${granteeEmail}"`, }, url: `/${objectKey}?uploads`, + actionImplicitDenies: false, }; async.waterfall([ @@ -1343,6 +1360,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, (err, result) => { @@ -1395,6 +1413,7 @@ describe('Multipart Upload API', () => { url: `/${objectKey}?uploadId=${testUploadId}`, headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: testUploadId }, + actionImplicitDenies: false, }; assert.strictEqual(metadata.keyMaps.get(mpuBucket).size, 2); multipartDelete(authInfo, deleteRequest, log, err => { @@ -1445,6 +1464,7 @@ describe('Multipart Upload API', () => { url: `/${objectKey}?uploadId=${testUploadId}`, headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: 'non-existent-upload-id' }, + actionImplicitDenies: false, }; assert.strictEqual(metadata.keyMaps.get(mpuBucket).size, 2); multipartDelete(authInfo, deleteRequest, log, err => { @@ -1524,6 +1544,7 @@ describe('Multipart Upload API', () => { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: testUploadId }, post: completeBody, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, (err, result) => { @@ -1577,6 +1598,7 @@ describe('Multipart Upload API', () => { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: testUploadId }, post: completeBody, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, next); }, @@ -1648,6 +1670,7 @@ describe('Multipart Upload API', () => { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId }, post: completeBody, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, next); }, @@ -1718,6 +1741,7 @@ describe('Multipart Upload API', () => { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId }, post: completeBody, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, done); }, @@ -1810,6 +1834,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; // show that second part data is there assert(ds[2]); diff --git a/tests/unit/api/objectHead.js b/tests/unit/api/objectHead.js index 032b781304..c01d1a4fea 100644 --- a/tests/unit/api/objectHead.js +++ b/tests/unit/api/objectHead.js @@ -26,6 +26,7 @@ const testPutBucketRequest = { namespace, headers: {}, url: `/${bucketName}`, + actionImplicitDenies: false, }; const userMetadataKey = 'x-amz-meta-test'; const userMetadataValue = 'some metadata'; @@ -54,6 +55,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: { 'if-modified-since': laterDate }, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -77,6 +79,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: { 'if-unmodified-since': earlierDate }, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -101,6 +104,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: { 'if-match': incorrectMD5 }, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -124,6 +128,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: { 'if-none-match': correctMD5 }, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -146,6 +151,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: { range: 'bytes=1-9' }, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -170,6 +176,7 @@ describe('objectHead API', () => { query: { partNumber: '1', }, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -196,6 +203,7 @@ describe('objectHead API', () => { query: { partNumber: 'nan', }, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -218,6 +226,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: {}, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -238,6 +247,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: {}, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -261,6 +271,7 @@ describe('objectHead API', () => { namespace, headers: { 'x-amz-bucket-object-lock-enabled': 'true' }, url: `/${bucketName}`, + actionImplicitDenies: false, }; const testPutObjectRequestLock = new DummyRequest({ bucketName, @@ -280,6 +291,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: {}, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequestLock, log, () => { diff --git a/tests/unit/api/objectReplicationMD.js b/tests/unit/api/objectReplicationMD.js index 7d1fef1194..640d990726 100644 --- a/tests/unit/api/objectReplicationMD.js +++ b/tests/unit/api/objectReplicationMD.js @@ -48,6 +48,7 @@ const objectACLReq = { }, url: `/${bucketName}/${keyA}?acl`, query: { acl: '' }, + actionImplicitDenies: false, }; // Get an object request with the given key. @@ -186,6 +187,7 @@ function putMPU(key, body, cb) { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId }, post: postBody, + actionImplicitDenies: false, }; return completeMultipartUpload(authInfo, req, log, cb); } diff --git a/tests/unit/api/transientBucket.js b/tests/unit/api/transientBucket.js index b127f44ef1..9ddf6952db 100644 --- a/tests/unit/api/transientBucket.js +++ b/tests/unit/api/transientBucket.js @@ -52,11 +52,13 @@ const baseTestRequest = { url: '/', post: '', headers: { host: `${bucketName}.s3.amazonaws.com` }, + actionImplicitDenies: false, }; const serviceGetRequest = { parsedHost: 's3.amazonaws.com', headers: { host: 's3.amazonaws.com' }, url: '/', + actionImplicitDenies: false, }; const userBucketOwner = 'admin'; diff --git a/tests/unit/utils/bucketEncryption.js b/tests/unit/utils/bucketEncryption.js index 7577689e42..63cb33df9a 100644 --- a/tests/unit/utils/bucketEncryption.js +++ b/tests/unit/utils/bucketEncryption.js @@ -29,6 +29,7 @@ function templateRequest(bucketName, { post }) { bucketName, headers: { host: `${bucketName}.s3.amazonaws.com` }, post, + actionImplicitDenies: false, }; } diff --git a/tests/unit/utils/lifecycleHelpers.js b/tests/unit/utils/lifecycleHelpers.js index 0cbb88d660..b9399b00ac 100644 --- a/tests/unit/utils/lifecycleHelpers.js +++ b/tests/unit/utils/lifecycleHelpers.js @@ -4,6 +4,7 @@ function getLifecycleRequest(bucketName, xml) { headers: { host: `${bucketName}.s3.amazonaws.com`, }, + actionImplicitDenies: false, }; if (xml) { request.post = xml; diff --git a/tests/unit/utils/mpuUtils.js b/tests/unit/utils/mpuUtils.js index f0af8b0eca..397b07c5b9 100644 --- a/tests/unit/utils/mpuUtils.js +++ b/tests/unit/utils/mpuUtils.js @@ -28,6 +28,7 @@ function createinitiateMPURequest(namespace, bucketName, objectKey) { objectKey, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: `/${objectKey}?uploads`, + actionImplicitDenies: false, }; return request; @@ -45,6 +46,7 @@ function createPutPartRequest(namespace, bucketName, objectKey, partNumber, test uploadId: testUploadId, }, calculatedHash, + actionImplicitDenies: false, }, partBody); return request; @@ -68,6 +70,7 @@ function createCompleteRequest(namespace, bucketName, objectKey, testUploadId) { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: testUploadId }, post: completeBody, + actionImplicitDenies: false, }; return request; diff --git a/yarn.lock b/yarn.lock index 21b70608fc..9979828efe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -789,9 +789,9 @@ arraybuffer.slice@~0.0.7: optionalDependencies: ioctl "^2.0.2" -"arsenal@git+https://github.com/scality/arsenal#8.1.115": - version "8.1.115" - resolved "git+https://github.com/scality/arsenal#d800179f86e81a9632b4e4b935ae106a6fdf1871" +"arsenal@git+https://github.com/scality/arsenal#8.1.116": + version "8.1.116" + resolved "git+https://github.com/scality/arsenal#74ff1691a032dd929d978f66ca9ad13187662997" dependencies: "@azure/identity" "^3.1.1" "@azure/storage-blob" "^12.12.0"