Skip to content

Commit cdad405

Browse files
committed
CLDSRV-872: test checksums are respected in backbeat routes
1 parent b58aab6 commit cdad405

File tree

2 files changed

+117
-1
lines changed

2 files changed

+117
-1
lines changed

lib/routes/routeBackbeat.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,14 @@ function putData(request, response, bucketInfo, objMd, log, callback) {
447447
}
448448
return dataStore(
449449
context, cipherBundle, request, payloadLen, {},
450-
backendInfo, log, (err, retrievalInfo, md5) => {
450+
backendInfo, log,
451+
// The callback's 4th arg (checksum) is intentionally ignored: any
452+
// x-amz-checksum-* header sent by Backbeat is already validated
453+
// inside dataStore by ChecksumTransform. The computed value is not
454+
// stored here because this is a data-only write — metadata is
455+
// written separately by Backbeat, which should propagate the source
456+
// object's checksum.
457+
(err, retrievalInfo, md5) => {
451458
if (err) {
452459
log.error('error putting data', {
453460
error: err,
@@ -853,6 +860,12 @@ function putObject(request, response, log, callback) {
853860
const payloadLen = parseInt(request.headers['content-length'], 10);
854861
const backendInfo = new BackendInfo(config, storageLocation);
855862
return dataStore(context, CIPHER, request, payloadLen, {}, backendInfo, log,
863+
// The callback's 4th arg (checksum) is intentionally ignored: any
864+
// x-amz-checksum-* header sent by Backbeat is already validated inside
865+
// dataStore by ChecksumTransform. The computed value is not stored here
866+
// because this is a data-only write to an external backend — metadata
867+
// is managed separately by Backbeat, which should propagate the source
868+
// object's checksum.
856869
(err, retrievalInfo, md5) => {
857870
if (err) {
858871
log.error('error putting data', {

tests/multipleBackend/routes/routeBackbeat.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3642,4 +3642,107 @@ describe('backbeat routes', () => {
36423642
], done);
36433643
});
36443644
});
3645+
3646+
describe('checksum validation', () => {
3647+
const testDataSha256B64 = crypto.createHash('sha256')
3648+
.update(testData, 'utf-8').digest('base64');
3649+
// A valid-length but wrong sha256 digest (44 base64 chars).
3650+
const wrongSha256B64 = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=';
3651+
3652+
describe('putData', () => {
3653+
it('should return 400 BadDigest when x-amz-checksum-sha256 does not match body', done => {
3654+
makeBackbeatRequest({
3655+
method: 'PUT',
3656+
resourceType: 'data',
3657+
bucket: TEST_BUCKET,
3658+
objectKey: TEST_KEY,
3659+
headers: {
3660+
'x-scal-canonical-id': testMd['owner-id'],
3661+
'content-md5': testDataMd5,
3662+
'content-length': testData.length,
3663+
'x-amz-checksum-sha256': wrongSha256B64,
3664+
},
3665+
requestBody: testData,
3666+
authCredentials: backbeatAuthCredentials,
3667+
}, err => {
3668+
assert(err, 'expected an error response');
3669+
assert.strictEqual(err.statusCode, 400);
3670+
assert.strictEqual(err.code, 'BadDigest');
3671+
done();
3672+
});
3673+
});
3674+
3675+
it('should return 200 when x-amz-checksum-sha256 matches body', done => {
3676+
makeBackbeatRequest({
3677+
method: 'PUT',
3678+
resourceType: 'data',
3679+
bucket: TEST_BUCKET,
3680+
objectKey: TEST_KEY,
3681+
headers: {
3682+
'x-scal-canonical-id': testMd['owner-id'],
3683+
'content-md5': testDataMd5,
3684+
'content-length': testData.length,
3685+
'x-amz-checksum-sha256': testDataSha256B64,
3686+
},
3687+
requestBody: testData,
3688+
authCredentials: backbeatAuthCredentials,
3689+
}, (err, data) => {
3690+
assert.ifError(err);
3691+
assert.strictEqual(data.statusCode, 200);
3692+
done();
3693+
});
3694+
});
3695+
});
3696+
3697+
describe('putObject (multiplebackenddata)', () => {
3698+
itIfLocationAws('should return 400 BadDigest when x-amz-checksum-sha256 does not match body', done => {
3699+
makeBackbeatRequest({
3700+
method: 'PUT',
3701+
resourceType: 'multiplebackenddata',
3702+
bucket: TEST_BUCKET,
3703+
objectKey: TEST_KEY,
3704+
queryObj: { operation: 'putobject' },
3705+
headers: {
3706+
'x-scal-canonical-id': testMd['owner-id'],
3707+
'x-scal-storage-type': 'aws_s3',
3708+
'x-scal-storage-class': awsLocation,
3709+
'content-md5': testDataMd5,
3710+
'content-length': testData.length,
3711+
'x-amz-checksum-sha256': wrongSha256B64,
3712+
},
3713+
requestBody: testData,
3714+
authCredentials: backbeatAuthCredentials,
3715+
}, err => {
3716+
assert(err, 'expected an error response');
3717+
assert.strictEqual(err.statusCode, 400);
3718+
assert.strictEqual(err.code, 'BadDigest');
3719+
done();
3720+
});
3721+
});
3722+
3723+
itIfLocationAws('should return 200 when x-amz-checksum-sha256 matches body', done => {
3724+
makeBackbeatRequest({
3725+
method: 'PUT',
3726+
resourceType: 'multiplebackenddata',
3727+
bucket: TEST_BUCKET,
3728+
objectKey: TEST_KEY,
3729+
queryObj: { operation: 'putobject' },
3730+
headers: {
3731+
'x-scal-canonical-id': testMd['owner-id'],
3732+
'x-scal-storage-type': 'aws_s3',
3733+
'x-scal-storage-class': awsLocation,
3734+
'content-md5': testDataMd5,
3735+
'content-length': testData.length,
3736+
'x-amz-checksum-sha256': testDataSha256B64,
3737+
},
3738+
requestBody: testData,
3739+
authCredentials: backbeatAuthCredentials,
3740+
}, (err, data) => {
3741+
assert.ifError(err);
3742+
assert.strictEqual(data.statusCode, 200);
3743+
done();
3744+
});
3745+
});
3746+
});
3747+
});
36453748
});

0 commit comments

Comments
 (0)