From 760ab8947810fca7d1f1e252cffdfa6478197238 Mon Sep 17 00:00:00 2001 From: Maha Benzekri Date: Wed, 29 Jul 2026 18:27:54 +0200 Subject: [PATCH 1/5] Send signatureVersion and authType unswapped to Vault checkPolicies multiObjectDelete assigned authType to signatureVersion and vice versa when building the checkPolicies request context, so Vault validated and evaluated each field against the wrong value. Issue: CLDSRV-963 --- lib/api/multiObjectDelete.js | 4 +- tests/unit/api/multiObjectDelete.js | 59 ++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/lib/api/multiObjectDelete.js b/lib/api/multiObjectDelete.js index e62e6b756e..4db9b4f4d7 100644 --- a/lib/api/multiObjectDelete.js +++ b/lib/api/multiObjectDelete.js @@ -549,8 +549,8 @@ function multiObjectDelete(authInfo, request, log, callback) { awsService: 's3', locationConstraint: null, 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, }, parameterize: { diff --git a/tests/unit/api/multiObjectDelete.js b/tests/unit/api/multiObjectDelete.js index b3d71d03ec..d1fcd3ba7f 100644 --- a/tests/unit/api/multiObjectDelete.js +++ b/tests/unit/api/multiObjectDelete.js @@ -1,6 +1,6 @@ const crypto = require('crypto'); const assert = require('assert'); -const { errors, storage } = require('arsenal'); +const { auth, errors, storage } = require('arsenal'); const { decodeObjectVersion, getObjMetadataAndDelete, initializeMultiObjectDeleteWithBatchingSupport } = require('../../../lib/api/multiObjectDelete'); @@ -28,6 +28,7 @@ const objectKey1 = 'objectName1'; const objectKey2 = 'objectName2'; const metadataUtils = require('../../../lib/metadata/metadataUtils'); const services = require('../../../lib/services'); +const vault = require('../../../lib/auth/vault'); const { BucketInfo } = require('arsenal/build/lib/models'); const testBucketPutRequest = new DummyRequest({ bucketName, @@ -456,3 +457,59 @@ describe('multiObjectDelete function', () => { }); }); }); + +describe('multiObjectDelete checkPolicies request context', () => { + afterEach(() => { + sinon.restore(); + }); + + it('should forward auth params unswapped to vault, including a zero signatureAge', done => { + const post = 'objectname'; + const request = new DummyRequest({ + bucketName: 'bucketname', + objectKey: 'objectname', + parsedHost: 'localhost', + headers: { + 'content-md5': crypto.createHash('md5').update(post, 'utf8').digest('base64'), + }, + post, + socket: { + remoteAddress: '127.0.0.1', + }, + url: '/bucketname', + }); + // IAM user so that the request goes through the checkPolicies path + const userAuthInfo = makeAuthInfo('accessKey1', 'testuser'); + + sinon.stub(metadataWrapper, 'getBucket').callsFake((bucketName, log, cb) => + cb(null, new BucketInfo( + 'bucketname', + userAuthInfo.getCanonicalID(), + 'accountA', + new Date().toISOString(), + 15, + ), undefined)); + sinon.stub(auth.server, 'extractParams').returns({ + params: { + version: 4, + data: { + signatureVersion: 'AWS4-HMAC-SHA256', + authType: 'REST-HEADER', + signatureAge: 0, + }, + }, + }); + const checkPoliciesStub = sinon.stub(vault, 'checkPolicies') + .callsFake((requestContextParams, arn, log, cb) => cb(errors.AccessDenied)); + + multiObjectDelete.multiObjectDelete(userAuthInfo, request, log, err => { + assert.strictEqual(err, null); + sinon.assert.calledOnce(checkPoliciesStub); + const { constantParams } = checkPoliciesStub.getCall(0).args[0]; + assert.strictEqual(constantParams.signatureVersion, 'AWS4-HMAC-SHA256'); + assert.strictEqual(constantParams.authType, 'REST-HEADER'); + assert.strictEqual(constantParams.signatureAge, 0); + done(); + }); + }); +}); From ea42afc5561901723cf52ab04fc45f6dc27e5fd5 Mon Sep 17 00:00:00 2001 From: Maha Benzekri Date: Wed, 29 Jul 2026 18:28:11 +0200 Subject: [PATCH 2/5] Bump project version Issue: CLDSRV-963 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 33561b70b2..4372f1dcfc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zenko/cloudserver", - "version": "9.1.14", + "version": "9.1.15", "description": "Zenko CloudServer, an open-source Node.js implementation of a server handling the Amazon S3 protocol", "main": "index.js", "engines": { From 9b02cb46a488c3982ff18e0f5ba26113f721bb90 Mon Sep 17 00:00:00 2001 From: Maha Benzekri Date: Wed, 5 Aug 2026 10:52:12 +0200 Subject: [PATCH 3/5] Send signatureVersion and authType unswapped in bucketPut checkPolicies Issue: CLDSRV-963 --- lib/api/bucketPut.js | 4 ++-- tests/unit/api/bucketPut.js | 42 ++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/lib/api/bucketPut.js b/lib/api/bucketPut.js index 5f3409da04..5bc7019bcc 100644 --- a/lib/api/bucketPut.js +++ b/lib/api/bucketPut.js @@ -126,8 +126,8 @@ function _buildConstantParams({ 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, diff --git a/tests/unit/api/bucketPut.js b/tests/unit/api/bucketPut.js index 529f2947cb..2ed309251c 100644 --- a/tests/unit/api/bucketPut.js +++ b/tests/unit/api/bucketPut.js @@ -1,5 +1,5 @@ const assert = require('assert'); -const { errors } = require('arsenal'); +const { auth, errors } = require('arsenal'); const sinon = require('sinon'); const inMemory = require('../../../lib/kms/in_memory/backend').backend; const vault = require('../../../lib/auth/vault'); @@ -934,3 +934,43 @@ describe('bucketPut API with SSE Configurations', () => { }); }); }); + +describe('bucketPut checkPolicies request context', () => { + afterEach(() => { + sinon.restore(); + cleanup(); + }); + + it('should forward auth params unswapped to vault, including a zero signatureAge', done => { + // IAM user so that the request goes through the checkPolicies path + const userAuthInfo = makeAuthInfo(accessKey, 'testuser'); + sinon.stub(auth.server, 'extractParams').returns({ + params: { + version: 4, + data: { + signatureVersion: 'AWS4-HMAC-SHA256', + authType: 'REST-HEADER', + signatureAge: 0, + }, + }, + }); + const checkPoliciesStub = sinon.stub(vault, 'checkPolicies') + .callsFake((requestContextParams, arn, log, cb) => cb(errors.AccessDenied)); + const request = { + ...testRequest, + socket: { + remoteAddress: '127.0.0.1', + }, + }; + + bucketPut(userAuthInfo, request, log, err => { + assert(err && err.AccessDenied); + sinon.assert.calledOnce(checkPoliciesStub); + const { constantParams } = checkPoliciesStub.getCall(0).args[0][0]; + assert.strictEqual(constantParams.signatureVersion, 'AWS4-HMAC-SHA256'); + assert.strictEqual(constantParams.authType, 'REST-HEADER'); + assert.strictEqual(constantParams.signatureAge, 0); + done(); + }); + }); +}); From 5564b2c9863b793c8a2945d69ab916f2b65f4533 Mon Sep 17 00:00:00 2001 From: Maha Benzekri Date: Wed, 5 Aug 2026 12:29:48 +0200 Subject: [PATCH 4/5] Assert the exact error in the bucketPut checkPolicies test Issue: CLDSRV-963 --- tests/unit/api/bucketPut.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/api/bucketPut.js b/tests/unit/api/bucketPut.js index 2ed309251c..3b0ba3a51c 100644 --- a/tests/unit/api/bucketPut.js +++ b/tests/unit/api/bucketPut.js @@ -964,7 +964,7 @@ describe('bucketPut checkPolicies request context', () => { }; bucketPut(userAuthInfo, request, log, err => { - assert(err && err.AccessDenied); + assert.strictEqual(err.is.AccessDenied, true); sinon.assert.calledOnce(checkPoliciesStub); const { constantParams } = checkPoliciesStub.getCall(0).args[0][0]; assert.strictEqual(constantParams.signatureVersion, 'AWS4-HMAC-SHA256'); From 0f2f742233b973d03ed0bb81f456427c5109282f Mon Sep 17 00:00:00 2001 From: Maha Benzekri Date: Wed, 5 Aug 2026 17:10:59 +0200 Subject: [PATCH 5/5] Report the received error in the bucketPut checkPolicies test assertion Issue: CLDSRV-963 --- tests/unit/api/bucketPut.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/api/bucketPut.js b/tests/unit/api/bucketPut.js index 3b0ba3a51c..d9e3344905 100644 --- a/tests/unit/api/bucketPut.js +++ b/tests/unit/api/bucketPut.js @@ -964,7 +964,7 @@ describe('bucketPut checkPolicies request context', () => { }; bucketPut(userAuthInfo, request, log, err => { - assert.strictEqual(err.is.AccessDenied, true); + assert.strictEqual(err.is.AccessDenied, true, `expected AccessDenied, got ${err && err.message}`); sinon.assert.calledOnce(checkPoliciesStub); const { constantParams } = checkPoliciesStub.getCall(0).args[0][0]; assert.strictEqual(constantParams.signatureVersion, 'AWS4-HMAC-SHA256');