Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
760ab89
Send signatureVersion and authType unswapped to Vault checkPolicies
benzekrimaha Jul 29, 2026
ea42afc
Bump project version
benzekrimaha Jul 29, 2026
4aeb34d
Merge remote-tracking branch 'origin/improvement/CLDSRV-963-fix-swapp…
benzekrimaha Aug 4, 2026
7becbc6
Merge remote-tracking branch 'origin/w/9.2/improvement/CLDSRV-963-fix…
benzekrimaha Aug 4, 2026
dbea941
Format multiObjectDelete files with prettier
benzekrimaha Aug 4, 2026
f348fc5
Merge branch 'w/9.3/improvement/CLDSRV-963-fix-swapped-auth-params-ch…
benzekrimaha Aug 4, 2026
9b02cb4
Send signatureVersion and authType unswapped in bucketPut checkPolicies
benzekrimaha Aug 5, 2026
1896c2e
Merge branch 'improvement/CLDSRV-963-fix-swapped-auth-params-check-po…
bert-e Aug 5, 2026
07764bd
Merge branch 'w/9.2/improvement/CLDSRV-963-fix-swapped-auth-params-ch…
benzekrimaha Aug 5, 2026
af2e3b1
Format bucketPut files with prettier
benzekrimaha Aug 5, 2026
28e8ec8
Merge branches 'development/9.4' and 'w/9.3/improvement/CLDSRV-963-fi…
bert-e Aug 5, 2026
5564b2c
Assert the exact error in the bucketPut checkPolicies test
benzekrimaha Aug 5, 2026
9be71ce
Merge branch 'improvement/CLDSRV-963-fix-swapped-auth-params-check-po…
bert-e Aug 5, 2026
8213575
Merge branch 'w/9.2/improvement/CLDSRV-963-fix-swapped-auth-params-ch…
bert-e Aug 5, 2026
af7e0a5
Merge branch 'w/9.3/improvement/CLDSRV-963-fix-swapped-auth-params-ch…
bert-e Aug 5, 2026
0f2f742
Report the received error in the bucketPut checkPolicies test assertion
benzekrimaha Aug 5, 2026
731015a
Merge branch 'improvement/CLDSRV-963-fix-swapped-auth-params-check-po…
bert-e Aug 5, 2026
cbc8519
Merge branch 'w/9.2/improvement/CLDSRV-963-fix-swapped-auth-params-ch…
bert-e Aug 5, 2026
8a8ee9b
Merge branch 'w/9.3/improvement/CLDSRV-963-fix-swapped-auth-params-ch…
bert-e Aug 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 92 additions & 100 deletions lib/api/bucketPut.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,19 @@
} else if (parsedHost && restEndpoints[parsedHost]) {
locationConstraintChecked = restEndpoints[parsedHost];
} else {
log.trace('no location constraint provided on bucket put;' +
'setting us-east-1');
log.trace('no location constraint provided on bucket put;' + 'setting us-east-1');
locationConstraintChecked = 'us-east-1';
}

