Skip to content

Commit 7335f5f

Browse files
committed
Merge branch 'improvement/CLDSRV-741-putversionretention' into tmp/octopus/w/9.1/improvement/CLDSRV-741-putversionretention
2 parents 2cf326d + 6087310 commit 7335f5f

File tree

3 files changed

+270
-1
lines changed

3 files changed

+270
-1
lines changed

tests/functional/aws-node-sdk/lib/utility/bucket-util.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class BucketUtility {
8282
* @returns {Promise.<T>}
8383
*/
8484

85-
empty(bucketName) {
85+
empty(bucketName, BypassGovernanceRetention = false) {
8686
const param = {
8787
Bucket: bucketName,
8888
};
@@ -99,6 +99,7 @@ class BucketUtility {
9999
Bucket: bucketName,
100100
Key: object.Key,
101101
VersionId: object.VersionId,
102+
...(BypassGovernanceRetention && { BypassGovernanceRetention }),
102103
}).promise()
103104
.then(() => object)
104105
)
@@ -110,6 +111,7 @@ class BucketUtility {
110111
Bucket: bucketName,
111112
Key: object.Key,
112113
VersionId: object.VersionId,
114+
...(BypassGovernanceRetention && { BypassGovernanceRetention }),
113115
}).promise()
114116
.then(() => object)
115117
)
@@ -120,6 +122,7 @@ class BucketUtility {
120122
Bucket: bucketName,
121123
Key: object.Key,
122124
VersionId: object.VersionId,
125+
...(BypassGovernanceRetention && { BypassGovernanceRetention }),
123126
}).promise()
124127
.then(() => object)))
125128
)

tests/functional/aws-node-sdk/test/object/putObjectLegalHold.js

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
const assert = require('assert');
2+
const AWS = require('aws-sdk');
3+
const { errorInstances } = require('arsenal');
24

35
const withV4 = require('../support/withV4');
46
const BucketUtility = require('../../lib/utility/bucket-util');
57
const checkError = require('../../lib/utility/checkError');
68
const changeObjectLock = require('../../../../utilities/objectLock-util');
9+
const { VALIDATE_CREDENTIALS, SIGN } = AWS.EventListeners.Core;
710

