Skip to content

Commit a7435d9

Browse files
Added fixes and some test fixes
Signed-off-by: Aayush Chouhan <[email protected]>
1 parent 349d827 commit a7435d9

File tree

5 files changed

+40
-128
lines changed

5 files changed

+40
-128
lines changed

src/sdk/bucketspace_fs.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,12 @@ class BucketSpaceFS extends BucketSpaceSimpleFS {
274274

275275
if (!this.has_list_bucket_permission(bucket, account)) return;
276276

277-
const fs_accessible = await this.validate_fs_bucket_access(bucket, object_sdk);
278-
if (!fs_accessible) return;
277+
// only for nsfs buckets, also check filesystem access
278+
const is_nsfs_bucket = object_sdk.is_nsfs_bucket(bucket.namespace);
279+
if (is_nsfs_bucket) {
280+
const fs_accessible = await this._has_access_to_nsfs_dir(bucket.namespace, object_sdk);
281+
if (!fs_accessible) return;
282+
}
279283
return bucket;
280284
});
281285
return { buckets: buckets.filter(bucket => bucket) };
@@ -942,7 +946,7 @@ class BucketSpaceFS extends BucketSpaceSimpleFS {
942946

943947
/**
944948
* has_list_bucket_permission returns true if the account can list the bucket in ListBuckets operation
945-
* this is a synchronous function that only checks system ownership and bucket ownership
949+
* only checks bucket ownership (aws-compliant: bucket policies don't affect ListBuckets)
946950
*
947951
* @param {Record<string, any>} bucket
948952
* @param {Record<string, any>} account
@@ -952,7 +956,7 @@ class BucketSpaceFS extends BucketSpaceSimpleFS {
952956
// bucket owner can list their buckets only
953957
if (this.is_bucket_owner(bucket, account)) return true;
954958

955-
// TODO: Add IAM policy support for s3:ListAllMyBuckets action
959+
// TODO: Add IAM policy support for user's s3:ListAllMyBuckets action
956960

957961
return false;
958962
}

src/server/common_services/auth_server.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ function has_list_bucket_permission(bucket, account, system) {
564564
// bucket owner can list their buckets only
565565
if (is_bucket_owner(bucket, account)) return true;
566566

567-
// TODO: Add IAM policy support for s3:ListAllMyBuckets action
567+
// TODO: Add IAM policy support for user's s3:ListAllMyBuckets action
568568

569569
return false;
570570
}

src/test/integration_tests/api/sts/test_sts.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ function verify_session_token(session_token, access_key, secret_key, assumed_rol
457457
mocha.describe('Session token tests', function() {
458458
const { rpc_client } = coretest;
459459
const alice2 = 'alice2';
460+
const alice2_buck = 'alice2-test-bucket';
460461
const bob2 = 'bob2';
461462
const charlie2 = 'charlie2';
462463
const accounts = [{ email: alice2 }, { email: bob2 }, { email: charlie2 }];
@@ -466,6 +467,8 @@ mocha.describe('Session token tests', function() {
466467
mocha.after(async function() {
467468
const self = this; // eslint-disable-line no-invalid-this
468469
self.timeout(60000);
470+
471+
await accounts[0].s3.deleteBucket({ Bucket: alice2_buck }).promise();
469472
for (const account of accounts) {
470473
await rpc_client.account.delete_account({ email: account.email });
471474
}
@@ -542,6 +545,10 @@ mocha.describe('Session token tests', function() {
542545
name: 'first.bucket',
543546
policy: s3accesspolicy,
544547
});
548+
549+
// create a bucket owned by alice2 for ListBuckets to work
550+
// Note: bucket policy alone is not sufficient for ListBuckets operation
551+
await accounts[0].s3.createBucket({ Bucket: alice2_buck }).promise();
545552
});
546553

547554
mocha.it('user b assume role of user a - default expiry - list s3 - should be allowed', async function() {
@@ -564,7 +571,7 @@ mocha.describe('Session token tests', function() {
564571
});
565572

566573
const buckets1 = await temp_s3_with_session_token.listBuckets().promise();
567-
assert.ok(buckets1.Buckets.length > 0);
574+
assert.ok(buckets1.Buckets[0].Name === alice2_buck);
568575
});
569576

570577
mocha.it('user b assume role of user a - valid expiry via durationSeconds - list s3 - should be allowed', async function() {
@@ -589,7 +596,7 @@ mocha.describe('Session token tests', function() {
589596
});
590597

591598
const buckets1 = await temp_s3_with_session_token.listBuckets().promise();
592-
assert.ok(buckets1.Buckets.length > 0);
599+
assert.ok(buckets1.Buckets[0].Name === alice2_buck);
593600
});
594601

595602
mocha.it('user b assume role of user a - invalid expiry via durationSeconds - should be rejected', async function() {

src/test/integration_tests/nsfs/test_nsfs_integration.js

Lines changed: 19 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,12 @@ mocha.describe('bucket operations - namespace_fs', function() {
249249
s3_wrong_uid = new S3(s3_creds);
250250
});
251251
mocha.it('list buckets with wrong uid, gid', async function() {
252-
// Give s3_wrong_uid access to the required buckets
253-
const s3_policy = generate_s3_policy('*', first_bucket, ['s3:*']);
254-
await rpc_client.bucket.put_bucket_policy({ name: first_bucket, policy: s3_policy.policy });
255-
252+
await s3_wrong_uid.createBucket({ Bucket: 'bucket-wrong-uid' });
256253
const res = await s3_wrong_uid.listBuckets({});
257254
console.log(inspect(res));
258-
const list_ok = bucket_in_list([first_bucket], [bucket_name], res.Buckets);
255+
const list_ok = bucket_in_list(['bucket-wrong-uid'], [first_bucket, bucket_name], res.Buckets);
259256
assert.ok(list_ok);
257+
await s3_wrong_uid.deleteBucket({ Bucket: 'bucket-wrong-uid' });
260258
});
261259
mocha.it('update account', async function() {
262260
this.timeout(600000); // eslint-disable-line no-invalid-this
@@ -514,13 +512,12 @@ mocha.describe('bucket operations - namespace_fs', function() {
514512
}
515513
});
516514
mocha.it('list buckets with uid, gid', async function() {
517-
// Give s3_correct_uid access to the required buckets
518-
const generated = generate_s3_policy('*', bucket_name, ['s3:*']);
519-
await rpc_client.bucket.put_bucket_policy({ name: generated.params.bucket, policy: generated.policy });
515+
await s3_correct_uid.createBucket({ Bucket: 'bucket-correct-uid' });
520516
const res = await s3_correct_uid.listBuckets({});
521517
console.log(inspect(res));
522-
const list_ok = bucket_in_list([bucket_name], [], res.Buckets);
518+
const list_ok = bucket_in_list(['bucket-correct-uid'], [bucket_name], res.Buckets);
523519
assert.ok(list_ok);
520+
await s3_correct_uid.deleteBucket({ Bucket: 'bucket-correct-uid' });
524521
});
525522
mocha.it('list buckets with dn', async function() {
526523
// Give s3_correct_uid access to the required buckets
@@ -1059,11 +1056,10 @@ mocha.describe('list objects - namespace_fs', async function() {
10591056
await fs_utils.folder_delete(tmp_fs_root_ls1);
10601057
});
10611058

1062-
mocha.it('list buckets - uid & gid mismatch - should fail', async function() {
1059+
mocha.it('list buckets - uid & gid mismatch - should list nothing initially', async function() {
10631060
const { s3_client } = accounts.account1;
10641061
const res = await s3_client.listBuckets({});
1065-
assert.equal(res.Buckets.length, 1);
1066-
assert.equal(res.Buckets[0].Name, first_bucket);
1062+
assert.equal(res.Buckets.length, 0);
10671063
});
10681064

10691065
mocha.it('put object 1 account_with_access - uid & gid mismatch - should fail', async function() {
@@ -1104,18 +1100,17 @@ mocha.describe('list objects - namespace_fs', async function() {
11041100
}
11051101
});
11061102

1107-
mocha.it('list buckets - uid & gid mismatch - account1', async function() {
1103+
mocha.it('list buckets - uid & gid mismatch - account1 lists owned bucket', async function() {
11081104
const { s3_client } = accounts.account1;
11091105
const res = await s3_client.listBuckets({});
1110-
assert.equal(res.Buckets.length, 2);
1111-
assert.equal(res.Buckets.filter(bucket => bucket.Name === s3_b_name || bucket.Name === first_bucket).length, 2);
1106+
assert.equal(res.Buckets.length, 1);
1107+
assert.equal(res.Buckets[0].Name, s3_b_name);
11121108
});
11131109

1114-
mocha.it('list buckets - uid & gid mismatch - account2', async function() {
1110+
mocha.it('list buckets - uid & gid mismatch - account2 lists nothing', async function() {
11151111
const { s3_client } = accounts.account2;
11161112
const res = await s3_client.listBuckets({});
1117-
assert.equal(res.Buckets.length, 1);
1118-
assert.equal(res.Buckets[0].Name, first_bucket);
1113+
assert.equal(res.Buckets.length, 0);
11191114
});
11201115

11211116
mocha.it('create s3 bucket by root', async function() {
@@ -1125,10 +1120,11 @@ mocha.describe('list objects - namespace_fs', async function() {
11251120
await rpc_client.bucket.put_bucket_policy({ name: s3_root_b_name, policy: s3_policy.policy });
11261121
});
11271122

1128-
mocha.it('list buckets - uid & gid match - account with permission', async function() {
1123+
mocha.it('list buckets - uid & gid match - account lists owned bucket', async function() {
11291124
const { s3_client } = accounts.account4;
11301125
const res = await s3_client.listBuckets({});
1131-
assert.equal(res.Buckets.length, 4);
1126+
assert.equal(res.Buckets.length, 1);
1127+
assert.equal(res.Buckets[0].Name, s3_root_b_name);
11321128
});
11331129

11341130
mocha.it('change mode of /bucket123/ to 0o777: ', async function() {
@@ -1665,92 +1661,14 @@ mocha.describe('list buckets - namespace_fs', async function() {
16651661
await fs_utils.folder_delete(tmp_fs_root_ls);
16661662
});
16671663

1668-
mocha.it('list buckets - each account can list only its own bucket - no bucket policies applied ', async function() {
1664+
mocha.it('list buckets - each account can list only its own bucket', async function() {
16691665
for (const account of Object.values(accounts)) {
16701666
const { s3_client } = account;
16711667
const res = await s3_client.listBuckets({});
16721668
const buckets = res.Buckets.map(bucket => bucket.Name).sort();
1673-
assert.equal(buckets.length, 2);
1674-
assert.deepStrictEqual(buckets, [account.bucket, first_bucket]);
1675-
}
1676-
});
1677-
1678-
mocha.it('account1 - all accounts are allowed to list bucket1', async function() {
1679-
this.timeout(50000); // eslint-disable-line no-invalid-this
1680-
// allow all accounts to list bucket1
1681-
const public_bucket = accounts.account1.bucket;
1682-
const bucket_policy = generate_s3_policy('*', public_bucket, ['s3:ListBucket']);
1683-
await rpc_client.bucket.put_bucket_policy({
1684-
name: public_bucket,
1685-
policy: bucket_policy.policy,
1686-
});
1687-
// check account2 and account3 can list bucket1
1688-
// account2/account3 should be able to list -
1689-
// 1. first.bucket
1690-
// 2. buckets owned by the account (account2 can list bucket2 / account3 can list bucket3)
1691-
// 3. bucket1 (by the given bucket policy)
1692-
// account4 can not list bucket1 because of missing fs access permissions (unmatching uid/gid)
1693-
// account4 can list -
1694-
// 1. first.bucket
1695-
// 2. bucket4 - owned by the account
1696-
for (const account_name of ['account2', 'account3', 'account4']) {
1697-
const account = accounts[account_name];
1698-
const { s3_client, bucket } = account;
1699-
const res = await s3_client.listBuckets({});
1700-
const buckets = res.Buckets.map(bucket_info => bucket_info.Name).sort();
1701-
if (account_name === 'account4') {
1702-
assert.equal(buckets.length, 2);
1703-
assert.deepStrictEqual(buckets, [bucket, first_bucket]);
1704-
} else {
1705-
assert.equal(buckets.length, 3);
1706-
assert.deepStrictEqual(buckets, [accounts.account1.bucket, bucket, first_bucket]);
1707-
}
1669+
assert.equal(buckets.length, 1);
1670+
assert.deepStrictEqual(buckets, [account.bucket]);
17081671
}
1709-
1710-
// delete bucket policy
1711-
await rpc_client.bucket.put_bucket_policy({
1712-
name: public_bucket,
1713-
policy: '',
1714-
});
1715-
});
1716-
1717-
mocha.it('account2 - set allow only account1 list bucket2, account1/account2 can list bucket2 but account3 cant', async function() {
1718-
this.timeout(50000); // eslint-disable-line no-invalid-this
1719-
const bucket2 = accounts.account2.bucket;
1720-
const account_name = 'account1';
1721-
// on NC the account identifier is account name, and on containerized it's the account's email
1722-
// allow bucket2 to be listed by account1
1723-
const account1_principal = is_nc_coretest ? account_name : `${account_name}@noobaa.com`;
1724-
const bucket_policy = generate_s3_policy(account1_principal, bucket2, ['s3:ListBucket']);
1725-
await rpc_client.bucket.put_bucket_policy({
1726-
name: bucket2,
1727-
policy: bucket_policy.policy,
1728-
});
1729-
1730-
// account1 can list -
1731-
// 1. bucket1
1732-
// 2. bucket2 (due to the policy)
1733-
// 3. first.bucket
1734-
let s3_client = accounts.account1.s3_client;
1735-
let res = await s3_client.listBuckets({});
1736-
let buckets = res.Buckets.map(bucket => bucket.Name).sort();
1737-
assert.equal(buckets.length, 3);
1738-
assert.deepStrictEqual(buckets, [accounts.account1.bucket, accounts.account2.bucket, first_bucket]);
1739-
1740-
// account3 can list -
1741-
// 1. bucket3
1742-
// 2. first.bucket
1743-
s3_client = accounts.account3.s3_client;
1744-
res = await s3_client.listBuckets({});
1745-
buckets = res.Buckets.map(bucket => bucket.Name).sort();
1746-
assert.equal(buckets.length, 2);
1747-
assert.deepStrictEqual(buckets, [accounts.account3.bucket, first_bucket]);
1748-
1749-
// delete bucket policy
1750-
await rpc_client.bucket.put_bucket_policy({
1751-
name: bucket2,
1752-
policy: '',
1753-
});
17541672
});
17551673
});
17561674

src/test/unit_tests/nsfs/test_bucketspace_fs.js

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const nb_native = require('../../../util/nb_native');
2222
const SensitiveString = require('../../../util/sensitive_string');
2323
const NamespaceFS = require('../../../sdk/namespace_fs');
2424
const BucketSpaceFS = require('../../../sdk/bucketspace_fs');
25-
const { TMP_PATH, generate_s3_policy } = require('../../system_tests/test_utils');
25+
const { TMP_PATH } = require('../../system_tests/test_utils');
2626
const { CONFIG_SUBDIRS, JSON_SUFFIX } = require('../../../sdk/config_fs');
2727
const nc_mkm = require('../../../manage_nsfs/nc_master_key_manager').get_instance();
2828

@@ -519,27 +519,10 @@ mocha.describe('bucketspace_fs', function() {
519519
const res = await bucketspace_fs.list_buckets({}, dummy_object_sdk_for_iam_account);
520520
assert.equal(res.buckets.length, 0);
521521
});
522-
mocha.it('list buckets - different account with bucket policy (principal by name)', async function() {
523-
// another user created a bucket
524-
// with bucket policy account_user3 can list it
525-
const policy = generate_s3_policy(account_user4.name, test_bucket, ['s3:*']).policy;
526-
const param = { name: test_bucket, policy: policy };
527-
await bucketspace_fs.put_bucket_policy(param);
528-
const dummy_object_sdk_for_iam_account = make_dummy_object_sdk_for_account(dummy_object_sdk, account_user4);
529-
const res = await bucketspace_fs.list_buckets({}, dummy_object_sdk_for_iam_account);
530-
assert.equal(res.buckets.length, 1);
531-
assert.equal(res.buckets[0].name.unwrap(), test_bucket);
532-
});
533-
mocha.it('list buckets - different account with bucket policy (principal by id)', async function() {
534-
// another user created a bucket
535-
// with bucket policy account_user3 can list it
536-
const policy = generate_s3_policy(account_user4._id, test_bucket, ['s3:*']).policy;
537-
const param = { name: test_bucket, policy: policy };
538-
await bucketspace_fs.put_bucket_policy(param);
522+
mocha.it('list buckets - different account cannot list buckets they do not own', async function() {
539523
const dummy_object_sdk_for_iam_account = make_dummy_object_sdk_for_account(dummy_object_sdk, account_user4);
540524
const res = await bucketspace_fs.list_buckets({}, dummy_object_sdk_for_iam_account);
541-
assert.equal(res.buckets.length, 1);
542-
assert.equal(res.buckets[0].name.unwrap(), test_bucket);
525+
assert.equal(res.buckets.length, 0);
543526
});
544527
mocha.afterEach(async function() {
545528
await fs_utils.folder_delete(`${new_buckets_path}/${test_bucket}`);

0 commit comments

Comments
 (0)