if (!locationConstraints[locationConstraintChecked]) {
const errMsg = 'value of the location you are attempting to set - ' +
const errMsg =
'value of the location you are attempting to set - ' +
`${locationConstraintChecked} - is not listed in the ` +
'locationConstraint config';
log.trace(`locationConstraint is invalid - ${errMsg}`,
{ locationConstraint: locationConstraintChecked });
return { error: errorInstances.InvalidLocationConstraint.
customizeDescription(errMsg) };
log.trace(`locationConstraint is invalid - ${errMsg}`, { locationConstraint: locationConstraintChecked });
return { error: errorInstances.InvalidLocationConstraint.customizeDescription(errMsg) };
}
if (locationConstraints[locationConstraintChecked].isCold ||
locationConstraints[locationConstraintChecked].isCRR) {
if (locationConstraints[locationConstraintChecked].isCold || locationConstraints[locationConstraintChecked].isCRR) {
return { error: errors.InvalidLocationConstraint };
}
if (locationConstraintAddon) {
Expand All @@ -84,27 +81,26 @@
function _parseXML(request, log, cb) {
if (request.post) {
return parseString(request.post, (err, result) => {
if (err || !result.CreateBucketConfiguration
|| !result.CreateBucketConfiguration.LocationConstraint
|| !result.CreateBucketConfiguration.LocationConstraint[0]) {
if (
err ||
!result.CreateBucketConfiguration ||
!result.CreateBucketConfiguration.LocationConstraint ||
!result.CreateBucketConfiguration.LocationConstraint[0]
) {
log.debug('request xml is malformed');
return cb(errors.MalformedXML);
}
const locationConstraint = result.CreateBucketConfiguration
.LocationConstraint[0];
log.trace('location constraint',
{ locationConstraint });
const locationCheck = checkLocationConstraint(request,
locationConstraint, log);
const locationConstraint = result.CreateBucketConfiguration.LocationConstraint[0];
log.trace('location constraint', { locationConstraint });
const locationCheck = checkLocationConstraint(request, locationConstraint, log);
if (locationCheck.error) {
return cb(locationCheck.error);
}
return cb(null, locationCheck.locationConstraint);
});
}
return process.nextTick(() => {
const locationCheck = checkLocationConstraint(request,
undefined, log);
const locationCheck = checkLocationConstraint(request, undefined, log);
if (locationCheck.error) {
return cb(locationCheck.error);
}
Expand All @@ -113,7 +109,15 @@
}

function _buildConstantParams({
request, bucketName, authInfo, authParams, ip, isSecure, locationConstraint, apiMethod }) {
request,
bucketName,
authInfo,
authParams,
ip,
isSecure,
locationConstraint,
apiMethod,
}) {
return {
constantParams: {
headers: request.headers,
Expand All @@ -126,8 +130,8 @@
sslEnabled: isSecure,
awsService: 's3',
requesterInfo: authInfo,
signatureVersion: authParams.params.data.authType,
authType: authParams.params.data.signatureVersion,
signatureVersion: authParams.params.data.signatureVersion,
authType: authParams.params.data.authType,
signatureAge: authParams.params.data.signatureAge,
apiMethod,
locationConstraint,
Expand All @@ -140,16 +144,15 @@
if (err) {
return cb(err);
}
if (!authorizationResults.every(res => {
if (Array.isArray(res)) {
return res.every(subRes => subRes.isAllowed);
}
return res.isAllowed;
})) {
log.trace(
'authorization check failed for user',
{ locationConstraint },
);
if (
!authorizationResults.every(res => {
if (Array.isArray(res)) {
return res.every(subRes => subRes.isAllowed);
}
return res.isAllowed;
})
) {
log.trace('authorization check failed for user', { locationConstraint });
return cb(errors.AccessDenied);
}
return cb(null, locationConstraint);
Expand Down Expand Up @@ -177,30 +180,15 @@
authInfo,
locationConstraint,
};
const requestConstantParams = [Object.assign(
baseParams,
{ apiMethod: 'bucketPut' },
)];
const requestConstantParams = [Object.assign(baseParams, { apiMethod: 'bucketPut' })];

if (_isObjectLockEnabled(request.headers)) {
requestConstantParams.push(Object.assign(
{},
baseParams,
{ apiMethod: 'bucketPutObjectLock' },
));
requestConstantParams.push(Object.assign(
{},
baseParams,
{ apiMethod: 'bucketPutVersioning' },
));
requestConstantParams.push(Object.assign({}, baseParams, { apiMethod: 'bucketPutObjectLock' }));
requestConstantParams.push(Object.assign({}, baseParams, { apiMethod: 'bucketPutVersioning' }));
}

if (_isAclProvided(request.headers)) {
requestConstantParams.push(Object.assign(
{},
baseParams,
{ apiMethod: 'bucketPutACL' },
));
requestConstantParams.push(Object.assign({}, baseParams, { apiMethod: 'bucketPutACL' }));
}

return requestConstantParams;
Expand All @@ -219,66 +207,70 @@

if (authInfo.isRequesterPublicUser()) {
log.debug('operation not available for public user');
monitoring.promMetrics(
'PUT', request.bucketName, 403, 'createBucket');
monitoring.promMetrics('PUT', request.bucketName, 403, 'createBucket');
return callback(errors.AccessDenied);
}
if (!aclUtils.checkGrantHeaderValidity(request.headers)) {
log.trace('invalid acl header');
monitoring.promMetrics(
'PUT', request.bucketName, 400, 'createBucket');
monitoring.promMetrics('PUT', request.bucketName, 400, 'createBucket');
return callback(errors.InvalidArgument);
}
const { bucketName } = request;


if (request.bucketName === 'METADATA'
// Note: for this to work with Vault, would need way to set
// canonical ID to http://acs.zenko.io/accounts/service/clueso
&& !authInfo.isRequesterThisServiceAccount('clueso')) {
monitoring.promMetrics(
'PUT', bucketName, 403, 'createBucket');
return callback(errorInstances.AccessDenied
.customizeDescription('The bucket METADATA is used ' +
'for internal purposes'));
if (
request.bucketName === 'METADATA' &&
// Note: for this to work with Vault, would need way to set
// canonical ID to http://acs.zenko.io/accounts/service/clueso
!authInfo.isRequesterThisServiceAccount('clueso')
) {
monitoring.promMetrics('PUT', bucketName, 403, 'createBucket');
return callback(
errorInstances.AccessDenied.customizeDescription('The bucket METADATA is used ' + 'for internal purposes'),
);
}

return waterfall([
next => _parseXML(request, log, next),
(locationConstraint, next) => {
if (!isRequesterNonAccountUser(authInfo)) {
return next(null, locationConstraint);
}
return waterfall(
[
next => _parseXML(request, log, next),

Check notice

Code scanning / CodeQL

Callback-style function (async migration) Note

This function uses a callback parameter ('next'). Refactor to async/await.
(locationConstraint, next) => {
if (!isRequesterNonAccountUser(authInfo)) {
return next(null, locationConstraint);
}

const authParams = auth.server.extractParams(request, log, 's3', request.query);
const requestConstantParams = authBucketPut(
authParams, bucketName, locationConstraint, request, authInfo
);
const authParams = auth.server.extractParams(request, log, 's3', request.query);
const requestConstantParams = authBucketPut(
authParams,
bucketName,
locationConstraint,
request,
authInfo,
);

return vault.checkPolicies(
requestConstantParams.map(_buildConstantParams),
authInfo.getArn(),
log,
_handleAuthResults(locationConstraint, log, next),
);
},
(locationConstraint, next) => createBucket(authInfo, bucketName,
request.headers, locationConstraint, log, (err, previousBucket) => {
// if bucket already existed, gather any relevant cors
// headers
const corsHeaders = collectCorsHeaders(
request.headers.origin, request.method, previousBucket);
if (err) {
return next(err, corsHeaders);
}
pushMetric('createBucket', log, {
authInfo,
bucket: bucketName,
});
monitoring.promMetrics('PUT', bucketName, '200', 'createBucket');
return next(null, corsHeaders);
}),
], callback);
return vault.checkPolicies(
requestConstantParams.map(_buildConstantParams),
authInfo.getArn(),
log,
_handleAuthResults(locationConstraint, log, next),
);
},

Check notice

Code scanning / CodeQL

Callback-style function (async migration) Note

This function uses a callback parameter ('next'). Refactor to async/await.
Comment on lines +235 to +255
(locationConstraint, next) =>
createBucket(authInfo, bucketName, request.headers, locationConstraint, log, (err, previousBucket) => {
// if bucket already existed, gather any relevant cors
// headers
const corsHeaders = collectCorsHeaders(request.headers.origin, request.method, previousBucket);
if (err) {
return next(err, corsHeaders);
}
pushMetric('createBucket', log, {
authInfo,
bucket: bucketName,
});
monitoring.promMetrics('PUT', bucketName, '200', 'createBucket');
return next(null, corsHeaders);
}),

Check notice

Code scanning / CodeQL

Callback-style function (async migration) Note

This function uses a callback parameter ('next'). Refactor to async/await.
Comment on lines +256 to +270
],
callback,
);
}

module.exports = {
Expand Down
Loading
Loading