811
const bucket = 'mock-bucket-lock';
912
const unlockedBucket = 'mock-bucket-no-lock';
@@ -190,3 +193,142 @@ describeSkipIfCeph('PUT object legal hold', () => {
190193
});
191194
});
192195
});
196+
197+
// Use bucket policy to test iam action for putObjectLegalHold with version id
198+
// It used to need non standard s3:PutObjectVersionLegalHold action but was fixed
199+
// by ARSN-297 ARTESCA-7107
200+
describeSkipIfCeph('PUT object legal hold iam action and version id', () => {
201+
withV4(sigCfg => {
202+
const bucketUtil = new BucketUtility('default', sigCfg);
203+
const s3 = bucketUtil.s3;
204+
const testBucket = 'bucket-policy-legalhold-test';
205+
let versionId;
206+
207+
const legalHoldConfig = { Status: 'ON' };
208+
209+
function awsRequest(auth, operation, params, callback) {
210+
if (auth) {
211+
bucketUtil.s3[operation](params, callback);
212+
} else {
213+
const unauthBucketUtil = new BucketUtility('default', sigCfg);
214+
const request = unauthBucketUtil.s3[operation](params);
215+
request.removeListener('validate', VALIDATE_CREDENTIALS);
216+
request.removeListener('sign', SIGN);
217+
request.send(callback);
218+
}
219+
}
220+
221+
function cbNoError(done) {
222+
return err => {
223+
assert.ifError(err);
224+
done();
225+
};
226+
}
227+
228+
function cbWithError(done) {
229+
return err => {
230+
assert.strictEqual(err.statusCode, errorInstances.AccessDenied.code);
231+
done();
232+
};
233+
}
234+
235+
beforeEach(() => {
236+
process.stdout.write('Setting up bucket policy legal hold tests\n');
237+
return s3.createBucket({
238+
Bucket: testBucket,
239+
ObjectLockEnabledForBucket: true,
240+
}).promise()
241+
.then(() => s3.putObject({ Bucket: testBucket, Key: key }).promise())
242+
.then(res => {
243+
versionId = res.VersionId;
244+
})
245+
.catch(err => {
246+
process.stdout.write('Error in beforeEach\n');
247+
throw err;
248+
});
249+
});
250+
251+
afterEach(() => {
252+
process.stdout.write('Cleaning up bucket policy legal hold tests\n');
253+
return bucketUtil.empty(testBucket)
254+
.then(() => bucketUtil.deleteMany([testBucket]))
255+
.catch(err => {
256+
process.stdout.write('Error in afterEach\n');
257+
throw err;
258+
});
259+
});
260+
261+
const policyTestCases = [
262+
{
263+
action: 's3:PutObjectLegalHold',
264+
expectedResult: 'allow',
265+
callback: cbNoError,
266+
},
267+
{
268+
action: 's3:PutObjectVersionLegalHold',
269+
expectedResult: 'deny',
270+
callback: cbWithError,
271+
},
272+
];
273+
274+
policyTestCases.forEach(testCase => {
275+
describe(`with ${testCase.action} policy`, () => {
276+
beforeEach(done => {
277+
const statement = {
278+
Sid: 'AllowLegalHold',
279+
Effect: 'Allow',
280+
Principal: '*',
281+
Action: [testCase.action],
282+
Resource: [`arn:aws:s3:::${testBucket}/*`],
283+
};
284+
const bucketPolicy = {
285+
Version: '2012-10-17',
286+
Statement: [statement],
287+
};
288+
s3.putBucketPolicy({
289+
Bucket: testBucket,
290+
Policy: JSON.stringify(bucketPolicy),
291+
}, err => {
292+
assert.ifError(err);
293+
done();
294+
});
295+
});
296+
297+
if (testCase.expectedResult === 'allow') {
298+
afterEach(() =>
299+
s3.putObjectLegalHold({
300+
Bucket: testBucket,
301+
Key: key,
302+
LegalHold: { Status: 'OFF' },
303+
}).promise()
304+
.then(() => s3.putObjectLegalHold({
305+
Bucket: testBucket,
306+
Key: key,
307+
VersionId: versionId,
308+
LegalHold: { Status: 'OFF' },
309+
}).promise())
310+
);
311+
}
312+
313+
it(`should ${testCase.expectedResult} unauthenticated putObjectLegalHold without VersionId`, done => {
314+
const params = {
315+
Bucket: testBucket,
316+
Key: key,
317+
LegalHold: legalHoldConfig,
318+
};
319+
awsRequest(false, 'putObjectLegalHold', params, testCase.callback(done));
320+
});
321+
322+
it(`should ${testCase.expectedResult} unauthenticated putObjectLegalHold with VersionId`, done => {
323+
const params = {
324+
Bucket: testBucket,
325+
Key: key,
326+
LegalHold: legalHoldConfig,
327+
VersionId: versionId,
328+
};
329+
awsRequest(false, 'putObjectLegalHold', params, testCase.callback(done));
330+
});
331+
});
332+
});
333+
});
334+
});

tests/functional/aws-node-sdk/test/object/putRetention.js

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
const assert = require('assert');
22
const moment = require('moment');
3+
const AWS = require('aws-sdk');
4+
const { errorInstances } = require('arsenal');
35

46
const withV4 = require('../support/withV4');
57
const BucketUtility = require('../../lib/utility/bucket-util');
68
const checkError = require('../../lib/utility/checkError');
79
const changeObjectLock = require('../../../../utilities/objectLock-util');
10+
const { VALIDATE_CREDENTIALS, SIGN } = AWS.EventListeners.Core;
811

