diff options
author | Israel Hsu <israel.hsu@mongodb.com> | 2023-04-04 17:52:23 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-04-04 19:19:18 +0000 |
commit | b584db7ad2e3256b37aa0191bb2b1215a7aff709 (patch) | |
tree | e5e02718c6af4b9f2bba1a4927c2f32c0913f05d /jstests | |
parent | e0a1eb3ce7cb84669666e94c9f37d1d3bffe53ec (diff) | |
download | mongo-b584db7ad2e3256b37aa0191bb2b1215a7aff709.tar.gz |
SERVER-69653 Add auth privilege requirements to the analyzeShardKey and configureQueryAnalyzer commands
Diffstat (limited to 'jstests')
4 files changed, 392 insertions, 2 deletions
diff --git a/jstests/sharding/analyze_shard_key/analyze_shard_key_agg_stage_auth.js b/jstests/sharding/analyze_shard_key/analyze_shard_key_agg_stage_auth.js new file mode 100644 index 00000000000..78fc4f1d1e8 --- /dev/null +++ b/jstests/sharding/analyze_shard_key/analyze_shard_key_agg_stage_auth.js @@ -0,0 +1,134 @@ +/** + * Test to validate the privileges required by the analyzeShardKey aggregation stage, + * $_analyzeShardKeyReadWriteDistribution. + * + * @tags: [requires_fcv_70, featureFlagAnalyzeShardKey] + */ + +(function() { + +'use strict'; + +function runTest(primary) { + const dbName = "testDb"; + const collName0 = "testColl0"; + const collName1 = "testColl1"; + const ns0 = dbName + "." + collName0; + const ns1 = dbName + "." + collName1; + + const adminDb = primary.getDB("admin"); + assert.commandWorked( + adminDb.runCommand({createUser: "super", pwd: "super", roles: ["__system"]})); + assert(adminDb.auth("super", "super")); + const testDb = adminDb.getSiblingDB(dbName); + const docs = []; + const numDocs = 1000; + for (let i = 0; i < numDocs; i++) { + docs.push({x: i}); + } + assert.commandWorked(testDb.getCollection(collName0).insert(docs)); + assert.commandWorked(testDb.getCollection(collName1).insert(docs)); + assert(adminDb.logout()); + + // $_analyzeShardKeyReadWriteDistribution spec + const stageSpec = { + key: {x: 1}, + splitPointsNss: "config.analyzeShardKey.splitPoints.test", + splitPointsAfterClusterTime: new Timestamp(100, 1), + // The use of "dummyShard" for splitPointsShardId will cause the aggregation to fail on + // a sharded cluster with error code ShardNotFound. + splitPointsShardId: "dummyShard" + }; + const aggregateCmd0 = { + aggregate: collName0, + pipeline: [{$_analyzeShardKeyReadWriteDistribution: stageSpec}], + cursor: {} + }; + const aggregateCmd1 = { + aggregate: collName1, + pipeline: [{$_analyzeShardKeyReadWriteDistribution: stageSpec}], + cursor: {} + }; + + // Set up a user without any role or privilege. + assert(adminDb.auth("super", "super")); + assert.commandWorked(testDb.runCommand({createUser: "user_no_priv", pwd: "pwd", roles: []})); + assert(adminDb.logout()); + // Verify that the user is not authorized to run the analyzeShardKey stage against ns0 or ns1. + assert(testDb.auth("user_no_priv", "pwd")); + assert.commandFailedWithCode(testDb.runCommand(aggregateCmd0), ErrorCodes.Unauthorized); + assert.commandFailedWithCode(testDb.runCommand(aggregateCmd0), ErrorCodes.Unauthorized); + assert(testDb.logout()); + + // Set up a user with the 'analyzeShardKey' privilege against ns0. + assert(adminDb.auth("super", "super")); + assert.commandWorked(testDb.runCommand({ + createRole: "role_ns0_priv", + roles: [], + privileges: [{resource: {db: dbName, collection: collName0}, actions: ["analyzeShardKey"]}] + })); + assert.commandWorked(testDb.runCommand({ + createUser: "user_with_explicit_ns0_priv", + pwd: "pwd", + roles: [{role: "role_ns0_priv", db: dbName}] + })); + assert(adminDb.logout()); + // Verify that the user is authorized to run the aggregation stage against ns0 but not ns1. + assert(testDb.auth("user_with_explicit_ns0_priv", "pwd")); + assert.commandWorkedOrFailedWithCode(testDb.runCommand(aggregateCmd0), + ErrorCodes.ShardNotFound); + assert.commandFailedWithCode(testDb.runCommand(aggregateCmd1), ErrorCodes.Unauthorized); + assert(testDb.logout()); + + // Set up a user with the 'clusterManager' role. + assert(adminDb.auth("super", "super")); + assert.commandWorked(adminDb.runCommand({ + createUser: "user_cluster_mgr", + pwd: "pwd", + roles: [{role: "clusterManager", db: "admin"}] + })); + assert(adminDb.logout()); + // Verify that the user is authorized to run the aggregation stage against both ns0 and ns1. + assert(adminDb.auth("user_cluster_mgr", "pwd")); + assert.commandWorkedOrFailedWithCode(testDb.runCommand(aggregateCmd0), + ErrorCodes.ShardNotFound); + assert.commandWorkedOrFailedWithCode(testDb.runCommand(aggregateCmd1), + ErrorCodes.ShardNotFound); + assert(adminDb.logout()); + + // Set up a user with the 'enableSharding' role. + assert(adminDb.auth("super", "super")); + assert.commandWorked(adminDb.runCommand({ + createUser: "user_enable_sharding", + pwd: "pwd", + roles: [{role: "enableSharding", db: "testDb"}] + })); + assert(adminDb.logout()); + // Verify that the user is authorized to run the aggregation command against both ns0 and ns1. + assert(adminDb.auth("user_enable_sharding", "pwd")); + assert.commandWorkedOrFailedWithCode(testDb.runCommand(aggregateCmd0), + ErrorCodes.ShardNotFound); + assert.commandWorkedOrFailedWithCode(testDb.runCommand(aggregateCmd1), + ErrorCodes.ShardNotFound); + assert(adminDb.logout()); +} + +{ + const st = new ShardingTest({shards: 1, keyFile: "jstests/libs/key1"}); + + runTest(st.rs0.getPrimary()); + + st.stop(); +} + +{ + const rst = new ReplSetTest({nodes: 1, keyFile: "jstests/libs/key1"}); + rst.startSet(); + rst.initiate(); + const primary = rst.getPrimary(); + + runTest(primary); + + rst.stopSet(); +} +})(); diff --git a/jstests/sharding/analyze_shard_key/analyze_shard_key_auth.js b/jstests/sharding/analyze_shard_key/analyze_shard_key_auth.js new file mode 100644 index 00000000000..61060cf70fb --- /dev/null +++ b/jstests/sharding/analyze_shard_key/analyze_shard_key_auth.js @@ -0,0 +1,116 @@ +/** + * Test to validate the privileges required by the analyzeShardKey and configureQueryAnalyzer + * commands and _refreshQueryAnalyzerConfiguration internal command. + * + * @tags: [requires_fcv_70, featureFlagAnalyzeShardKey] + */ + +(function() { + +'use strict'; + +function runTest(conn) { + const dbName = "testDb"; + const collName0 = "testColl0"; + const collName1 = "testColl1"; + const ns0 = dbName + "." + collName0; + const ns1 = dbName + "." + collName1; + + const adminDb = conn.getDB("admin"); + assert.commandWorked( + adminDb.runCommand({createUser: "super", pwd: "super", roles: ["__system"]})); + assert(adminDb.auth("super", "super")); + const testDb = adminDb.getSiblingDB(dbName); + const docs = []; + const numDocs = 1000; + for (let i = 0; i < numDocs; i++) { + docs.push({x: i}); + } + assert.commandWorked(testDb.getCollection(collName0).insert(docs)); + assert.commandWorked(testDb.getCollection(collName1).insert(docs)); + assert(adminDb.logout()); + + // Set up a user without any role or privilege. + assert(adminDb.auth("super", "super")); + assert.commandWorked(adminDb.runCommand({createUser: "user_no_priv", pwd: "pwd", roles: []})); + assert(adminDb.logout()); + // Verify that the user is not authorized to run the analyzeShardKey command against ns0 or + // ns1. + assert(adminDb.auth("user_no_priv", "pwd")); + assert.commandFailedWithCode(adminDb.runCommand({"analyzeShardKey": ns0, key: {_id: 1}}), + ErrorCodes.Unauthorized); + assert.commandFailedWithCode(adminDb.runCommand({"analyzeShardKey": ns1, key: {_id: 1}}), + ErrorCodes.Unauthorized); + assert(adminDb.logout()); + + // Set up a user with the 'analyzeShardKey' privilege against ns0. + assert(adminDb.auth("super", "super")); + assert.commandWorked(adminDb.runCommand({ + createRole: "role_ns0_priv", + roles: [], + privileges: [{resource: {db: dbName, collection: collName0}, actions: ["analyzeShardKey"]}] + })); + assert.commandWorked(adminDb.runCommand({ + createUser: "user_with_explicit_ns0_priv", + pwd: "pwd", + roles: [{role: "role_ns0_priv", db: "admin"}] + })); + assert(adminDb.logout()); + // Verify that the user is authorized to run the analyzeShardKey command against ns0 but not + // ns1. + assert(adminDb.auth("user_with_explicit_ns0_priv", "pwd")); + assert.commandWorked(adminDb.runCommand({"analyzeShardKey": ns0, key: {_id: 1}})); + assert.commandFailedWithCode(adminDb.runCommand({"analyzeShardKey": ns1, key: {_id: 1}}), + ErrorCodes.Unauthorized); + assert(adminDb.logout()); + + // Set up a user with the 'clusterManager' role. + assert(adminDb.auth("super", "super")); + assert.commandWorked(adminDb.runCommand({ + createUser: "user_cluster_mgr", + pwd: "pwd", + roles: [{role: "clusterManager", db: "admin"}] + })); + assert(adminDb.logout()); + // Verify that the user is authorized to run the analyzeShardKey command against both ns0 + // and ns1. + assert(adminDb.auth("user_cluster_mgr", "pwd")); + assert.commandWorked(adminDb.runCommand({"analyzeShardKey": ns0, key: {_id: 1}})); + assert.commandWorked(adminDb.runCommand({"analyzeShardKey": ns1, key: {_id: 1}})); + assert(adminDb.logout()); + + // Set up a user with the 'enableSharding' role. + assert(adminDb.auth("super", "super")); + assert.commandWorked(adminDb.runCommand({ + createUser: "user_enable_sharding", + pwd: "pwd", + roles: [{role: "enableSharding", db: "admin"}] + })); + assert(adminDb.logout()); + // Verify that the user is authorized to run the analyzeShardKey command against both ns0 + // and ns1. + assert(adminDb.auth("user_enable_sharding", "pwd")); + assert.commandWorked(adminDb.runCommand({"analyzeShardKey": ns0, key: {_id: 1}})); + assert.commandWorked(adminDb.runCommand({"analyzeShardKey": ns1, key: {_id: 1}})); + assert(adminDb.logout()); +} + +{ + const st = new ShardingTest({shards: 1, keyFile: "jstests/libs/key1"}); + + runTest(st.s); + + st.stop(); +} + +{ + const rst = new ReplSetTest({nodes: 1, keyFile: "jstests/libs/key1"}); + rst.startSet(); + rst.initiate(); + const primary = rst.getPrimary(); + + runTest(primary); + + rst.stopSet(); +} +})(); diff --git a/jstests/sharding/analyze_shard_key/analyze_shard_key_basic.js b/jstests/sharding/analyze_shard_key/analyze_shard_key_basic.js index f24690d531b..e375a6d0478 100644 --- a/jstests/sharding/analyze_shard_key/analyze_shard_key_basic.js +++ b/jstests/sharding/analyze_shard_key/analyze_shard_key_basic.js @@ -282,8 +282,8 @@ if (!TestData.auth) { adminDb.runCommand({createUser: "admin", pwd: "pwd", roles: ["__system"]})); assert(adminDb.auth("admin", "pwd")); - // The analyzeShardKey command is supported on any mongod. - const testCases = [{conn: adminDb, isSupported: true}]; + // The analyzeShardKey command is not supported in multitenancy. + const testCases = [{conn: adminDb, isSupported: false}]; testNonExistingCollection(testCases, tenantId); rst.stopSet(); } diff --git a/jstests/sharding/analyze_shard_key/configure_query_analyzer_auth.js b/jstests/sharding/analyze_shard_key/configure_query_analyzer_auth.js new file mode 100644 index 00000000000..4e70099a2af --- /dev/null +++ b/jstests/sharding/analyze_shard_key/configure_query_analyzer_auth.js @@ -0,0 +1,140 @@ +/** + * Test to validate the privileges required by configureQueryAnalyzer command. Also tests the + * internal command _refreshQueryAnalyzerConfigurations. + * + * @tags: [requires_fcv_70, featureFlagAnalyzeShardKey] + */ + +(function() { + +'use strict'; + +function testConfigureQueryAnalyzer(conn) { + const dbName = "testDb"; + const collName0 = "testColl0"; + const collName1 = "testColl1"; + const ns0 = dbName + "." + collName0; + const ns1 = dbName + "." + collName1; + const otherDbName = "otherTestDb"; + + const adminDb = conn.getDB("admin"); + assert.commandWorked( + adminDb.runCommand({createUser: "super", pwd: "super", roles: ["__system"]})); + assert(adminDb.auth("super", "super")); + const testDb = adminDb.getSiblingDB(dbName); + assert.commandWorked(testDb.createCollection(collName0)); + assert.commandWorked(testDb.createCollection(collName1)); + assert(adminDb.logout()); + + const mode = "full"; + const sampleRate = 100; + + // Set up a user without any role or privilege. + assert(adminDb.auth("super", "super")); + assert.commandWorked(adminDb.runCommand({createUser: "user_no_priv", pwd: "pwd", roles: []})); + assert(adminDb.logout()); + // Verify that the user is not authorized to run the configureQueryAnalyzer command. + assert(adminDb.auth("user_no_priv", "pwd")); + assert.commandFailedWithCode( + adminDb.runCommand({"configureQueryAnalyzer": ns0, mode, sampleRate}), + ErrorCodes.Unauthorized); + assert.commandFailedWithCode( + adminDb.runCommand({"configureQueryAnalyzer": ns1, mode, sampleRate}), + ErrorCodes.Unauthorized); + assert(adminDb.logout()); + + // Set up a user with the 'configureQueryAnalyzer' privilege against ns0. + assert(adminDb.auth("super", "super")); + assert.commandWorked(adminDb.runCommand({ + createRole: "role_ns0_priv", + roles: [], + privileges: + [{resource: {db: dbName, collection: collName0}, actions: ["configureQueryAnalyzer"]}] + })); + assert.commandWorked(adminDb.runCommand({ + createUser: "user_with_explicit_ns0_priv", + pwd: "pwd", + roles: [{role: "role_ns0_priv", db: "admin"}] + })); + assert(adminDb.logout()); + // Verify that the user is authorized to run the configureQueryAnalyzer command against ns0 + // but not ns1. + assert(adminDb.auth("user_with_explicit_ns0_priv", "pwd")); + assert.commandWorked(adminDb.runCommand({"configureQueryAnalyzer": ns0, mode, sampleRate})); + assert.commandFailedWithCode( + adminDb.runCommand({"configureQueryAnalyzer": ns1, mode, sampleRate}), + ErrorCodes.Unauthorized); + assert(adminDb.logout()); + + // Set up a user with the 'clusterManager' role. + assert(adminDb.auth("super", "super")); + assert.commandWorked(adminDb.runCommand({ + createUser: "user_cluster_mgr", + pwd: "pwd", + roles: [{role: "clusterManager", db: "admin"}] + })); + assert(adminDb.logout()); + // Verify that the user is authorized to run the configureQueryAnalyzer command against both + // ns0 and ns1. + assert(adminDb.auth("user_cluster_mgr", "pwd")); + assert.commandWorked(adminDb.runCommand({"configureQueryAnalyzer": ns0, mode, sampleRate})); + assert.commandWorked(adminDb.runCommand({"configureQueryAnalyzer": ns1, mode, sampleRate})); + assert(adminDb.logout()); + + // Set up a user with the 'dbAdmin' role. + assert(adminDb.auth("super", "super")); + assert.commandWorked(adminDb.runCommand( + {createUser: "user_db_admin", pwd: "pwd", roles: [{role: "dbAdmin", db: dbName}]})); + assert(adminDb.logout()); + // Verify that the user is authorized to run the configureQueryAnalyzer command against both + // ns0 and ns1 but not against a ns in some other database. + assert(adminDb.auth("user_db_admin", "pwd")); + assert.commandWorked(adminDb.runCommand({"configureQueryAnalyzer": ns0, mode, sampleRate})); + assert.commandWorked(adminDb.runCommand({"configureQueryAnalyzer": ns1, mode, sampleRate})); + assert.commandFailedWithCode( + adminDb.runCommand({"configureQueryAnalyzer": otherDbName + collName0, mode, sampleRate}), + ErrorCodes.Unauthorized); + assert(adminDb.logout()); +} + +function testRefreshQueryAnalyzerConfiguration(conn) { + // This function uses the users that were setup in testConfigureQueryAnalyzer(). + const adminDb = conn.getDB("admin"); + + // Verify that a user with the internal role is authorized to run the + // _refreshQueryAnalyzerConfiguration command. + assert(adminDb.auth("super", "super")); + assert.commandWorked(adminDb.runCommand( + {_refreshQueryAnalyzerConfiguration: 1, name: conn.host, numQueriesExecutedPerSecond: 1})); + assert(adminDb.logout()); + + assert(adminDb.auth("user_no_priv", "pwd")); + assert.commandFailedWithCode(adminDb.runCommand({ + _refreshQueryAnalyzerConfiguration: 1, + name: conn.host, + numQueriesExecutedPerSecond: 1 + }), + ErrorCodes.Unauthorized); + assert(adminDb.logout()); +} + +{ + const st = new ShardingTest({shards: 1, keyFile: "jstests/libs/key1"}); + + testConfigureQueryAnalyzer(st.s); + testRefreshQueryAnalyzerConfiguration(st.configRS.getPrimary()); + st.stop(); +} + +{ + const rst = new ReplSetTest({nodes: 1, keyFile: "jstests/libs/key1"}); + rst.startSet(); + rst.initiate(); + const primary = rst.getPrimary(); + + testConfigureQueryAnalyzer(primary); + testRefreshQueryAnalyzerConfiguration(primary); + + rst.stopSet(); +} +})(); |