summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorIsrael Hsu <israel.hsu@mongodb.com>2023-04-04 17:52:23 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-04-04 19:19:18 +0000
commitb584db7ad2e3256b37aa0191bb2b1215a7aff709 (patch)
treee5e02718c6af4b9f2bba1a4927c2f32c0913f05d /jstests
parente0a1eb3ce7cb84669666e94c9f37d1d3bffe53ec (diff)
downloadmongo-b584db7ad2e3256b37aa0191bb2b1215a7aff709.tar.gz
SERVER-69653 Add auth privilege requirements to the analyzeShardKey and configureQueryAnalyzer commands
Diffstat (limited to 'jstests')
-rw-r--r--jstests/sharding/analyze_shard_key/analyze_shard_key_agg_stage_auth.js134
-rw-r--r--jstests/sharding/analyze_shard_key/analyze_shard_key_auth.js116
-rw-r--r--jstests/sharding/analyze_shard_key/analyze_shard_key_basic.js4
-rw-r--r--jstests/sharding/analyze_shard_key/configure_query_analyzer_auth.js140
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();
+}
+})();