diff --git a/lib/api/api.js b/lib/api/api.js index f85f0d33a1..798b3581c7 100644 --- a/lib/api/api.js +++ b/lib/api/api.js @@ -114,6 +114,7 @@ const api = { // no need to check auth on website or cors preflight requests if (apiMethod === 'websiteGet' || apiMethod === 'websiteHead' || apiMethod === 'corsPreflight') { + request.actionImplicitDenies = false; return this[apiMethod](request, log, callback); } @@ -136,15 +137,25 @@ const api = { const requestContexts = prepareRequestContexts(apiMethod, request, sourceBucket, sourceObject, sourceVersionId); + // Extract all the _apiMethods and store them in an array + const apiMethods = requestContexts ? requestContexts.map(context => context._apiMethod) : []; + // Attach the names to the current request + // eslint-disable-next-line no-param-reassign + request.apiMethods = apiMethods; function checkAuthResults(authResults) { let returnTagCount = true; + const isImplicitDeny = {}; + let isOnlyImplicitDeny = true; if (apiMethod === 'objectGet') { // first item checks s3:GetObject(Version) action - if (!authResults[0].isAllowed) { + if (!authResults[0].isAllowed && !authResults[0].isImplicit) { log.trace('get object authorization denial from Vault'); return errors.AccessDenied; } + // TODO add support for returnTagCount in the bucket policy + // checks + isImplicitDeny[authResults[0].action] = authResults[0].isImplicit; // second item checks s3:GetObject(Version)Tagging action if (!authResults[1].isAllowed) { log.trace('get tagging authorization denial ' + @@ -153,13 +164,26 @@ const api = { } } else { for (let i = 0; i < authResults.length; i++) { - if (!authResults[i].isAllowed) { + isImplicitDeny[authResults[i].action] = true; + if (!authResults[i].isAllowed && !authResults[i].isImplicit) { + // Any explicit deny rejects the current API call log.trace('authorization denial from Vault'); return errors.AccessDenied; } + if (authResults[i].isAllowed) { + // If the action is allowed, the result is not implicit + // Deny. + isImplicitDeny[authResults[i].action] = false; + isOnlyImplicitDeny = false; + } } } - return returnTagCount; + // These two APIs cannot use ACLs or Bucket Policies, hence, any + // implicit deny from vault must be treated as an explicit deny. + if ((apiMethod === 'bucketPut' || apiMethod === 'serviceGet') && isOnlyImplicitDeny) { + return errors.AccessDenied; + } + return { returnTagCount, isImplicitDeny }; } return async.waterfall([ @@ -237,7 +261,16 @@ const api = { if (checkedResults instanceof Error) { return callback(checkedResults); } - returnTagCount = checkedResults; + returnTagCount = checkedResults.returnTagCount; + request.actionImplicitDenies = checkedResults.isImplicitDeny; + } else { + // create an object of keys apiMethods with all values to false: + // for backward compatibility, all apiMethods are allowed by default + // thus it is explicitly allowed, so implicit deny is false + request.actionImplicitDenies = apiMethods.reduce((acc, curr) => { + acc[curr] = false; + return acc; + }, {}); } if (apiMethod === 'objectPut' || apiMethod === 'objectPutPart') { request._response = response; diff --git a/package.json b/package.json index 397564d4a6..7e1ec16ff9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "s3", - "version": "7.70.29", + "version": "7.70.30", "description": "S3 connector", "main": "index.js", "engines": { @@ -20,7 +20,7 @@ "homepage": "https://github.com/scality/S3#readme", "dependencies": { "@hapi/joi": "^17.1.0", - "arsenal": "git+https://github.com/scality/arsenal#7.70.12", + "arsenal": "git+https://github.com/scality/arsenal#7.70.13", "async": "~2.5.0", "aws-sdk": "2.905.0", "azure-storage": "^2.1.0", diff --git a/yarn.lock b/yarn.lock index 612225d088..e69014d47d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -494,9 +494,9 @@ arraybuffer.slice@~0.0.7: optionalDependencies: ioctl "^2.0.2" -"arsenal@git+https://github.com/scality/arsenal#7.70.12": - version "7.70.12" - resolved "git+https://github.com/scality/arsenal#79b83a90678e0b9eea521f08b3a7ec9eb158d748" +"arsenal@git+https://github.com/scality/arsenal#7.70.13": + version "7.70.13" + resolved "git+https://github.com/scality/arsenal#29ef2ef265e8cccb02b282be1c1316ab67f65a97" dependencies: "@types/async" "^3.2.12" "@types/utf8" "^3.0.1"