Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/improvement/CLDSRV-428-put-apis-…
Browse files Browse the repository at this point in the history
…implicitDeny' into w/7.70/improvement/CLDSRV-428-put-apis-implicitDeny
  • Loading branch information
benzekrimaha committed Nov 21, 2023
2 parents 2344204 + e590b47 commit 1fabe3b
Show file tree
Hide file tree
Showing 39 changed files with 1,440 additions and 1,210 deletions.
2 changes: 2 additions & 0 deletions constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ const constants = {
'objectDeleteTagging',
'objectGetTagging',
'objectPutTagging',
'objectPutLegalHold',
'objectPutRetention',
],
// response header to be sent when there are invalid
// user metadata in the object's metadata
Expand Down
112 changes: 53 additions & 59 deletions lib/api/bucketPutACL.js
Original file line number Diff line number Diff line change
Expand Up @@ -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/metrics');
Expand Down Expand Up @@ -44,7 +44,7 @@ const monitoring = require('../utilities/metrics');
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 = [
Expand All @@ -54,27 +54,14 @@ 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,
];
const metadataValParams = {
authInfo,
bucketName,
requestType: 'bucketPutACL',
requestType: request.apiMethods || 'bucketPutACL',
request,
};
const possibleGrants = ['FULL_CONTROL', 'WRITE',
Expand All @@ -88,34 +75,41 @@ function bucketPutACL(authInfo, request, log, callback) {
READ_ACP: [],
};

const grantReadHeader =
aclUtils.parseGrant(request.headers[
'x-amz-grant-read'], 'READ');
const grantWriteHeader =
aclUtils.parseGrant(request.headers['x-amz-grant-write'], 'WRITE');
const grantReadACPHeader =
aclUtils.parseGrant(request.headers['x-amz-grant-read-acp'],
'READ_ACP');
const grantWriteACPHeader =
aclUtils.parseGrant(request.headers['x-amz-grant-write-acp'],
'WRITE_ACP');
const grantFullControlHeader =
aclUtils.parseGrant(request.headers['x-amz-grant-full-control'],
'FULL_CONTROL');
const grantReadHeader = aclUtils.parseGrant(request.headers[
'x-amz-grant-read'], 'READ');
const grantWriteHeader = aclUtils.parseGrant(request.headers['x-amz-grant-write'], 'WRITE');
const grantReadACPHeader = aclUtils.parseGrant(request.headers['x-amz-grant-read-acp'],
'READ_ACP');
const grantWriteACPHeader = aclUtils.parseGrant(request.headers['x-amz-grant-write-acp'],
'WRITE_ACP');
const grantFullControlHeader = aclUtils.parseGrant(request.headers['x-amz-grant-full-control'],
'FULL_CONTROL');

return async.waterfall([
function waterfall1(next) {
metadataValidateBucket(metadataValParams, log,
(err, bucket) => {
if (err) {
log.trace('request authorization failed', {
error: err,
method: 'metadataValidateBucket',
});
return next(err, bucket);
}
return next(null, bucket);
});
standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log,
(err, bucket) => {
if (err) {
log.trace('request authorization failed', {
error: err,
method: 'metadataValidateBucket',
});
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);
});
},
function waterfall2(bucket, next) {
// If not setting acl through headers, parse body
Expand Down Expand Up @@ -182,7 +176,7 @@ function bucketPutACL(authInfo, request, log, callback) {
if (!skip && granteeType === 'Group') {
if (possibleGroups.indexOf(grantee.URI[0]) < 0) {
log.trace('invalid user group',
{ userGroup: grantee.URI[0] });
{ userGroup: grantee.URI[0] });
return next(errors.InvalidArgument, bucket);
}
return usersIdentifiedByGroup.push({
Expand All @@ -196,22 +190,23 @@ function bucketPutACL(authInfo, request, log, callback) {
} else {
// If no canned ACL and no parsed xml, loop
// through the access headers
const allGrantHeaders =
[].concat(grantReadHeader, grantWriteHeader,
const allGrantHeaders = [].concat(grantReadHeader, grantWriteHeader,
grantReadACPHeader, grantWriteACPHeader,
grantFullControlHeader);

usersIdentifiedByEmail = allGrantHeaders.filter(item =>
item && item.userIDType.toLowerCase() === 'emailaddress');
usersIdentifiedByEmail = allGrantHeaders.filter(item => item
&& item.userIDType.toLowerCase() === 'emailaddress');

usersIdentifiedByGroup = allGrantHeaders
.filter(itm => itm && itm.userIDType
.toLowerCase() === 'uri');
.toLowerCase() === 'uri');
for (let i = 0; i < usersIdentifiedByGroup.length; i++) {
const userGroup = usersIdentifiedByGroup[i].identifier;
if (possibleGroups.indexOf(userGroup) < 0) {
log.trace('invalid user group', { userGroup,
method: 'bucketPutACL' });
log.trace('invalid user group', {
userGroup,
method: 'bucketPutACL',
});
return next(errors.InvalidArgument, bucket);
}
}
Expand Down Expand Up @@ -246,8 +241,8 @@ function bucketPutACL(authInfo, request, log, callback) {
return vault.getCanonicalIds(justEmails, log,
(err, results) => {
if (err) {
log.trace('error looking up canonical ids', {
error: err, method: 'vault.getCanonicalIDs' });
log.trace('error looking up canonical ids',
{ error: err, method: 'vault.getCanonicalIDs' });
return next(err, bucket);
}
const reconstructedUsersIdentifiedByEmail = aclUtils
Expand All @@ -256,17 +251,18 @@ function bucketPutACL(authInfo, request, log, callback) {
const allUsers = [].concat(
reconstructedUsersIdentifiedByEmail,
usersIdentifiedByID,
usersIdentifiedByGroup);
usersIdentifiedByGroup,
);
const revisedAddACLParams = aclUtils
.sortHeaderGrants(allUsers, addACLParams);
return next(null, bucket, revisedAddACLParams);
});
}
const allUsers = [].concat(
usersIdentifiedByID,
usersIdentifiedByGroup);
const revisedAddACLParams =
aclUtils.sortHeaderGrants(allUsers, addACLParams);
usersIdentifiedByGroup,
);
const revisedAddACLParams = aclUtils.sortHeaderGrants(allUsers, addACLParams);
return next(null, bucket, revisedAddACLParams);
},
function waterfall4(bucket, addACLParams, next) {
Expand All @@ -277,12 +273,10 @@ function bucketPutACL(authInfo, request, log, callback) {
if (bucket.hasTransientFlag() || bucket.hasDeletedFlag()) {
log.trace('transient or deleted flag so cleaning up bucket');
bucket.setFullAcl(addACLParams);
return cleanUpBucket(bucket, canonicalID, log, err =>
next(err, bucket));
return cleanUpBucket(bucket, canonicalID, log, err => next(err, bucket));
}
// If no bucket flags, just add acl's to bucket metadata
return acl.addACL(bucket, addACLParams, log, err =>
next(err, bucket));
return acl.addACL(bucket, addACLParams, log, err => next(err, bucket));
},
], (err, bucket) => {
const corsHeaders = collectCorsHeaders(request.headers.origin,
Expand Down
11 changes: 5 additions & 6 deletions lib/api/bucketPutCors.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ const { errors } = require('arsenal');

const bucketShield = require('./apiUtils/bucket/bucketShield');
const collectCorsHeaders = require('../utilities/collectCorsHeaders');
const { isBucketAuthorized } =
require('./apiUtils/authorization/permissionChecks');
const { isBucketAuthorized } = require('./apiUtils/authorization/permissionChecks');
const metadata = require('../metadata/wrapper');
const { parseCorsXml } = require('./apiUtils/bucket/bucketCors');
const { pushMetric } = require('../utapi/utilities');
Expand All @@ -23,7 +22,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) {
Expand Down Expand Up @@ -70,7 +69,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,
});
Expand All @@ -81,8 +81,7 @@ function bucketPutCors(authInfo, request, log, callback) {
function updateBucketMetadata(bucket, rules, corsHeaders, next) {
log.trace('updating bucket cors rules in metadata');
bucket.setCors(rules);
metadata.updateBucket(bucketName, bucket, log, err =>
next(err, corsHeaders));
metadata.updateBucket(bucketName, bucket, log, err => next(err, corsHeaders));
},
], (err, corsHeaders) => {
if (err) {
Expand Down
8 changes: 4 additions & 4 deletions lib/api/bucketPutEncryption.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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' });
Expand Down
14 changes: 6 additions & 8 deletions lib/api/bucketPutLifecycle.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
const { waterfall } = require('async');
const uuid = require('uuid/v4');
const LifecycleConfiguration =
require('arsenal').models.LifecycleConfiguration;
const { LifecycleConfiguration } = require('arsenal').models;

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/metrics');

Expand All @@ -22,11 +21,11 @@ const monitoring = require('../utilities/metrics');
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([
Expand All @@ -43,7 +42,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);
Expand All @@ -55,8 +54,7 @@ function bucketPutLifecycle(authInfo, request, log, callback) {
bucket.setUid(uuid());
}
bucket.setLifecycleConfiguration(lcConfig);
metadata.updateBucket(bucket.getName(), bucket, log, err =>
next(err, bucket));
metadata.updateBucket(bucket.getName(), bucket, log, err => next(err, bucket));
},
], (err, bucket) => {
const corsHeaders = collectCorsHeaders(request.headers.origin,
Expand Down
14 changes: 8 additions & 6 deletions lib/api/bucketPutNotification.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');

/**
Expand All @@ -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,
};

Expand All @@ -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);
Expand All @@ -45,8 +45,10 @@ function bucketPutNotification(authInfo, request, log, callback) {
const corsHeaders = collectCorsHeaders(request.headers.origin,
request.method, bucket);
if (err) {
log.trace('error processing request', { error: err,
method: 'bucketPutNotification' });
log.trace('error processing request', {
error: err,
method: 'bucketPutNotification',
});
return callback(err, corsHeaders);
}
pushMetric('putBucketNotification', log, {
Expand Down
Loading

0 comments on commit 1fabe3b

Please sign in to comment.