Skip to content

Commit 36120ba

Browse files
committed
CLDSRV-729: don't require content-md5 header in put-bucket-cors and delete-objects
1 parent 091fd27 commit 36120ba

4 files changed

Lines changed: 121 additions & 14 deletions

File tree

lib/api/bucketPutCors.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@ function bucketPutCors(authInfo, request, log, callback) {
3333
return callback(errors.MissingRequestBodyError);
3434
}
3535

36-
const md5 = crypto.createHash('md5')
37-
.update(request.post, 'utf8').digest('base64');
38-
if (md5 !== request.headers['content-md5']) {
39-
log.debug('bad md5 digest', { error: errors.BadDigest });
40-
monitoring.promMetrics('PUT', bucketName, 400, 'putBucketCors');
41-
return callback(errors.BadDigest);
36+
if (request.headers['content-md5']) {
37+
const md5 = crypto.createHash('md5')
38+
.update(request.post, 'utf8').digest('base64');
39+
if (md5 !== request.headers['content-md5']) {
40+
log.debug('bad md5 digest', { error: errors.BadDigest });
41+
monitoring.promMetrics('PUT', bucketName, 400, 'putBucketCors');
42+
return callback(errors.BadDigest);
43+
}
4244
}
4345

4446
if (parseInt(request.headers['content-length'], 10) > 65536) {

lib/api/multiObjectDelete.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -474,12 +474,15 @@ function multiObjectDelete(authInfo, request, log, callback) {
474474
'multiObjectDelete');
475475
return callback(errors.MissingRequestBodyError);
476476
}
477-
const md5 = crypto.createHash('md5')
478-
.update(request.post, 'utf8').digest('base64');
479-
if (md5 !== request.headers['content-md5']) {
480-
monitoring.promMetrics('DELETE', request.bucketName, 400,
481-
'multiObjectDelete');
482-
return callback(errors.BadDigest);
477+
478+
if (request.headers['content-md5']) {
479+
const md5 = crypto.createHash('md5')
480+
.update(request.post, 'utf8').digest('base64');
481+
if (md5 !== request.headers['content-md5']) {
482+
monitoring.promMetrics('DELETE', request.bucketName, 400,
483+
'multiObjectDelete');
484+
return callback(errors.BadDigest);
485+
}
483486
}
484487

485488
const inPlayInternal = [];

tests/unit/api/bucketPutCors.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ describe('putBucketCORS API', () => {
5555
.createBucketCorsRequest('PUT', bucketName);
5656
bucketPutCors(authInfo, testBucketPutCorsRequest, log, err => {
5757
if (err) {
58-
process.stdout.write(`Err putting website config ${err}`);
58+
process.stdout.write(`Err putting bucket cors ${err}`);
5959
return done(err);
6060
}
6161
return metadata.getBucket(bucketName, log, (err, bucket) => {
@@ -70,11 +70,33 @@ describe('putBucketCORS API', () => {
7070
});
7171
});
7272

73-
it('should return BadDigest if md5 is omitted', done => {
73+
it('should accept request if md5 is omitted', done => {
7474
const corsUtil = new CorsConfigTester();
7575
const testBucketPutCorsRequest = corsUtil
7676
.createBucketCorsRequest('PUT', bucketName);
7777
testBucketPutCorsRequest.headers['content-md5'] = undefined;
78+
bucketPutCors(authInfo, testBucketPutCorsRequest, log, err => {
79+
if (err) {
80+
process.stdout.write(`Err putting bucket cors ${err}`);
81+
return done(err);
82+
}
83+
return metadata.getBucket(bucketName, log, (err, bucket) => {
84+
if (err) {
85+
process.stdout.write(`Err retrieving bucket MD ${err}`);
86+
return done(err);
87+
}
88+
const uploadedCors = bucket.getCors();
89+
assert.deepStrictEqual(uploadedCors, corsUtil.getCors());
90+
return done();
91+
});
92+
});
93+
});
94+
95+
it('should reject request if md5 is mismatch', done => {
96+
const corsUtil = new CorsConfigTester();
97+
const testBucketPutCorsRequest = corsUtil
98+
.createBucketCorsRequest('PUT', bucketName);
99+
testBucketPutCorsRequest.headers['content-md5'] = 'wrong md5';
78100
_testPutBucketCors(authInfo, testBucketPutCorsRequest,
79101
log, 'BadDigest', done);
80102
});

tests/unit/api/multiObjectDelete.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,4 +412,84 @@ describe('multiObjectDelete function', () => {
412412
done();
413413
});
414414
});
415+
416+
it('should accept request when content-md5 header is missing', done => {
417+
const post = '<Delete><Object><Key>objectname</Key></Object></Delete>';
418+
const testObjectKey = 'objectname';
419+
const testBucketName = 'test-bucket';
420+
421+
const request = new DummyRequest({
422+
bucketName: testBucketName,
423+
objectKey: testObjectKey,
424+
parsedHost: 'localhost',
425+
headers: {
426+
// No content-md5 header
427+
},
428+
post,
429+
socket: {
430+
remoteAddress: '127.0.0.1',
431+
},
432+
url: `/${testBucketName}`,
433+
});
434+
435+
// Use the same canonicalID for both authInfo and bucket owner to avoid AccessDenied
436+
const testAuthInfo = makeAuthInfo(canonicalID);
437+
438+
// Create bucket with proper ownership
439+
const testBucketRequest = new DummyRequest({
440+
bucketName: testBucketName,
441+
namespace,
442+
headers: {},
443+
url: `/${testBucketName}`,
444+
});
445+
446+
// Create object to delete
447+
const testObjectRequest = new DummyRequest({
448+
bucketName: testBucketName,
449+
namespace,
450+
objectKey: testObjectKey,
451+
headers: {},
452+
url: `/${testBucketName}/${testObjectKey}`,
453+
}, postBody);
454+
455+
bucketPut(testAuthInfo, testBucketRequest, log, () => {
456+
objectPut(testAuthInfo, testObjectRequest, undefined, log, () => {
457+
multiObjectDelete.multiObjectDelete(testAuthInfo, request, log, (err, res) => {
458+
// Request should succeed even without content-md5 header
459+
assert.strictEqual(err, null);
460+
assert.strictEqual(typeof res, 'string');
461+
// Should contain successful deletion response
462+
assert.strictEqual(res.includes('<Deleted><Key>objectname</Key></Deleted>'), true);
463+
done();
464+
});
465+
});
466+
});
467+
});
468+
469+
it('should reject request with BadDigest error when content-md5 header mismatches', done => {
470+
const post = '<Delete><Object><Key>objectname</Key></Object></Delete>';
471+
const incorrectMd5 = 'incorrectMd5Hash';
472+
473+
const request = new DummyRequest({
474+
bucketName: 'bucketname',
475+
objectKey: 'objectname',
476+
parsedHost: 'localhost',
477+
headers: {
478+
'content-md5': incorrectMd5
479+
},
480+
post,
481+
socket: {
482+
remoteAddress: '127.0.0.1',
483+
},
484+
url: '/bucketname',
485+
});
486+
const authInfo = makeAuthInfo('123456');
487+
488+
multiObjectDelete.multiObjectDelete(authInfo, request, log, (err, res) => {
489+
// Should return BadDigest error for mismatched content-md5
490+
assert.strictEqual(err.is.BadDigest, true);
491+
assert.strictEqual(res, undefined);
492+
done();
493+
});
494+
});
415495
});

0 commit comments

Comments
 (0)