912
const bucketName = 'lockenabledputbucket';
1013
const unlockedBucket = 'locknotenabledputbucket';
@@ -144,3 +147,124 @@ describeSkipIfCeph('PUT object retention', () => {
144147
});
145148
});
146149
});
150+
151+
// Use bucket policy to test iam action for putObjectRetention with version id
152+
// It used to need non standard s3:PutObjectVersionRetention action but was fixed
153+
// by ARSN-297 ARTESCA-7107
154+
describeSkipIfCeph('PUT object retention iam action and version id', () => {
155+
withV4(sigCfg => {
156+
const bucketUtil = new BucketUtility('default', sigCfg);
157+
const s3 = bucketUtil.s3;
158+
const testBucket = 'bucket-policy-retention-test';
159+
let versionId;
160+
161+
function awsRequest(auth, operation, params, callback) {
162+
if (auth) {
163+
bucketUtil.s3[operation](params, callback);
164+
} else {
165+
const unauthBucketUtil = new BucketUtility('default', sigCfg);
166+
const request = unauthBucketUtil.s3[operation](params);
167+
request.removeListener('validate', VALIDATE_CREDENTIALS);
168+
request.removeListener('sign', SIGN);
169+
request.send(callback);
170+
}
171+
}
172+
173+
function cbNoError(done) {
174+
return err => {
175+
assert.ifError(err);
176+
done();
177+
};
178+
}
179+
180+
function cbWithError(done) {
181+
return err => {
182+
assert.strictEqual(err.statusCode, errorInstances.AccessDenied.code);
183+
done();
184+
};
185+
}
186+
187+
beforeEach(() => {
188+
process.stdout.write('Setting up bucket policy retention tests\n');
189+
return s3.createBucket({
190+
Bucket: testBucket,
191+
ObjectLockEnabledForBucket: true,
192+
}).promise()
193+
.then(() => s3.putObject({ Bucket: testBucket, Key: objectName }).promise())
194+
.then(res => {
195+
versionId = res.VersionId;
196+
})
197+
.catch(err => {
198+
process.stdout.write('Error in beforeEach\n');
199+
throw err;
200+
});
201+
});
202+
203+
afterEach(() => {
204+
process.stdout.write('Cleaning up bucket policy retention tests\n');
205+
return bucketUtil.empty(testBucket, true)
206+
.then(() => bucketUtil.deleteMany([testBucket]))
207+
.catch(err => {
208+
process.stdout.write('Error in afterEach\n');
209+
throw err;
210+
});
211+
});
212+
213+
const policyTestCases = [
214+
{
215+
action: 's3:PutObjectRetention',
216+
expectedResult: 'allow',
217+
callback: cbNoError,
218+
},
219+
{
220+
action: 's3:PutObjectVersionRetention',
221+
expectedResult: 'deny',
222+
callback: cbWithError,
223+
},
224+
];
225+
226+
policyTestCases.forEach(testCase => {
227+
describe(`with ${testCase.action} policy`, () => {
228+
beforeEach(done => {
229+
const statement = {
230+
Sid: 'AllowRetention',
231+
Effect: 'Allow',
232+
Principal: '*',
233+
Action: [testCase.action],
234+
Resource: [`arn:aws:s3:::${testBucket}/*`],
235+
};
236+
const bucketPolicy = {
237+
Version: '2012-10-17',
238+
Statement: [statement],
239+
};
240+
s3.putBucketPolicy({
241+
Bucket: testBucket,
242+
Policy: JSON.stringify(bucketPolicy),
243+
}, err => {
244+
assert.ifError(err);
245+
done();
246+
});
247+
});
248+
249+
it(`should ${testCase.expectedResult} unauthenticated putObjectRetention without VersionId`, done => {
250+
const params = {
251+
Bucket: testBucket,
252+
Key: objectName,
253+
Retention: retentionConfig,
254+
};
255+
awsRequest(false, 'putObjectRetention', params, testCase.callback(done));
256+
});
257+
258+
it(`should ${testCase.expectedResult} unauthenticated putObjectRetention with VersionId`, done => {
259+
const params = {
260+
Bucket: testBucket,
261+
Key: objectName,
262+
Retention: retentionConfig,
263+
VersionId: versionId,
264+
};
265+
awsRequest(false, 'putObjectRetention', params, testCase.callback(done));
266+
});
267+
});
268+
});
269+
});
270+
});

0 commit comments

Comments
 (0)