Compare commits

...

5 Commits

Author SHA1 Message Date
williamlardier 70e9228c4f
testing 2023-07-18 13:22:48 +02:00
williamlardier cf230e7c07
test bb 2023-07-11 11:44:35 +02:00
williamlardier 7ccf386da5
wip 2023-07-11 11:05:45 +02:00
williamlardier d596264f01
wip 2023-07-11 10:11:07 +02:00
williamlardier 9a29d19a5a
Handle implcit deny results from IAM.
The API is started if IAM returns Allow or an implicit Deny.
In these cases, we add a new boolean to the request that
serves as a context when checking the Bucket/Object ACL or
the Bucket policies. Then, we implement the same authorization
logic as AWS, where an implicit deny from IAM and an Allow from
the Bucket Policy should allow the request.
2023-07-10 10:24:24 +02:00
58 changed files with 284 additions and 113 deletions

View File

@ -139,9 +139,10 @@ const api = {
function checkAuthResults(authResults) { function checkAuthResults(authResults) {
let returnTagCount = true; let returnTagCount = true;
let isImplicitDeny = true;
if (apiMethod === 'objectGet') { if (apiMethod === 'objectGet') {
// first item checks s3:GetObject(Version) action // 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'); log.trace('get object authorization denial from Vault');
return errors.AccessDenied; return errors.AccessDenied;
} }
@ -153,13 +154,22 @@ const api = {
} }
} else { } else {
for (let i = 0; i < authResults.length; i++) { for (let i = 0; i < authResults.length; i++) {
if (!authResults[i].isAllowed) { if (!authResults[i].isAllowed && !authResults[i].isImplicit) {
// Any explicit deny rejects the current APÏ call
log.trace('authorization denial from Vault'); log.trace('authorization denial from Vault');
return errors.AccessDenied; return errors.AccessDenied;
} else if (authResults[i].isAllowed) {
// If the action is allowed, the result is not implicit
// Deny.
isImplicitDeny = false;
} }
} }
} }
return returnTagCount; // Specific APIs are not checking any ACLs or Bucket Policies.
if (apiMethod === 'bucketPut' || apiMethod === 'serviceGet' && isImplicitDeny) {
return errors.AccessDenied;
}
return { returnTagCount, isImplicitDeny };
} }
return async.waterfall([ return async.waterfall([
@ -237,7 +247,8 @@ const api = {
if (checkedResults instanceof Error) { if (checkedResults instanceof Error) {
return callback(checkedResults); return callback(checkedResults);
} }
returnTagCount = checkedResults; returnTagCount = checkedResults.returnTagCount;
request.isImplicitIdentityDeny = checkedResults.isImplicitDeny;
} }
if (apiMethod === 'objectPut' || apiMethod === 'objectPutPart') { if (apiMethod === 'objectPut' || apiMethod === 'objectPutPart') {
request._response = response; request._response = response;

View File

@ -1,5 +1,6 @@
const { evaluators, actionMaps, RequestContext } = require('arsenal').policies; const { evaluators, actionMaps, RequestContext, requestUtils } = require('arsenal').policies;
const constants = require('../../../../constants'); const constants = require('../../../../constants');
const { config } = require('../../../Config');
const { allAuthedUsersId, bucketOwnerActions, logId, publicId, const { allAuthedUsersId, bucketOwnerActions, logId, publicId,
assumedRoleArnResourceType, backbeatLifecycleSessionName } = constants; assumedRoleArnResourceType, backbeatLifecycleSessionName } = constants;
@ -198,6 +199,20 @@ function _checkBucketPolicyResources(request, resource, log) {
return evaluators.isResourceApplicable(requestContext, resource, log); return evaluators.isResourceApplicable(requestContext, resource, log);
} }
function _checkBucketPolicyConditions(request, conditions, log) {
const ip = request ? requestUtils.getClientIp(request, config) : undefined;
if (!conditions) {
return true;
}
// build request context from the request!
const requestContext = new RequestContext(request.headers, request.query,
request.bucketName, request.objectKey, ip,
request.connection.encrypted, request.resourceType, 's3', null, null,
null, null, null, null, null, null, null, null, null,
request.objectLockRetentionDays);
return evaluators.meetConditions(requestContext, conditions, log);
}
function _getAccountId(arn) { function _getAccountId(arn) {
// account or user arn is of format 'arn:aws:iam::<12-digit-acct-id>:etc... // account or user arn is of format 'arn:aws:iam::<12-digit-acct-id>:etc...
return arn.substr(13, 12); return arn.substr(13, 12);
@ -255,12 +270,13 @@ function checkBucketPolicy(policy, requestType, canonicalID, arn, bucketOwner, l
const principalMatch = _checkPrincipals(canonicalID, arn, s.Principal); const principalMatch = _checkPrincipals(canonicalID, arn, s.Principal);
const actionMatch = _checkBucketPolicyActions(requestType, s.Action, log); const actionMatch = _checkBucketPolicyActions(requestType, s.Action, log);
const resourceMatch = _checkBucketPolicyResources(request, s.Resource, log); const resourceMatch = _checkBucketPolicyResources(request, s.Resource, log);
const conditionsMatch = _checkBucketPolicyConditions(request, s.Condition, log);
if (principalMatch && actionMatch && resourceMatch && s.Effect === 'Deny') { if (principalMatch && actionMatch && resourceMatch && conditionsMatch && s.Effect === 'Deny') {
// explicit deny trumps any allows, so return immediately // explicit deny trumps any allows, so return immediately
return 'explicitDeny'; return 'explicitDeny';
} }
if (principalMatch && actionMatch && resourceMatch && s.Effect === 'Allow') { if (principalMatch && actionMatch && resourceMatch && conditionsMatch && s.Effect === 'Allow') {
permission = 'allow'; permission = 'allow';
} }
copiedStatement = copiedStatement.splice(1); copiedStatement = copiedStatement.splice(1);
@ -268,7 +284,18 @@ function checkBucketPolicy(policy, requestType, canonicalID, arn, bucketOwner, l
return permission; return permission;
} }
function isBucketAuthorized(bucket, requestType, canonicalID, authInfo, log, request) { function isIdentityAndResourceAuthorized(isImplicitIdentityDeny, resourceAuthzResult) {
// If resourceAuthzResult is true, the the IAM result is either Allow or
// implicit Deny (nothing applicable): in this case, we allow the request.
if (resourceAuthzResult === true) {
return true;
}
// If resourceAuthzResult is false, we only return true if IAM result is
// Allow. Otherwise we default to an implicit Deny.
return isImplicitIdentityDeny === false;
}
function isBucketAuthorized(bucket, requestType, canonicalID, authInfo, isImplicitIdentityDeny, log, request) {
// Check to see if user is authorized to perform a // Check to see if user is authorized to perform a
// particular action on bucket based on ACLs. // particular action on bucket based on ACLs.
// TODO: Add IAM checks // TODO: Add IAM checks
@ -280,32 +307,34 @@ function isBucketAuthorized(bucket, requestType, canonicalID, authInfo, log, req
} }
// if the bucket owner is an account, users should not have default access // if the bucket owner is an account, users should not have default access
if ((bucket.getOwner() === canonicalID) && requesterIsNotUser) { if ((bucket.getOwner() === canonicalID) && requesterIsNotUser) {
return true; return isIdentityAndResourceAuthorized(isImplicitIdentityDeny, true);
} }
const aclPermission = checkBucketAcls(bucket, requestType, canonicalID); const aclPermission = checkBucketAcls(bucket, requestType, canonicalID, requesterIsNotUser);
const bucketPolicy = bucket.getBucketPolicy(); const bucketPolicy = bucket.getBucketPolicy();
if (!bucketPolicy) { if (!bucketPolicy) {
return aclPermission; return isIdentityAndResourceAuthorized(isImplicitIdentityDeny, aclPermission);
} }
const bucketPolicyPermission = checkBucketPolicy(bucketPolicy, requestType, const bucketPolicyPermission = checkBucketPolicy(bucketPolicy, requestType,
canonicalID, arn, bucket.getOwner(), log, request); canonicalID, arn, bucket.getOwner(), log, request);
if (bucketPolicyPermission === 'explicitDeny') { if (bucketPolicyPermission === 'explicitDeny') {
return false; return false;
} }
return (aclPermission || (bucketPolicyPermission === 'allow')); return isIdentityAndResourceAuthorized(isImplicitIdentityDeny,
(aclPermission || (bucketPolicyPermission === 'allow')));
} }
function isObjAuthorized(bucket, objectMD, requestType, canonicalID, authInfo, log, request) { function isObjAuthorized(bucket, objectMD, requestType, canonicalID, authInfo, isImplicitIdentityDeny, log, request) {
const bucketOwner = bucket.getOwner(); const bucketOwner = bucket.getOwner();
if (!objectMD) { if (!objectMD) {
// User is already authorized on the bucket for FULL_CONTROL or WRITE or // User is already authorized on the bucket for FULL_CONTROL or WRITE or
// bucket has canned ACL public-read-write // bucket has canned ACL public-read-write
if (requestType === 'objectPut' || requestType === 'objectDelete') { if (requestType === 'objectPut' || requestType === 'objectDelete') {
return true; return isIdentityAndResourceAuthorized(isImplicitIdentityDeny, true);
} }
// check bucket has read access // check bucket has read access
// 'bucketGet' covers listObjects and listMultipartUploads, bucket read actions // 'bucketGet' covers listObjects and listMultipartUploads, bucket read actions
return isBucketAuthorized(bucket, 'bucketGet', canonicalID, authInfo, log, request); return isIdentityAndResourceAuthorized(isImplicitIdentityDeny,
isBucketAuthorized(bucket, 'bucketGet', canonicalID, authInfo, isImplicitIdentityDeny, log, request));
} }
let requesterIsNotUser = true; let requesterIsNotUser = true;
let arn = null; let arn = null;
@ -314,7 +343,7 @@ function isObjAuthorized(bucket, objectMD, requestType, canonicalID, authInfo, l
arn = authInfo.getArn(); arn = authInfo.getArn();
} }
if (objectMD['owner-id'] === canonicalID && requesterIsNotUser) { if (objectMD['owner-id'] === canonicalID && requesterIsNotUser) {
return true; return isIdentityAndResourceAuthorized(isImplicitIdentityDeny, true);
} }
// account is authorized if: // account is authorized if:
// - requesttype is included in bucketOwnerActions and // - requesttype is included in bucketOwnerActions and
@ -323,20 +352,21 @@ function isObjAuthorized(bucket, objectMD, requestType, canonicalID, authInfo, l
if (bucketOwnerActions.includes(requestType) if (bucketOwnerActions.includes(requestType)
&& (bucketOwner === canonicalID) && (bucketOwner === canonicalID)
&& requesterIsNotUser) { && requesterIsNotUser) {
return true; return isIdentityAndResourceAuthorized(isImplicitIdentityDeny, true);
} }
const aclPermission = checkObjectAcls(bucket, objectMD, requestType, const aclPermission = checkObjectAcls(bucket, objectMD, requestType,
canonicalID); canonicalID);
const bucketPolicy = bucket.getBucketPolicy(); const bucketPolicy = bucket.getBucketPolicy();
if (!bucketPolicy) { if (!bucketPolicy) {
return aclPermission; return isIdentityAndResourceAuthorized(isImplicitIdentityDeny, aclPermission);
} }
const bucketPolicyPermission = checkBucketPolicy(bucketPolicy, requestType, const bucketPolicyPermission = checkBucketPolicy(bucketPolicy, requestType,
canonicalID, arn, bucket.getOwner(), log, request); canonicalID, arn, bucket.getOwner(), log, request);
if (bucketPolicyPermission === 'explicitDeny') { if (bucketPolicyPermission === 'explicitDeny') {
return false; return false;
} }
return (aclPermission || (bucketPolicyPermission === 'allow')); return isIdentityAndResourceAuthorized(isImplicitIdentityDeny,
(aclPermission || (bucketPolicyPermission === 'allow')));
} }
function _checkResource(resource, bucketArn) { function _checkResource(resource, bucketArn) {

View File

@ -22,10 +22,11 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
// but the requestType is the more general 'objectDelete' // but the requestType is the more general 'objectDelete'
const metadataValParams = Object.assign({}, metadataValMPUparams); const metadataValParams = Object.assign({}, metadataValMPUparams);
metadataValParams.requestType = 'objectPut'; metadataValParams.requestType = 'objectPut';
const authzIdentityResult = request ? request.isImplicitIdentityDeny : true;
async.waterfall([ async.waterfall([
function checkDestBucketVal(next) { function checkDestBucketVal(next) {
metadataValidateBucketAndObj(metadataValParams, log, metadataValidateBucketAndObj(metadataValParams, authzIdentityResult, log,
(err, destinationBucket) => { (err, destinationBucket) => {
if (err) { if (err) {
return next(err, destinationBucket); return next(err, destinationBucket);

View File

@ -34,7 +34,7 @@ function bucketDelete(authInfo, request, log, cb) {
request, request,
}; };
return metadataValidateBucket(metadataValParams, log, return metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucketMD) => { (err, bucketMD) => {
const corsHeaders = collectCorsHeaders(request.headers.origin, const corsHeaders = collectCorsHeaders(request.headers.origin,
request.method, bucketMD); request.method, bucketMD);

View File

@ -26,7 +26,7 @@ function bucketDeleteEncryption(authInfo, request, log, callback) {
}; };
return async.waterfall([ return async.waterfall([
next => metadataValidateBucket(metadataValParams, log, next), next => metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, next),
(bucket, next) => checkExpectedBucketOwner(request.headers, bucket, log, err => next(err, bucket)), (bucket, next) => checkExpectedBucketOwner(request.headers, bucket, log, err => next(err, bucket)),
(bucket, next) => { (bucket, next) => {
const sseConfig = bucket.getServerSideEncryption(); const sseConfig = bucket.getServerSideEncryption();

View File

@ -21,7 +21,7 @@ function bucketDeleteLifecycle(authInfo, request, log, callback) {
requestType: 'bucketDeleteLifecycle', requestType: 'bucketDeleteLifecycle',
request, request,
}; };
return metadataValidateBucket(metadataValParams, log, (err, bucket) => { return metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, (err, bucket) => {
const corsHeaders = collectCorsHeaders(headers.origin, method, bucket); const corsHeaders = collectCorsHeaders(headers.origin, method, bucket);
if (err) { if (err) {
log.debug('error processing request', { log.debug('error processing request', {

View File

@ -19,7 +19,7 @@ function bucketDeletePolicy(authInfo, request, log, callback) {
requestType: 'bucketDeletePolicy', requestType: 'bucketDeletePolicy',
request, request,
}; };
return metadataValidateBucket(metadataValParams, log, (err, bucket) => { return metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, (err, bucket) => {
const corsHeaders = collectCorsHeaders(headers.origin, method, bucket); const corsHeaders = collectCorsHeaders(headers.origin, method, bucket);
if (err) { if (err) {
log.debug('error processing request', { log.debug('error processing request', {

View File

@ -21,7 +21,7 @@ function bucketDeleteReplication(authInfo, request, log, callback) {
requestType: 'bucketDeleteReplication', requestType: 'bucketDeleteReplication',
request, request,
}; };
return metadataValidateBucket(metadataValParams, log, (err, bucket) => { return metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, (err, bucket) => {
const corsHeaders = collectCorsHeaders(headers.origin, method, bucket); const corsHeaders = collectCorsHeaders(headers.origin, method, bucket);
if (err) { if (err) {
log.debug('error processing request', { log.debug('error processing request', {

View File

@ -30,7 +30,7 @@ async function bucketDeleteTagging(authInfo, request, log, callback) {
}; };
try { try {
bucket = await metadataValidateBucketPromise(metadataValParams, log); bucket = await metadataValidateBucketPromise(metadataValParams, request.isImplicitIdentityDeny, log);
bucket.setTags([]); bucket.setTags([]);
// eslint-disable-next-line no-unused-expressions // eslint-disable-next-line no-unused-expressions
await updateBucketPromise(bucket.getName(), bucket, log); await updateBucketPromise(bucket.getName(), bucket, log);

View File

@ -351,7 +351,7 @@ function bucketGet(authInfo, request, log, callback) {
listParams.marker = params.marker; listParams.marker = params.marker;
} }
metadataValidateBucket(metadataValParams, log, (err, bucket) => { metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, (err, bucket) => {
const corsHeaders = collectCorsHeaders(request.headers.origin, const corsHeaders = collectCorsHeaders(request.headers.origin,
request.method, bucket); request.method, bucket);
if (err) { if (err) {

View File

@ -55,7 +55,7 @@ function bucketGetACL(authInfo, request, log, callback) {
}, },
}; };
metadataValidateBucket(metadataValParams, log, (err, bucket) => { metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, (err, bucket) => {
const corsHeaders = collectCorsHeaders(request.headers.origin, const corsHeaders = collectCorsHeaders(request.headers.origin,
request.method, bucket); request.method, bucket);
if (err) { if (err) {

View File

@ -27,7 +27,7 @@ function bucketGetEncryption(authInfo, request, log, callback) {
}; };
return async.waterfall([ return async.waterfall([
next => metadataValidateBucket(metadataValParams, log, next), next => metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, next),
(bucket, next) => checkExpectedBucketOwner(request.headers, bucket, log, err => next(err, bucket)), (bucket, next) => checkExpectedBucketOwner(request.headers, bucket, log, err => next(err, bucket)),
(bucket, next) => { (bucket, next) => {
// If sseInfo is present but the `mandatory` flag is not set // If sseInfo is present but the `mandatory` flag is not set

View File

@ -24,7 +24,7 @@ function bucketGetLifecycle(authInfo, request, log, callback) {
requestType: 'bucketGetLifecycle', requestType: 'bucketGetLifecycle',
request, request,
}; };
return metadataValidateBucket(metadataValParams, log, (err, bucket) => { return metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, (err, bucket) => {
const corsHeaders = collectCorsHeaders(headers.origin, method, bucket); const corsHeaders = collectCorsHeaders(headers.origin, method, bucket);
if (err) { if (err) {
log.debug('error processing request', { log.debug('error processing request', {

View File

@ -41,7 +41,7 @@ function bucketGetNotification(authInfo, request, log, callback) {
request, request,
}; };
return metadataValidateBucket(metadataValParams, log, (err, bucket) => { return metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, (err, bucket) => {
const corsHeaders = collectCorsHeaders(headers.origin, method, bucket); const corsHeaders = collectCorsHeaders(headers.origin, method, bucket);
if (err) { if (err) {
log.debug('error processing request', { log.debug('error processing request', {

View File

@ -36,7 +36,7 @@ function bucketGetObjectLock(authInfo, request, log, callback) {
requestType: 'bucketGetObjectLock', requestType: 'bucketGetObjectLock',
request, request,
}; };
return metadataValidateBucket(metadataValParams, log, (err, bucket) => { return metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, (err, bucket) => {
const corsHeaders = collectCorsHeaders(headers.origin, method, bucket); const corsHeaders = collectCorsHeaders(headers.origin, method, bucket);
if (err) { if (err) {
log.debug('error processing request', { log.debug('error processing request', {

View File

@ -21,7 +21,7 @@ function bucketGetPolicy(authInfo, request, log, callback) {
request, request,
}; };
return metadataValidateBucket(metadataValParams, log, (err, bucket) => { return metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, (err, bucket) => {
const corsHeaders = collectCorsHeaders(headers.origin, method, bucket); const corsHeaders = collectCorsHeaders(headers.origin, method, bucket);
if (err) { if (err) {
log.debug('error processing request', { log.debug('error processing request', {

View File

@ -24,7 +24,7 @@ function bucketGetReplication(authInfo, request, log, callback) {
requestType: 'bucketGetReplication', requestType: 'bucketGetReplication',
request, request,
}; };
return metadataValidateBucket(metadataValParams, log, (err, bucket) => { return metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, (err, bucket) => {
const corsHeaders = collectCorsHeaders(headers.origin, method, bucket); const corsHeaders = collectCorsHeaders(headers.origin, method, bucket);
if (err) { if (err) {
log.debug('error processing request', { log.debug('error processing request', {

View File

@ -78,7 +78,7 @@ async function bucketGetTagging(authInfo, request, log, callback) {
let xml = null; let xml = null;
try { try {
bucket = await metadataValidateBucketPromise(metadataValParams, log); bucket = await metadataValidateBucketPromise(metadataValParams, request.isImplicitIdentityDeny, log);
// eslint-disable-next-line no-unused-expressions // eslint-disable-next-line no-unused-expressions
await checkExpectedBucketOwnerPromise(headers, bucket, log); await checkExpectedBucketOwnerPromise(headers, bucket, log);
const tags = bucket.getTags(); const tags = bucket.getTags();

View File

@ -58,7 +58,7 @@ function bucketGetVersioning(authInfo, request, log, callback) {
request, request,
}; };
metadataValidateBucket(metadataValParams, log, (err, bucket) => { metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, (err, bucket) => {
const corsHeaders = collectCorsHeaders(request.headers.origin, const corsHeaders = collectCorsHeaders(request.headers.origin,
request.method, bucket); request.method, bucket);
if (err) { if (err) {

View File

@ -22,7 +22,7 @@ function bucketHead(authInfo, request, log, callback) {
requestType: 'bucketHead', requestType: 'bucketHead',
request, request,
}; };
metadataValidateBucket(metadataValParams, log, (err, bucket) => { metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, (err, bucket) => {
const corsHeaders = collectCorsHeaders(request.headers.origin, const corsHeaders = collectCorsHeaders(request.headers.origin,
request.method, bucket); request.method, bucket);
if (err) { if (err) {

View File

@ -105,7 +105,7 @@ function bucketPutACL(authInfo, request, log, callback) {
return async.waterfall([ return async.waterfall([
function waterfall1(next) { function waterfall1(next) {
metadataValidateBucket(metadataValParams, log, metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket) => { (err, bucket) => {
if (err) { if (err) {
log.trace('request authorization failed', { log.trace('request authorization failed', {

View File

@ -28,7 +28,7 @@ function bucketPutEncryption(authInfo, request, log, callback) {
}; };
return async.waterfall([ return async.waterfall([
next => metadataValidateBucket(metadataValParams, log, next), next => metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, next),
(bucket, next) => checkExpectedBucketOwner(request.headers, bucket, log, err => next(err, bucket)), (bucket, next) => checkExpectedBucketOwner(request.headers, bucket, log, err => next(err, bucket)),
(bucket, next) => { (bucket, next) => {
log.trace('parsing encryption config', { method: 'bucketPutEncryption' }); log.trace('parsing encryption config', { method: 'bucketPutEncryption' });

View File

@ -43,7 +43,7 @@ function bucketPutLifecycle(authInfo, request, log, callback) {
return next(null, configObj); return next(null, configObj);
}); });
}, },
(lcConfig, next) => metadataValidateBucket(metadataValParams, log, (lcConfig, next) => metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket) => { (err, bucket) => {
if (err) { if (err) {
return next(err, bucket); return next(err, bucket);

View File

@ -34,7 +34,7 @@ function bucketPutNotification(authInfo, request, log, callback) {
const notifConfig = notificationConfig.error ? undefined : notificationConfig; const notifConfig = notificationConfig.error ? undefined : notificationConfig;
process.nextTick(() => next(notificationConfig.error, notifConfig)); process.nextTick(() => next(notificationConfig.error, notifConfig));
}, },
(notifConfig, next) => metadataValidateBucket(metadataValParams, log, (notifConfig, next) => metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket) => next(err, bucket, notifConfig)), (err, bucket) => next(err, bucket, notifConfig)),
(bucket, notifConfig, next) => { (bucket, notifConfig, next) => {
bucket.setNotificationConfiguration(notifConfig); bucket.setNotificationConfiguration(notifConfig);

View File

@ -41,7 +41,7 @@ function bucketPutObjectLock(authInfo, request, log, callback) {
return next(configObj.error || null, configObj); return next(configObj.error || null, configObj);
}); });
}, },
(objectLockConfig, next) => metadataValidateBucket(metadataValParams, (objectLockConfig, next) => metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny,
log, (err, bucket) => { log, (err, bucket) => {
if (err) { if (err) {
return next(err, bucket); return next(err, bucket);

View File

@ -17,8 +17,7 @@ const { BucketPolicy } = models;
function _checkNotImplementedPolicy(policyString) { function _checkNotImplementedPolicy(policyString) {
// bucket names and key names cannot include "", so including those // bucket names and key names cannot include "", so including those
// isolates not implemented keys // isolates not implemented keys
return policyString.includes('"Condition"') return policyString.includes('"Service"')
|| policyString.includes('"Service"')
|| policyString.includes('"Federated"'); || policyString.includes('"Federated"');
} }
@ -70,7 +69,7 @@ function bucketPutPolicy(authInfo, request, log, callback) {
return next(null, bucketPolicy); return next(null, bucketPolicy);
}); });
}, },
(bucketPolicy, next) => metadataValidateBucket(metadataValParams, log, (bucketPolicy, next) => metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket) => { (err, bucket) => {
if (err) { if (err) {
return next(err, bucket); return next(err, bucket);

View File

@ -37,7 +37,7 @@ function bucketPutReplication(authInfo, request, log, callback) {
// Check bucket user privileges and ensure versioning is 'Enabled'. // Check bucket user privileges and ensure versioning is 'Enabled'.
(config, next) => (config, next) =>
// TODO: Validate that destination bucket exists and has versioning. // TODO: Validate that destination bucket exists and has versioning.
metadataValidateBucket(metadataValParams, log, (err, bucket) => { metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log, (err, bucket) => {
if (err) { if (err) {
return next(err); return next(err);
} }

View File

@ -42,7 +42,7 @@ function bucketPutTagging(authInfo, request, log, callback) {
}; };
let bucket = null; let bucket = null;
return waterfall([ return waterfall([
next => metadataValidateBucket(metadataValParams, log, next => metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log,
(err, b) => { (err, b) => {
bucket = b; bucket = b;
return next(err); return next(err);

View File

@ -94,7 +94,7 @@ function bucketPutVersioning(authInfo, request, log, callback) {
return waterfall([ return waterfall([
next => _parseXML(request, log, next), next => _parseXML(request, log, next),
next => metadataValidateBucket(metadataValParams, log, next => metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket) => next(err, bucket)), // ignore extra null object, (err, bucket) => next(err, bucket)), // ignore extra null object,
(bucket, next) => parseString(request.post, (err, result) => { (bucket, next) => parseString(request.post, (err, result) => {
// just for linting; there should not be any parsing error here // just for linting; there should not be any parsing error here

View File

@ -120,7 +120,7 @@ function completeMultipartUpload(authInfo, request, log, callback) {
// at the destinationBucket level are same as objectPut // at the destinationBucket level are same as objectPut
requestType: 'objectPut', requestType: 'objectPut',
}; };
metadataValidateBucketAndObj(metadataValParams, log, next); metadataValidateBucketAndObj(metadataValParams, request.isImplicitIdentityDeny, log, next);
}, },
function validateMultipart(destBucket, objMD, next) { function validateMultipart(destBucket, objMD, next) {
if (objMD) { if (objMD) {

View File

@ -262,7 +262,7 @@ function initiateMultipartUpload(authInfo, request, log, callback) {
} }
async.waterfall([ async.waterfall([
next => metadataValidateBucketAndObj(metadataValParams, log, next => metadataValidateBucketAndObj(metadataValParams, request.isImplicitIdentityDeny, log,
(error, destinationBucket) => { (error, destinationBucket) => {
const corsHeaders = collectCorsHeaders(request.headers.origin, const corsHeaders = collectCorsHeaders(request.headers.origin,
request.method, destinationBucket); request.method, destinationBucket);

View File

@ -105,7 +105,7 @@ function listMultipartUploads(authInfo, request, log, callback) {
function waterfall1(next) { function waterfall1(next) {
// Check final destination bucket for authorization rather // Check final destination bucket for authorization rather
// than multipart upload bucket // than multipart upload bucket
metadataValidateBucket(metadataValParams, log, metadataValidateBucket(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket) => next(err, bucket)); (err, bucket) => next(err, bucket));
}, },
function getMPUBucket(bucket, next) { function getMPUBucket(bucket, next) {

View File

@ -115,7 +115,7 @@ function listParts(authInfo, request, log, callback) {
async.waterfall([ async.waterfall([
function checkDestBucketVal(next) { function checkDestBucketVal(next) {
metadataValidateBucketAndObj(metadataValParams, log, metadataValidateBucketAndObj(metadataValParams, request.isImplicitIdentityDeny, log,
(err, destinationBucket) => { (err, destinationBucket) => {
if (err) { if (err) {
return next(err, destinationBucket, null); return next(err, destinationBucket, null);

View File

@ -249,7 +249,7 @@ function objectCopy(authInfo, request, sourceBucket,
} }
return async.waterfall([ return async.waterfall([
function checkDestAuth(next) { function checkDestAuth(next) {
return metadataValidateBucketAndObj(valPutParams, log, return metadataValidateBucketAndObj(valPutParams, request.isImplicitIdentityDeny, log,
(err, destBucketMD, destObjMD) => { (err, destBucketMD, destObjMD) => {
if (err) { if (err) {
log.debug('error validating put part of request', log.debug('error validating put part of request',
@ -267,7 +267,7 @@ function objectCopy(authInfo, request, sourceBucket,
}); });
}, },
function checkSourceAuthorization(destBucketMD, destObjMD, next) { function checkSourceAuthorization(destBucketMD, destObjMD, next) {
return metadataValidateBucketAndObj(valGetParams, log, return metadataValidateBucketAndObj(valGetParams, request.isImplicitIdentityDeny, log,
(err, sourceBucketMD, sourceObjMD) => { (err, sourceBucketMD, sourceObjMD) => {
if (err) { if (err) {
log.debug('error validating get part of request', log.debug('error validating get part of request',

View File

@ -59,7 +59,7 @@ function objectDelete(authInfo, request, log, cb) {
const canonicalID = authInfo.getCanonicalID(); const canonicalID = authInfo.getCanonicalID();
return async.waterfall([ return async.waterfall([
function validateBucketAndObj(next) { function validateBucketAndObj(next) {
return metadataValidateBucketAndObj(valParams, log, return metadataValidateBucketAndObj(valParams, request.isImplicitIdentityDeny, log,
(err, bucketMD, objMD) => { (err, bucketMD, objMD) => {
if (err) { if (err) {
return next(err, bucketMD); return next(err, bucketMD);

View File

@ -49,7 +49,7 @@ function objectDeleteTagging(authInfo, request, log, callback) {
}; };
return async.waterfall([ return async.waterfall([
next => metadataValidateBucketAndObj(metadataValParams, log, next => metadataValidateBucketAndObj(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket, objectMD) => { (err, bucket, objectMD) => {
if (err) { if (err) {
log.trace('request authorization failed', log.trace('request authorization failed',

View File

@ -50,7 +50,7 @@ function objectGet(authInfo, request, returnTagCount, log, callback) {
request, request,
}; };
return metadataValidateBucketAndObj(mdValParams, log, return metadataValidateBucketAndObj(mdValParams, request.isImplicitIdentityDeny, log,
(err, bucket, objMD) => { (err, bucket, objMD) => {
const corsHeaders = collectCorsHeaders(request.headers.origin, const corsHeaders = collectCorsHeaders(request.headers.origin,
request.method, bucket); request.method, bucket);

View File

@ -74,7 +74,7 @@ function objectGetACL(authInfo, request, log, callback) {
return async.waterfall([ return async.waterfall([
function validateBucketAndObj(next) { function validateBucketAndObj(next) {
return metadataValidateBucketAndObj(metadataValParams, log, return metadataValidateBucketAndObj(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket, objectMD) => { (err, bucket, objectMD) => {
if (err) { if (err) {
log.trace('request authorization failed', log.trace('request authorization failed',

View File

@ -45,7 +45,7 @@ function objectGetLegalHold(authInfo, request, log, callback) {
}; };
return async.waterfall([ return async.waterfall([
next => metadataValidateBucketAndObj(metadataValParams, log, next => metadataValidateBucketAndObj(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket, objectMD) => { (err, bucket, objectMD) => {
if (err) { if (err) {
log.trace('request authorization failed', log.trace('request authorization failed',

View File

@ -45,7 +45,7 @@ function objectGetRetention(authInfo, request, log, callback) {
}; };
return async.waterfall([ return async.waterfall([
next => metadataValidateBucketAndObj(metadataValParams, log, next => metadataValidateBucketAndObj(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket, objectMD) => { (err, bucket, objectMD) => {
if (err) { if (err) {
log.trace('request authorization failed', log.trace('request authorization failed',

View File

@ -46,7 +46,7 @@ function objectGetTagging(authInfo, request, log, callback) {
}; };
return async.waterfall([ return async.waterfall([
next => metadataValidateBucketAndObj(metadataValParams, log, next => metadataValidateBucketAndObj(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket, objectMD) => { (err, bucket, objectMD) => {
if (err) { if (err) {
log.trace('request authorization failed', log.trace('request authorization failed',

View File

@ -50,7 +50,7 @@ function objectHead(authInfo, request, log, callback) {
request, request,
}; };
return metadataValidateBucketAndObj(mdValParams, log, return metadataValidateBucketAndObj(mdValParams, request.isImplicitIdentityDeny, log,
(err, bucket, objMD) => { (err, bucket, objMD) => {
const corsHeaders = collectCorsHeaders(request.headers.origin, const corsHeaders = collectCorsHeaders(request.headers.origin,
request.method, bucket); request.method, bucket);

View File

@ -71,7 +71,7 @@ function objectPut(authInfo, request, streamingV4Params, log, callback) {
log.trace('owner canonicalID to send to data', { canonicalID }); log.trace('owner canonicalID to send to data', { canonicalID });
return metadataValidateBucketAndObj(valParams, log, return metadataValidateBucketAndObj(valParams, request.isImplicitIdentityDeny, log,
(err, bucket, objMD) => { (err, bucket, objMD) => {
const responseHeaders = collectCorsHeaders(headers.origin, const responseHeaders = collectCorsHeaders(headers.origin,
method, bucket); method, bucket);

View File

@ -112,7 +112,7 @@ function objectPutACL(authInfo, request, log, cb) {
return async.waterfall([ return async.waterfall([
function validateBucketAndObj(next) { function validateBucketAndObj(next) {
return metadataValidateBucketAndObj(metadataValParams, log, return metadataValidateBucketAndObj(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket, objectMD) => { (err, bucket, objectMD) => {
if (err) { if (err) {
return next(err); return next(err);

View File

@ -93,7 +93,7 @@ function objectPutCopyPart(authInfo, request, sourceBucket,
return async.waterfall([ return async.waterfall([
function checkDestAuth(next) { function checkDestAuth(next) {
return metadataValidateBucketAndObj(valPutParams, log, return metadataValidateBucketAndObj(valPutParams, request.isImplicitIdentityDeny, log,
(err, destBucketMD) => { (err, destBucketMD) => {
if (err) { if (err) {
log.debug('error validating authorization for ' + log.debug('error validating authorization for ' +
@ -112,7 +112,7 @@ function objectPutCopyPart(authInfo, request, sourceBucket,
}); });
}, },
function checkSourceAuthorization(destBucketMD, next) { function checkSourceAuthorization(destBucketMD, next) {
return metadataValidateBucketAndObj(valGetParams, log, return metadataValidateBucketAndObj(valGetParams, request.isImplicitIdentityDeny, log,
(err, sourceBucketMD, sourceObjMD) => { (err, sourceBucketMD, sourceObjMD) => {
if (err) { if (err) {
log.debug('error validating get part of request', log.debug('error validating get part of request',

View File

@ -48,7 +48,7 @@ function objectPutLegalHold(authInfo, request, log, callback) {
}; };
return async.waterfall([ return async.waterfall([
next => metadataValidateBucketAndObj(metadataValParams, log, next => metadataValidateBucketAndObj(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket, objectMD) => { (err, bucket, objectMD) => {
if (err) { if (err) {
log.trace('request authorization failed', log.trace('request authorization failed',

View File

@ -49,7 +49,22 @@ function objectPutRetention(authInfo, request, log, callback) {
}; };
return async.waterfall([ return async.waterfall([
next => metadataValidateBucketAndObj(metadataValParams, log, next => {
log.trace('parsing retention information');
parseRetentionXml(request.post, log,
(err, retentionInfo) => {
if (err) {
log.trace('error parsing retention information',
{ error: err });
return next(err);
}
const remainingDays = Math.ceil(
(new Date(retentionInfo.date) - Date.now()) / (1000 * 3600 * 24));
metadataValParams.request.objectLockRetentionDays = remainingDays;
return next(null, retentionInfo);
});
},
(retentionInfo, next) => metadataValidateBucketAndObj(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket, objectMD) => { (err, bucket, objectMD) => {
if (err) { if (err) {
log.trace('request authorization failed', log.trace('request authorization failed',
@ -77,13 +92,8 @@ function objectPutRetention(authInfo, request, log, callback) {
'Bucket is missing Object Lock Configuration' 'Bucket is missing Object Lock Configuration'
), bucket); ), bucket);
} }
return next(null, bucket, objectMD); return next(null, bucket, retentionInfo, objectMD);
}), }),
(bucket, objectMD, next) => {
log.trace('parsing retention information');
parseRetentionXml(request.post, log,
(err, retentionInfo) => next(err, bucket, retentionInfo, objectMD));
},
(bucket, retentionInfo, objectMD, next) => { (bucket, retentionInfo, objectMD, next) => {
const hasGovernanceBypass = hasGovernanceBypassHeader(request.headers); const hasGovernanceBypass = hasGovernanceBypassHeader(request.headers);
if (hasGovernanceBypass && authInfo.isRequesterAnIAMUser()) { if (hasGovernanceBypass && authInfo.isRequesterAnIAMUser()) {

View File

@ -50,7 +50,7 @@ function objectPutTagging(authInfo, request, log, callback) {
}; };
return async.waterfall([ return async.waterfall([
next => metadataValidateBucketAndObj(metadataValParams, log, next => metadataValidateBucketAndObj(metadataValParams, request.isImplicitIdentityDeny, log,
(err, bucket, objectMD) => { (err, bucket, objectMD) => {
if (err) { if (err) {
log.trace('request authorization failed', log.trace('request authorization failed',

View File

@ -94,6 +94,7 @@ function metadataGetObject(bucketName, objectKey, versionId, log, cb) {
* @param {string} params.requestType - type of request * @param {string} params.requestType - type of request
* @param {string} [params.preciseRequestType] - precise type of request * @param {string} [params.preciseRequestType] - precise type of request
* @param {object} params.request - http request object * @param {object} params.request - http request object
* @param {object} isImplicitIdentityDeny - identity authorization results
* @param {RequestLogger} log - request logger * @param {RequestLogger} log - request logger
* @return {ArsenalError|null} returns a validation error, or null if validation OK * @return {ArsenalError|null} returns a validation error, or null if validation OK
* The following errors may be returned: * The following errors may be returned:
@ -102,7 +103,7 @@ function metadataGetObject(bucketName, objectKey, versionId, log, cb) {
* bucket policy operation * bucket policy operation
* - AccessDenied: bucket is not authorized * - AccessDenied: bucket is not authorized
*/ */
function validateBucket(bucket, params, log) { function validateBucket(bucket, params, isImplicitIdentityDeny, log) {
const { authInfo, requestType, preciseRequestType, request } = params; const { authInfo, requestType, preciseRequestType, request } = params;
if (bucketShield(bucket, requestType)) { if (bucketShield(bucket, requestType)) {
log.debug('bucket is shielded from request', { log.debug('bucket is shielded from request', {
@ -119,7 +120,7 @@ function validateBucket(bucket, params, log) {
return errors.MethodNotAllowed; return errors.MethodNotAllowed;
} }
if (!isBucketAuthorized(bucket, (preciseRequestType || requestType), canonicalID, if (!isBucketAuthorized(bucket, (preciseRequestType || requestType), canonicalID,
authInfo, log, request)) { authInfo, isImplicitIdentityDeny, log, request)) {
log.debug('access denied for user on bucket', { requestType }); log.debug('access denied for user on bucket', { requestType });
return errors.AccessDenied; return errors.AccessDenied;
} }
@ -135,11 +136,12 @@ function validateBucket(bucket, params, log) {
* @param {string} [params.versionId] - version id if getting specific version * @param {string} [params.versionId] - version id if getting specific version
* @param {string} params.requestType - type of request * @param {string} params.requestType - type of request
* @param {object} params.request - http request object * @param {object} params.request - http request object
* @param {boolean} isImplicitIdentityDeny - identity authorization results
* @param {RequestLogger} log - request logger * @param {RequestLogger} log - request logger
* @param {function} callback - callback * @param {function} callback - callback
* @return {undefined} - and call callback with params err, bucket md * @return {undefined} - and call callback with params err, bucket md
*/ */
function metadataValidateBucketAndObj(params, log, callback) { function metadataValidateBucketAndObj(params, isImplicitIdentityDeny, log, callback) {
const { authInfo, bucketName, objectKey, versionId, getDeleteMarker, const { authInfo, bucketName, objectKey, versionId, getDeleteMarker,
requestType, request } = params; requestType, request } = params;
async.waterfall([ async.waterfall([
@ -161,7 +163,7 @@ function metadataValidateBucketAndObj(params, log, callback) {
}); });
return next(errors.NoSuchBucket); return next(errors.NoSuchBucket);
} }
const validationError = validateBucket(bucket, params, log); const validationError = validateBucket(bucket, params, isImplicitIdentityDeny, log);
if (validationError) { if (validationError) {
return next(validationError, bucket); return next(validationError, bucket);
} }
@ -174,7 +176,8 @@ function metadataValidateBucketAndObj(params, log, callback) {
}, },
(bucket, objMD, next) => { (bucket, objMD, next) => {
const canonicalID = authInfo.getCanonicalID(); const canonicalID = authInfo.getCanonicalID();
if (!isObjAuthorized(bucket, objMD, requestType, canonicalID, authInfo, log, request)) { if (!isObjAuthorized(bucket, objMD, requestType, canonicalID, authInfo, isImplicitIdentityDeny,
log, request)) {
log.debug('access denied for user on object', { requestType }); log.debug('access denied for user on object', { requestType });
return next(errors.AccessDenied, bucket); return next(errors.AccessDenied, bucket);
} }
@ -196,18 +199,19 @@ function metadataValidateBucketAndObj(params, log, callback) {
* @param {string} params.bucketName - name of bucket * @param {string} params.bucketName - name of bucket
* @param {string} params.requestType - type of request * @param {string} params.requestType - type of request
* @param {string} params.request - http request object * @param {string} params.request - http request object
* @param {boolean} isImplicitIdentityDeny - identity authorization results
* @param {RequestLogger} log - request logger * @param {RequestLogger} log - request logger
* @param {function} callback - callback * @param {function} callback - callback
* @return {undefined} - and call callback with params err, bucket md * @return {undefined} - and call callback with params err, bucket md
*/ */
function metadataValidateBucket(params, log, callback) { function metadataValidateBucket(params, isImplicitIdentityDeny, log, callback) {
const { bucketName } = params; const { bucketName } = params;
return metadata.getBucket(bucketName, log, (err, bucket) => { return metadata.getBucket(bucketName, log, (err, bucket) => {
if (err) { if (err) {
log.debug('metadata getbucket failed', { error: err }); log.debug('metadata getbucket failed', { error: err });
return callback(err); return callback(err);
} }
const validationError = validateBucket(bucket, params, log); const validationError = validateBucket(bucket, params, isImplicitIdentityDeny, log);
return callback(validationError, bucket); return callback(validationError, bucket);
}); });
} }

View File

@ -1271,7 +1271,7 @@ function routeBackbeat(clientIP, request, response, log) {
requestType: 'ReplicateObject', requestType: 'ReplicateObject',
request, request,
}; };
return metadataValidateBucketAndObj(mdValParams, log, next); return metadataValidateBucketAndObj(mdValParams, request.isImplicitIdentityDeny, log, next);
}, },
(bucketInfo, objMd, next) => { (bucketInfo, objMd, next) => {
if (useMultipleBackend) { if (useMultipleBackend) {

View File

@ -20,7 +20,7 @@
"homepage": "https://github.com/scality/S3#readme", "homepage": "https://github.com/scality/S3#readme",
"dependencies": { "dependencies": {
"@hapi/joi": "^17.1.0", "@hapi/joi": "^17.1.0",
"arsenal": "git+https://github.com/scality/arsenal#7.70.4", "arsenal": "git+https://github.com/scality/arsenal#f4894a6d6ebb36ba1a559de4811180cb942d55a7",
"async": "~2.5.0", "async": "~2.5.0",
"aws-sdk": "2.905.0", "aws-sdk": "2.905.0",
"azure-storage": "^2.1.0", "azure-storage": "^2.1.0",

View File

@ -68,6 +68,7 @@ describe('GET object retention', () => {
afterEach(() => { afterEach(() => {
process.stdout.write('Removing object lock\n'); process.stdout.write('Removing object lock\n');
console.log(changeLockPromise, bucketName, objectName, versionId, changeObjectLock)
return changeLockPromise([{ bucket: bucketName, key: objectName, versionId }], '') return changeLockPromise([{ bucket: bucketName, key: objectName, versionId }], '')
.then(() => { .then(() => {
process.stdout.write('Emptying and deleting buckets\n'); process.stdout.write('Emptying and deleting buckets\n');
@ -81,7 +82,7 @@ describe('GET object retention', () => {
}); });
}); });
it('should return AccessDenied putting retention with another account', it.only('should return AccessDenied putting retention with another account',
done => { done => {
otherAccountS3.getObjectRetention({ otherAccountS3.getObjectRetention({
Bucket: bucketName, Bucket: bucketName,

View File

@ -244,7 +244,7 @@ describe('bucket policy authorization', () => {
describe('isBucketAuthorized with no policy set', () => { describe('isBucketAuthorized with no policy set', () => {
it('should allow access to bucket owner', done => { it('should allow access to bucket owner', done => {
const allowed = isBucketAuthorized(bucket, 'bucketPut', const allowed = isBucketAuthorized(bucket, 'bucketPut',
bucketOwnerCanonicalId, null, log); bucketOwnerCanonicalId, null, true, log);
assert.equal(allowed, true); assert.equal(allowed, true);
done(); done();
}); });
@ -252,7 +252,7 @@ describe('bucket policy authorization', () => {
it('should deny access to non-bucket owner', it('should deny access to non-bucket owner',
done => { done => {
const allowed = isBucketAuthorized(bucket, 'bucketPut', const allowed = isBucketAuthorized(bucket, 'bucketPut',
altAcctCanonicalId, null, log); altAcctCanonicalId, null, true, log);
assert.equal(allowed, false); assert.equal(allowed, false);
done(); done();
}); });
@ -268,7 +268,7 @@ describe('bucket policy authorization', () => {
it('should allow access to non-bucket owner if principal is set to "*"', it('should allow access to non-bucket owner if principal is set to "*"',
done => { done => {
const allowed = isBucketAuthorized(bucket, bucAction, const allowed = isBucketAuthorized(bucket, bucAction,
altAcctCanonicalId, null, log); altAcctCanonicalId, null, true, log);
assert.equal(allowed, true); assert.equal(allowed, true);
done(); done();
}); });
@ -276,7 +276,7 @@ describe('bucket policy authorization', () => {
it('should allow access to public user if principal is set to "*"', it('should allow access to public user if principal is set to "*"',
done => { done => {
const allowed = isBucketAuthorized(bucket, bucAction, const allowed = isBucketAuthorized(bucket, bucAction,
constants.publicId, null, log); constants.publicId, null, true, log);
assert.equal(allowed, true); assert.equal(allowed, true);
done(); done();
}); });
@ -287,7 +287,7 @@ describe('bucket policy authorization', () => {
newPolicy.Statement[0][t.keyToChange] = t.bucketValue; newPolicy.Statement[0][t.keyToChange] = t.bucketValue;
bucket.setBucketPolicy(newPolicy); bucket.setBucketPolicy(newPolicy);
const allowed = isBucketAuthorized(bucket, bucAction, const allowed = isBucketAuthorized(bucket, bucAction,
t.bucketId, t.bucketAuthInfo, log); t.bucketId, t.bucketAuthInfo, true, log);
assert.equal(allowed, t.expected); assert.equal(allowed, t.expected);
done(); done();
}); });
@ -304,7 +304,7 @@ describe('bucket policy authorization', () => {
}; };
bucket.setBucketPolicy(newPolicy); bucket.setBucketPolicy(newPolicy);
const allowed = isBucketAuthorized(bucket, bucAction, const allowed = isBucketAuthorized(bucket, bucAction,
altAcctCanonicalId, null, log); altAcctCanonicalId, null, true, log);
assert.equal(allowed, false); assert.equal(allowed, false);
done(); done();
}); });
@ -312,7 +312,7 @@ describe('bucket policy authorization', () => {
it('should deny access to non-bucket owner with an unsupported action type', it('should deny access to non-bucket owner with an unsupported action type',
done => { done => {
const allowed = isBucketAuthorized(bucket, 'unsupportedAction', const allowed = isBucketAuthorized(bucket, 'unsupportedAction',
altAcctCanonicalId, null, log); altAcctCanonicalId, null, true, log);
assert.equal(allowed, false); assert.equal(allowed, false);
done(); done();
}); });
@ -325,7 +325,7 @@ describe('bucket policy authorization', () => {
it('should allow access to object owner', done => { it('should allow access to object owner', done => {
const allowed = isObjAuthorized(bucket, object, objAction, const allowed = isObjAuthorized(bucket, object, objAction,
objectOwnerCanonicalId, null, log); objectOwnerCanonicalId, null, true, log);
assert.equal(allowed, true); assert.equal(allowed, true);
done(); done();
}); });
@ -333,7 +333,7 @@ describe('bucket policy authorization', () => {
it('should deny access to non-object owner', it('should deny access to non-object owner',
done => { done => {
const allowed = isObjAuthorized(bucket, object, objAction, const allowed = isObjAuthorized(bucket, object, objAction,
altAcctCanonicalId, null, log); altAcctCanonicalId, null, true, log);
assert.equal(allowed, false); assert.equal(allowed, false);
done(); done();
}); });
@ -352,7 +352,7 @@ describe('bucket policy authorization', () => {
it('should allow access to non-object owner if principal is set to "*"', it('should allow access to non-object owner if principal is set to "*"',
done => { done => {
const allowed = isObjAuthorized(bucket, object, objAction, const allowed = isObjAuthorized(bucket, object, objAction,
altAcctCanonicalId, null, log); altAcctCanonicalId, null, true, log);
assert.equal(allowed, true); assert.equal(allowed, true);
done(); done();
}); });
@ -360,7 +360,7 @@ describe('bucket policy authorization', () => {
it('should allow access to public user if principal is set to "*"', it('should allow access to public user if principal is set to "*"',
done => { done => {
const allowed = isObjAuthorized(bucket, object, objAction, const allowed = isObjAuthorized(bucket, object, objAction,
constants.publicId, null, log); constants.publicId, null, true, log);
assert.equal(allowed, true); assert.equal(allowed, true);
done(); done();
}); });
@ -371,7 +371,7 @@ describe('bucket policy authorization', () => {
newPolicy.Statement[0][t.keyToChange] = t.objectValue; newPolicy.Statement[0][t.keyToChange] = t.objectValue;
bucket.setBucketPolicy(newPolicy); bucket.setBucketPolicy(newPolicy);
const allowed = isObjAuthorized(bucket, object, objAction, const allowed = isObjAuthorized(bucket, object, objAction,
t.objectId, t.objectAuthInfo, log); t.objectId, t.objectAuthInfo, true, log);
assert.equal(allowed, t.expected); assert.equal(allowed, t.expected);
done(); done();
}); });
@ -383,7 +383,7 @@ describe('bucket policy authorization', () => {
newPolicy.Statement[0].Action = ['s3:GetObject']; newPolicy.Statement[0].Action = ['s3:GetObject'];
bucket.setBucketPolicy(newPolicy); bucket.setBucketPolicy(newPolicy);
const allowed = isObjAuthorized(bucket, object, 'objectHead', const allowed = isObjAuthorized(bucket, object, 'objectHead',
altAcctCanonicalId, altAcctAuthInfo, log); altAcctCanonicalId, altAcctAuthInfo, true, log);
assert.equal(allowed, true); assert.equal(allowed, true);
done(); done();
}); });
@ -393,7 +393,7 @@ describe('bucket policy authorization', () => {
newPolicy.Statement[0].Action = ['s3:PutObject']; newPolicy.Statement[0].Action = ['s3:PutObject'];
bucket.setBucketPolicy(newPolicy); bucket.setBucketPolicy(newPolicy);
const allowed = isObjAuthorized(bucket, object, 'objectHead', const allowed = isObjAuthorized(bucket, object, 'objectHead',
altAcctCanonicalId, altAcctAuthInfo, log); altAcctCanonicalId, altAcctAuthInfo, true, log);
assert.equal(allowed, false); assert.equal(allowed, false);
done(); done();
}); });
@ -408,7 +408,7 @@ describe('bucket policy authorization', () => {
}; };
bucket.setBucketPolicy(newPolicy); bucket.setBucketPolicy(newPolicy);
const allowed = isObjAuthorized(bucket, object, objAction, const allowed = isObjAuthorized(bucket, object, objAction,
altAcctCanonicalId, null, log); altAcctCanonicalId, null, true, log);
assert.equal(allowed, false); assert.equal(allowed, false);
done(); done();
}); });
@ -416,7 +416,7 @@ describe('bucket policy authorization', () => {
it('should deny access to non-object owner with an unsupported action type', it('should deny access to non-object owner with an unsupported action type',
done => { done => {
const allowed = isObjAuthorized(bucket, object, 'unsupportedAction', const allowed = isObjAuthorized(bucket, object, 'unsupportedAction',
altAcctCanonicalId, null, log); altAcctCanonicalId, null, true, log);
assert.equal(allowed, false); assert.equal(allowed, false);
done(); done();
}); });

View File

@ -76,7 +76,7 @@ describe('putBucketPolicy API', () => {
}); });
}); });
it('should return error if policy contains conditions', done => { it.skip('should return error if policy contains conditions', done => {
expectedBucketPolicy.Statement[0].Condition = expectedBucketPolicy.Statement[0].Condition =
{ StringEquals: { 's3:x-amz-acl': ['public-read'] } }; { StringEquals: { 's3:x-amz-acl': ['public-read'] } };
bucketPutPolicy(authInfo, getPolicyRequest(expectedBucketPolicy), log, bucketPutPolicy(authInfo, getPolicyRequest(expectedBucketPolicy), log,

View File

@ -456,7 +456,7 @@ describe('without object metadata', () => {
bucket.setCannedAcl(value.canned); bucket.setCannedAcl(value.canned);
const results = requestTypes.map(type => const results = requestTypes.map(type =>
isObjAuthorized(bucket, null, type, value.id, authInfoUser, log)); isObjAuthorized(bucket, null, type, value.id, authInfoUser, true, log));
assert.deepStrictEqual(results, value.response); assert.deepStrictEqual(results, value.response);
done(); done();
}); });

View File

@ -48,7 +48,7 @@ describe('validateBucket', () => {
authInfo: otherAuthInfo, authInfo: otherAuthInfo,
requestType: 'bucketGet', requestType: 'bucketGet',
request: null, request: null,
}, log); }, true, log);
assert(validationResult); assert(validationResult);
assert(validationResult.is.AccessDenied); assert(validationResult.is.AccessDenied);
}); });

View File

@ -10,6 +10,7 @@ const versionIdUtils = versioning.VersionID;
const log = new DummyRequestLogger(); const log = new DummyRequestLogger();
function changeObjectLock(objects, newConfig, cb) { function changeObjectLock(objects, newConfig, cb) {
console.log('>W>>>', metadata, objects, newConfig, metadata.setup, metadata.client)
async.each(objects, (object, next) => { async.each(objects, (object, next) => {
const { bucket, key, versionId } = object; const { bucket, key, versionId } = object;
metadataGetObject(bucket, key, versionIdUtils.decode(versionId), log, (err, objMD) => { metadataGetObject(bucket, key, versionIdUtils.decode(versionId), log, (err, objMD) => {

132
yarn.lock
View File

@ -129,6 +129,11 @@
resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz#5981a8db18b56ba38ef0efb7d995b12aa7b51918" resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz#5981a8db18b56ba38ef0efb7d995b12aa7b51918"
integrity sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ== integrity sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==
"@socket.io/component-emitter@~3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553"
integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
"@tootallnate/once@1": "@tootallnate/once@1":
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
@ -139,6 +144,23 @@
resolved "https://registry.yarnpkg.com/@types/async/-/async-3.2.15.tgz#26d4768fdda0e466f18d6c9918ca28cc89a4e1fe" resolved "https://registry.yarnpkg.com/@types/async/-/async-3.2.15.tgz#26d4768fdda0e466f18d6c9918ca28cc89a4e1fe"
integrity sha512-PAmPfzvFA31mRoqZyTVsgJMsvbynR429UTTxhmfsUCrWGh3/fxOrzqBtaTPJsn4UtzTv4Vb0+/O7CARWb69N4g== integrity sha512-PAmPfzvFA31mRoqZyTVsgJMsvbynR429UTTxhmfsUCrWGh3/fxOrzqBtaTPJsn4UtzTv4Vb0+/O7CARWb69N4g==
"@types/cookie@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d"
integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==
"@types/cors@^2.8.12":
version "2.8.13"
resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94"
integrity sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==
dependencies:
"@types/node" "*"
"@types/node@*", "@types/node@>=10.0.0":
version "20.4.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.1.tgz#a6033a8718653c50ac4962977e14d0f984d9527d"
integrity sha512-JIzsAvJeA/5iY6Y/OxZbv1lUcc8dNSE77lb2gnBH+/PJ3lFR1Ccvgwl5JWnHAkNHcRsT0TbpVOsiMKZ1F/yyJg==
"@types/utf8@^3.0.1": "@types/utf8@^3.0.1":
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/utf8/-/utf8-3.0.1.tgz#bf081663d4fff05ee63b41f377a35f8b189f7e5b" resolved "https://registry.yarnpkg.com/@types/utf8/-/utf8-3.0.1.tgz#bf081663d4fff05ee63b41f377a35f8b189f7e5b"
@ -426,9 +448,9 @@ arraybuffer.slice@~0.0.7:
optionalDependencies: optionalDependencies:
ioctl "^2.0.2" ioctl "^2.0.2"
"arsenal@git+https://github.com/scality/arsenal#7.70.4": "arsenal@git+https://github.com/scality/arsenal#f4894a6d6ebb36ba1a559de4811180cb942d55a7":
version "7.70.4" version "7.70.6"
resolved "git+https://github.com/scality/arsenal#c4cc5a2c3dfa4a8d6d565c4029ec05cbb0bf1a3e" resolved "git+https://github.com/scality/arsenal#f4894a6d6ebb36ba1a559de4811180cb942d55a7"
dependencies: dependencies:
"@types/async" "^3.2.12" "@types/async" "^3.2.12"
"@types/utf8" "^3.0.1" "@types/utf8" "^3.0.1"
@ -456,8 +478,8 @@ arraybuffer.slice@~0.0.7:
node-forge "^0.7.1" node-forge "^0.7.1"
prom-client "14.2.0" prom-client "14.2.0"
simple-glob "^0.2" simple-glob "^0.2"
socket.io "~2.3.0" socket.io "~4.6.1"
socket.io-client "~2.3.0" socket.io-client "~4.6.1"
sproxydclient "github:scality/sproxydclient#8.0.4" sproxydclient "github:scality/sproxydclient#8.0.4"
utf8 "2.1.2" utf8 "2.1.2"
uuid "^3.0.1" uuid "^3.0.1"
@ -712,7 +734,7 @@ base64-js@^1.0.2, base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
base64id@2.0.0: base64id@2.0.0, base64id@~2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
@ -1150,6 +1172,11 @@ cookie@0.5.0:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
cookie@~0.4.1:
version "0.4.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
core-js@^2.4.0: core-js@^2.4.0:
version "2.6.12" version "2.6.12"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
@ -1165,6 +1192,14 @@ core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
cors@~2.8.5:
version "2.8.5"
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
dependencies:
object-assign "^4"
vary "^1"
cron-parser@^2.11.0, cron-parser@^2.15.0, cron-parser@^2.18.0: cron-parser@^2.11.0, cron-parser@^2.15.0, cron-parser@^2.18.0:
version "2.18.0" version "2.18.0"
resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.18.0.tgz#de1bb0ad528c815548371993f81a54e5a089edcf" resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.18.0.tgz#de1bb0ad528c815548371993f81a54e5a089edcf"
@ -1228,7 +1263,7 @@ debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.6.8, debug@~2.6.9:
dependencies: dependencies:
ms "2.0.0" ms "2.0.0"
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3: debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3, debug@~4.3.1, debug@~4.3.2:
version "4.3.4" version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -1423,6 +1458,17 @@ engine.io-client@~3.4.0:
xmlhttprequest-ssl "~1.5.4" xmlhttprequest-ssl "~1.5.4"
yeast "0.1.2" yeast "0.1.2"
engine.io-client@~6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.4.0.tgz#88cd3082609ca86d7d3c12f0e746d12db4f47c91"
integrity sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1"
engine.io-parser "~5.0.3"
ws "~8.11.0"
xmlhttprequest-ssl "~2.0.0"
engine.io-parser@~2.2.0: engine.io-parser@~2.2.0:
version "2.2.1" version "2.2.1"
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.1.tgz#57ce5611d9370ee94f99641b589f94c97e4f5da7" resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.1.tgz#57ce5611d9370ee94f99641b589f94c97e4f5da7"
@ -1434,6 +1480,11 @@ engine.io-parser@~2.2.0:
blob "0.0.5" blob "0.0.5"
has-binary2 "~1.0.2" has-binary2 "~1.0.2"
engine.io-parser@~5.0.3:
version "5.0.7"
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.7.tgz#ed5eae76c71f398284c578ab6deafd3ba7e4e4f6"
integrity sha512-P+jDFbvK6lE3n1OL+q9KuzdOFWkkZ/cMV9gol/SbVfpyqfvrfrFTOFJ6fQm2VC3PZHlU3QPhVwmbsCnauHF2MQ==
engine.io@~3.4.0: engine.io@~3.4.0:
version "3.4.2" version "3.4.2"
resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.4.2.tgz#8fc84ee00388e3e228645e0a7d3dfaeed5bd122c" resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.4.2.tgz#8fc84ee00388e3e228645e0a7d3dfaeed5bd122c"
@ -1446,6 +1497,22 @@ engine.io@~3.4.0:
engine.io-parser "~2.2.0" engine.io-parser "~2.2.0"
ws "^7.1.2" ws "^7.1.2"
engine.io@~6.4.2:
version "6.4.2"
resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.4.2.tgz#ffeaf68f69b1364b0286badddf15ff633476473f"
integrity sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==
dependencies:
"@types/cookie" "^0.4.1"
"@types/cors" "^2.8.12"
"@types/node" ">=10.0.0"
accepts "~1.3.4"
base64id "2.0.0"
cookie "~0.4.1"
cors "~2.8.5"
debug "~4.3.1"
engine.io-parser "~5.0.3"
ws "~8.11.0"
entities@~2.1.0: entities@~2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5"
@ -3839,7 +3906,7 @@ oauth-sign@~0.9.0:
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
object-assign@^4.0.1, object-assign@^4.1.0: object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
@ -4585,6 +4652,13 @@ socket.io-adapter@~1.1.0:
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g== integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==
socket.io-adapter@~2.5.2:
version "2.5.2"
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz#5de9477c9182fdc171cd8c8364b9a8894ec75d12"
integrity sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==
dependencies:
ws "~8.11.0"
socket.io-client@2.3.0: socket.io-client@2.3.0:
version "2.3.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4" resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4"
@ -4622,6 +4696,16 @@ socket.io-client@~2.3.0:
socket.io-parser "~3.3.0" socket.io-parser "~3.3.0"
to-array "0.1.4" to-array "0.1.4"
socket.io-client@~4.6.1:
version "4.6.2"
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.6.2.tgz#2bfde952e74625d54e622718a7cb1d591ee62fd6"
integrity sha512-OwWrMbbA8wSqhBAR0yoPK6EdQLERQAYjXb3A0zLpgxfM1ZGLKoxHx8gVmCHA6pcclRX5oA/zvQf7bghAS11jRA==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.2"
engine.io-client "~6.4.0"
socket.io-parser "~4.2.4"
socket.io-parser@~3.3.0: socket.io-parser@~3.3.0:
version "3.3.2" version "3.3.2"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.2.tgz#ef872009d0adcf704f2fbe830191a14752ad50b6" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.2.tgz#ef872009d0adcf704f2fbe830191a14752ad50b6"
@ -4640,6 +4724,14 @@ socket.io-parser@~3.4.0:
debug "~4.1.0" debug "~4.1.0"
isarray "2.0.1" isarray "2.0.1"
socket.io-parser@~4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83"
integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1"
socket.io@~2.3.0: socket.io@~2.3.0:
version "2.3.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.3.0.tgz#cd762ed6a4faeca59bc1f3e243c0969311eb73fb" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.3.0.tgz#cd762ed6a4faeca59bc1f3e243c0969311eb73fb"
@ -4652,6 +4744,18 @@ socket.io@~2.3.0:
socket.io-client "2.3.0" socket.io-client "2.3.0"
socket.io-parser "~3.4.0" socket.io-parser "~3.4.0"
socket.io@~4.6.1:
version "4.6.2"
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.6.2.tgz#d597db077d4df9cbbdfaa7a9ed8ccc3d49439786"
integrity sha512-Vp+lSks5k0dewYTfwgPT9UeGGd+ht7sCpB7p0e83VgO4X/AHYWhXITMrNk/pg8syY2bpx23ptClCQuHhqi2BgQ==
dependencies:
accepts "~1.3.4"
base64id "~2.0.0"
debug "~4.3.2"
engine.io "~6.4.2"
socket.io-adapter "~2.5.2"
socket.io-parser "~4.2.4"
socks-proxy-agent@^6.0.0: socks-proxy-agent@^6.0.0:
version "6.2.1" version "6.2.1"
resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce"
@ -5251,7 +5355,7 @@ validator@^13.0.0, validator@^13.6.0, validator@^13.7.0:
resolved "https://registry.yarnpkg.com/validator/-/validator-13.7.0.tgz#4f9658ba13ba8f3d82ee881d3516489ea85c0857" resolved "https://registry.yarnpkg.com/validator/-/validator-13.7.0.tgz#4f9658ba13ba8f3d82ee881d3516489ea85c0857"
integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw== integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==
vary@~1.1.2: vary@^1, vary@~1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
@ -5414,6 +5518,11 @@ ws@~6.1.0:
dependencies: dependencies:
async-limiter "~1.0.0" async-limiter "~1.0.0"
ws@~8.11.0:
version "8.11.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143"
integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==
xml2js@0.4.19: xml2js@0.4.19:
version "0.4.19" version "0.4.19"
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7"
@ -5457,6 +5566,11 @@ xmlhttprequest-ssl@~1.5.4:
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
integrity sha512-/bFPLUgJrfGUL10AIv4Y7/CUt6so9CLtB/oFxQSHseSDNNCdC6vwwKEqwLN6wNPBg9YWXAiMu8jkf6RPRS/75Q== integrity sha512-/bFPLUgJrfGUL10AIv4Y7/CUt6so9CLtB/oFxQSHseSDNNCdC6vwwKEqwLN6wNPBg9YWXAiMu8jkf6RPRS/75Q==
xmlhttprequest-ssl@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67"
integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==
xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.0: xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.0:
version "4.0.2" version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"