Files
mongo/jstests/auth/internal_command_auth_validation.js
madelinezec ba91f7a2f0 SERVER-96706 router issues search index commands on all hosts for testing only (#30077)
GitOrigin-RevId: e1310806d0894197a110349de0361f5111010eb7
2024-12-12 17:19:24 +00:00

1072 lines
38 KiB
JavaScript

// This test ensures that internal commands only run with proper authorization and fail without
// proper authorization.
// @tags: [requires_profiling]
import {testOnlyCommands} from "jstests/auth/test_only_commands_list.js";
import {AllCommandsTest} from "jstests/libs/all_commands_test.js";
import {ShardingTest} from "jstests/libs/shardingtest.js";
// Multiple users cannot be authenticated on one connection within a session.
TestData.disableImplicitSessions = true;
// Cannot run the filtering metadata check on tests that run refineCollectionShardKey.
TestData.skipCheckShardFilteringMetadata = true;
const adminDbName = "admin";
const shard0name = "shard0000";
const dbName = "admin";
const collName = dbName + ".coll";
const ns = dbName + ".ns";
const dbPath = MongoRunner.toRealDir("$dataDir/commands_built_in_roles_sharded/");
const migrationOperationId = UUID();
const testOnlyCommandsSet = new Set(testOnlyCommands);
const sysUser = {
user: "admin",
pwd: "password",
roles: ["__system"]
};
const noroleUser = {
user: "testuser",
pwd: "password",
roles: []
};
/**
* internalCommandsMap contains tests for each internal command. For each command name there is
* a test object. Each test object inside the map has the following fields.
*
* testname: The name of the command to run.
* command: This includes the command details to run using runCommand.
* precommand: This function is run before the sysUser runs the command (to be tested). This
* creates preconditions so that the command is not blocked.
* postcommand: This function is run after the sysUser runs the command (to be tested)
* successfully. This ensures other commands will not be blocked.
* skip: Some commands are skipped.
*/
const internalCommandsMap = {
_clusterQueryWithoutShardKey: {
testname: "_clusterQueryWithoutShardKey",
command: {
_clusterQueryWithoutShardKey: 1,
writeCmd: {
update: "foo",
updates: [
{q: {x: 1}, u: {$set: {a: 90}, upsert: false}},
]
},
},
},
_addShard: {
testname: "_addShard",
command: {
_addShard: 1,
shardIdentity: {
shardName: shard0name,
clusterId: ObjectId('5b2031806195dffd744258ee'),
configsvrConnectionString: "foobarbaz/host:20022,host:20023,host:20024"
}
},
},
_clusterWriteWithoutShardKey: {
testname: "_clusterWriteWithoutShardKey",
command: {_clusterWriteWithoutShardKey: 1, writeCmd: {}, shardId: "", targetDocId: {}},
},
_configsvrAbortReshardCollection: {
testname: "_configsvrAbortReshardCollection",
command: {_configsvrAbortReshardCollection: "test.x"},
},
_configsvrAddShard: {
testname: "_configsvrAddShard",
command: {_configsvrAddShard: "x"},
},
_configsvrAddShardToZone: {
testname: "_configsvrAddShardToZone",
command: {_configsvrAddShardToZone: shard0name, zone: 'z'},
},
_configsvrBalancerStart: {
testname: "_configsvrBalancerStart",
command: {_configsvrBalancerStart: 1},
},
_configsvrBalancerStatus: {
testname: "_configsvrBalancerStatus",
command: {_configsvrBalancerStatus: 1},
},
_configsvrBalancerStop: {
testname: "_configsvrBalancerStop",
command: {_configsvrBalancerStop: 1},
},
_configsvrCommitChunkMigration: {
testname: "_configsvrCommitChunkMigration",
command: {
_configsvrCommitChunkMigration: "db.fooHashed",
fromShard: "move_chunk_basic-rs0",
toShard: "move_chunk_basic-rs1",
migratedChunk: {
lastmod: {
e: new ObjectId('62b052ac7f5653479a67a54f'),
t: new Timestamp(1655722668, 22),
v: new Timestamp(1, 0)
},
min: {_id: MinKey},
max: {_id: 611686018427387902}
},
fromShardCollectionVersion: {
e: new ObjectId('62b052ac7f5653479a67a54f'),
t: new Timestamp(1655722668, 22),
v: new Timestamp(1, 3)
},
validAfter: new Timestamp(1655722670, 6)
},
},
_configsvrBalancerCollectionStatus: {
testname: "_configsvrBalancerCollectionStatus",
command: {
_configsvrBalancerCollectionStatus: "x.y",
},
},
_configsvrCleanupReshardCollection: {
testname: "_configsvrCleanupReshardCollection",
command: {_configsvrCleanupReshardCollection: "test.x"},
},
_configsvrClearJumboFlag: {
testname: "_configsvrClearJumboFlag",
command:
{_configsvrClearJumboFlag: "x.y", epoch: ObjectId(), minKey: {x: 0}, maxKey: {x: 10}},
},
_configsvrCommitChunksMerge: {
testname: "_configsvrCommitChunksMerge",
command: {
_configsvrCommitChunksMerge: "x.y",
shard: shard0name,
collUUID: {uuid: UUID()},
chunkRange: {min: {a: 1}, max: {a: 10}}
},
},
_configsvrCommitChunkSplit: {
testname: "_configsvrCommitChunkSplit",
command: {_configsvrCommitChunkSplit: "x.y"},
},
_configsvrCommitIndex: {
testname: "_configsvrCommitIndex",
command: {
_configsvrCommitIndex: "x.y",
keyPattern: {x: 1},
name: 'x_1',
options: {},
collectionUUID: UUID(),
collectionIndexUUID: UUID(),
lastmod: Timestamp(1, 0),
},
},
_configsvrCommitRefineCollectionShardKey: {
testname: "_configsvrCommitRefineCollectionShardKey",
command: {
_configsvrCommitRefineCollectionShardKey: "test.x",
key: {aKey: 1},
newEpoch: new ObjectId(),
newTimestamp: Timestamp(),
oldTimestamp: Timestamp()
},
},
_configsvrCommitMergeAllChunksOnShard: {
testname: "_configsvrCommitMergeAllChunksOnShard",
command: {_configsvrCommitMergeAllChunksOnShard: "test.x", shard: shard0name},
},
_configsvrCommitReshardCollection: {
testname: "_configsvrCommitReshardCollection",
command: {_configsvrCommitReshardCollection: "test.x"},
},
_configsvrConfigureCollectionBalancing: {
testname: "_configsvrConfigureCollectionBalancing",
command: {_configsvrConfigureCollectionBalancing: "test.x"},
},
_configsvrCreateDatabase: {
testname: "_configsvrCreateDatabase",
command: {_configsvrCreateDatabase: "test.x", primaryShardId: ""},
},
_configsvrDropIndexCatalogEntry: {
testname: "_configsvrDropIndexCatalogEntry",
command: {
_configsvrDropIndexCatalogEntry: "x.y",
name: 'x_1',
collectionUUID: UUID(),
lastmod: Timestamp(1, 0),
},
},
_configsvrCheckClusterMetadataConsistency: {
testname: "_configsvrCheckClusterMetadataConsistency",
command: {
_configsvrCheckClusterMetadataConsistency: "x.y",
cursor: {},
},
},
_configsvrCheckMetadataConsistency: {
testname: "_configsvrCheckMetadataConsistency",
command: {
_configsvrCheckMetadataConsistency: "x.y",
cursor: {},
},
},
_configsvrCollMod: {
testname: "_configsvrCollMod",
command: {
_configsvrCollMod: "x.y",
collModRequest: {},
},
},
_configsvrCommitMovePrimary: {
testname: "_configsvrCommitMovePrimary",
command: {
_configsvrCommitMovePrimary: "test",
expectedDatabaseVersion: {
uuid: new UUID(),
timestamp: new Timestamp(1691525961, 12),
lastMod: NumberInt(5),
},
to: shard0name
},
},
_configsvrEnsureChunkVersionIsGreaterThan: {
testname: "_configsvrEnsureChunkVersionIsGreaterThan",
command: {
_configsvrEnsureChunkVersionIsGreaterThan: "x.y",
minKey: {},
maxKey: {},
version: {e: ObjectId("6657bdabfd296e9f62d2816c"), t: Timestamp(), v: Timestamp()},
collectionUUID: UUID(),
nss: ns,
},
},
_configsvrGetHistoricalPlacement: {
testname: "_configsvrGetHistoricalPlacement",
command: {
_configsvrGetHistoricalPlacement: "x.y",
at: new Timestamp(1691525961, 12),
},
},
_configsvrMoveRange: {
testname: "_configsvrMoveRange",
command: {
_configsvrMoveRange: "x.y",
toShard: shard0name,
},
},
_configsvrRemoveChunks: {
testname: "_configsvrRemoveChunks",
command: {
_configsvrRemoveChunks: 1,
collectionUUID: UUID(),
},
},
_configsvrRemoveShard: {
testname: "_configsvrRemoveShard",
command: {_configsvrRemoveShard: 1, removeShard: shard0name},
},
_configsvrRemoveShardFromZone: {
testname: "_configsvrRemoveShardFromZone",
command: {_configsvrRemoveShardFromZone: 1, removeShard: shard0name, zone: 'z'},
},
_configsvrRemoveTags: {
testname: "_configsvrRemoveTags",
command: {_configsvrRemoveTags: "test"},
},
_configsvrRepairShardedCollectionChunksHistory: {
testname: "_configsvrRepairShardedCollectionChunksHistory",
command: {_configsvrRepairShardedCollectionChunksHistory: ns},
},
_configsvrResetPlacementHistory: {
testname: "_configsvrResetPlacementHistory",
command: {_configsvrResetPlacementHistory: ns},
},
_configsvrReshardCollection: {
testname: "_configsvrReshardCollection",
command: {_configsvrReshardCollection: ns, key: {_id: 1}},
},
_configsvrRunRestore: {
testname: "_configsvrRunRestore",
command: {_configsvrRunRestore: 1},
},
_configsvrSetAllowMigrations: {
testname: "_configsvrSetAllowMigrations",
command: {
_configsvrSetAllowMigrations: ns,
allowMigrations: false,
writeConcern: {w: "majority"}
},
},
_configsvrSetClusterParameter: {
testname: "_configsvrSetClusterParameter",
command: {
_configsvrSetClusterParameter: {},
},
},
_configsvrSetUserWriteBlockMode: {
testname: "_configsvrSetUserWriteBlockMode",
command: {_configsvrSetUserWriteBlockMode: 1, global: true},
},
_configsvrTransitionFromDedicatedConfigServer: {
testname: "_configsvrTransitionFromDedicatedConfigServer",
command: {_configsvrTransitionFromDedicatedConfigServer: 1},
},
_configsvrTransitionToDedicatedConfigServer: {
testname: "_configsvrTransitionToDedicatedConfigServer",
command: {_configsvrTransitionToDedicatedConfigServer: 1},
},
_configsvrUpdateZoneKeyRange: {
testname: "_configsvrUpdateZoneKeyRange",
command: {_configsvrUpdateZoneKeyRange: 'test.foo', min: {x: 1}, max: {x: 5}, zone: 'z'},
},
_dropConnectionsToMongot: {
testname: "_dropConnectionsToMongot",
command: {_dropConnectionsToMongot: 1, hostAndPort: []},
},
_flushDatabaseCacheUpdates: {
testname: "_flushDatabaseCacheUpdates",
command: {_flushDatabaseCacheUpdates: 'test'},
},
_flushDatabaseCacheUpdatesWithWriteConcern: {
testname: "_flushDatabaseCacheUpdatesWithWriteConcern",
command: {_flushDatabaseCacheUpdatesWithWriteConcern: 'test', writeConcern: {w: 2}},
},
_flushReshardingStateChange: {
testname: "_flushReshardingStateChange",
command: {
_flushReshardingStateChange: ns,
reshardingUUID: UUID(),
},
},
_flushRoutingTableCacheUpdates: {
testname: "_flushRoutingTableCacheUpdates",
command: {
_flushRoutingTableCacheUpdates: ns,
},
},
_flushRoutingTableCacheUpdatesWithWriteConcern: {
testname: "_flushRoutingTableCacheUpdatesWithWriteConcern",
command: {_flushRoutingTableCacheUpdatesWithWriteConcern: ns, writeConcern: {w: 2}},
},
_getNextSessionMods: {
testname: "_getNextSessionMods",
command: {_getNextSessionMods: "a-b"},
},
_getUserCacheGeneration: {
testname: "_getUserCacheGeneration",
command: {_getUserCacheGeneration: 1},
},
_hashBSONElement: {
testname: "_hashBSONElement",
command: {_hashBSONElement: 0, seed: 1},
},
_isSelf: {
skip: true, // This command does not need '__system' role as it is currently used in atlas
// tools.
testname: "_isSelf",
command: {_isSelf: 1},
},
_killOperations: {
testname: "_killOperations",
command: {_killOperations: 1, operationKeys: [UUID()]},
},
_mergeAuthzCollections: {
testname: "_mergeAuthzCollections",
command: {
_mergeAuthzCollections: 1,
tempUsersCollection: 'admin.tempusers',
tempRolesCollection: 'admin.temproles',
db: "",
drop: false
},
},
_migrateClone: {
testname: "_migrateClone",
command: {_migrateClone: "test"},
},
_mongotConnPoolStats: {
testname: "_mongotConnPoolStats",
command: {_mongotConnPoolStats: 1},
},
_recvChunkAbort: {
testname: "_recvChunkAbort",
command: {_recvChunkAbort: 1},
},
_recvChunkCommit: {
testname: "_recvChunkCommit",
command: {_recvChunkCommit: 1},
},
_recvChunkReleaseCritSec: {
testname: "_recvChunkReleaseCritSec",
command: {_recvChunkReleaseCritSec: 1},
},
_recvChunkStart: {
testname: "_recvChunkStart",
command: {_recvChunkStart: ns},
},
_recvChunkStatus: {
testname: "_recvChunkStatus",
command: {_recvChunkStatus: ns},
},
_refreshQueryAnalyzerConfiguration: {
testname: "_refreshQueryAnalyzerConfiguration",
command:
{_refreshQueryAnalyzerConfiguration: 1, name: "test", numQueriesExecutedPerSecond: 1},
},
_shardsvrAbortReshardCollection: {
testname: "_shardsvrAbortReshardCollection",
command: {_shardsvrAbortReshardCollection: UUID(), userCanceled: true},
},
_shardsvrRunSearchIndexCommand: {
// test only comand. Bc this command is included in test_only_commands_list.js, this will be
// skipped.
testname: "__shardsvrRunSearchIndexCommand",
command: {__shardsvrRunSearchIndexCommand: 1, hostAndPort: []},
},
_shardsvrBeginMigrationBlockingOperation: {
testname: "_shardsvrBeginMigrationBlockingOperation",
command: {_shardsvrBeginMigrationBlockingOperation: ns, operationId: migrationOperationId},
postcommand: (db) => {
assert.commandWorked(db.runCommand(
{_shardsvrEndMigrationBlockingOperation: ns, operationId: migrationOperationId}));
},
},
_shardsvrChangePrimary: {
testname: "_shardsvrChangePrimary",
command: {
_shardsvrChangePrimary: "test",
expectedDatabaseVersion: {
uuid: new UUID(),
timestamp: new Timestamp(1691525961, 12),
lastMod: NumberInt(5),
},
to: shard0name
},
},
_shardsvrCleanupStructuredEncryptionData: {
testname: "_shardsvrCleanupStructuredEncryptionData",
command: {_shardsvrCleanupStructuredEncryptionData: "test", cleanupTokens: {}},
},
_shardsvrCleanupReshardCollection: {
testname: "_shardsvrCleanupReshardCollection",
command: {_shardsvrCleanupReshardCollection: "test.x", reshardingUUID: UUID()},
},
_shardsvrCloneCatalogData: {
testname: "_shardsvrCloneCatalogData",
command: {_shardsvrCloneCatalogData: 'test', from: [], writeConcern: {w: "majority"}},
},
_shardsvrCompactStructuredEncryptionData: {
testname: "_shardsvrCompactStructuredEncryptionData",
command: {_shardsvrCompactStructuredEncryptionData: 'test', compactionTokens: {}},
},
_shardsvrConvertToCapped: {
testname: "_shardsvrConvertToCapped",
command: {_shardsvrConvertToCapped: 'test', size: 0},
},
_shardsvrRegisterIndex: {
testname: "_shardsvrRegisterIndex",
command: {
_shardsvrRegisterIndex: ns,
keyPattern: {x: 1},
options: {},
name: 'x_1',
collectionUUID: UUID(),
indexCollectionUUID: UUID(),
lastmod: Timestamp(0, 0),
writeConcern: {w: 'majority'}
},
},
_shardsvrCommitIndexParticipant: {
testname: "_shardsvrCommitIndexParticipant",
command: {
_shardsvrCommitIndexParticipant: "x.y",
name: 'x_1',
keyPattern: {x: 1},
options: {},
collectionUUID: UUID(),
lastmod: Timestamp(1, 0),
},
},
_shardsvrCommitReshardCollection: {
testname: "_shardsvrCommitReshardCollection",
command: {
_shardsvrCommitReshardCollection: "x.y",
reshardingUUID: UUID(),
},
},
_shardsvrDropCollection: {
testname: "_shardsvrDropCollection",
command: {
_shardsvrDropCollection: "x.y",
collectionUUID: UUID(),
},
},
_shardsvrConvertToCappedParticipant: {
testname: "_shardsvrConvertToCappedParticipant",
command: {
_shardsvrConvertToCappedParticipant: "x.y",
size: 0,
targetUUID: UUID(),
},
},
_shardsvrJoinDDLCoordinators: {
testname: "_shardsvrJoinDDLCoordinators",
command: {
_shardsvrJoinDDLCoordinators: "x.y",
},
},
_shardsvrCreateCollection: {
testname: "_shardsvrCreateCollection",
command: {
_shardsvrCreateCollection: "x.y",
collectionUUID: UUID(),
},
},
_shardsvrDropCollectionIfUUIDNotMatchingWithWriteConcern: {
testname: "_shardsvrDropCollectionIfUUIDNotMatchingWithWriteConcern",
command: {
_shardsvrDropCollectionIfUUIDNotMatchingWithWriteConcern: "x.y",
expectedCollectionUUID: UUID(),
},
},
_shardsvrDropCollectionParticipant: {
testname: "_shardsvrDropCollectionParticipant",
command: {
_shardsvrDropCollectionParticipant: "x.y",
},
},
_shardsvrDropIndexCatalogEntryParticipant: {
testname: "_shardsvrDropIndexCatalogEntryParticipant",
command: {
_shardsvrDropIndexCatalogEntryParticipant: "x.y",
name: 'x_1',
collectionUUID: UUID(),
lastmod: Timestamp(1, 0),
},
},
_shardsvrDropIndexes: {
testname: "_shardsvrDropIndexes",
command: {
_shardsvrDropIndexes: "x.y",
index: "*",
collectionUUID: UUID(),
},
},
_shardsvrCreateCollectionParticipant: {
testname: "_shardsvrCreateCollectionParticipant",
command: {
_shardsvrCreateCollectionParticipant: "x.y",
indexes: [],
options: {},
idIndex: {v: 2, key: {_id: 1}, name: "_id_"},
},
},
_shardsvrCoordinateMultiUpdate: {
testname: "_shardsvrCoordinateMultiUpdate",
precommand: (precommanddb, user, pwd, coll) => {
assert(precommanddb.auth(user, pwd));
assert.commandWorked(coll.insert({x: 1, y: 1}));
assert.commandWorked(coll.insert({x: 1, y: 2}));
precommanddb.logout();
},
command: {
_shardsvrCoordinateMultiUpdate: collName,
uuid: UUID(),
command: {update: collName, updates: [{q: {x: 1}, u: {$set: {y: 2}}, multi: true}]}
},
},
_shardsvrEndMigrationBlockingOperation: {
testname: "_shardsvrEndMigrationBlockingOperation",
command: {
_shardsvrEndMigrationBlockingOperation: "ns",
operationId: migrationOperationId,
},
},
_shardsvrGetStatsForBalancing: {
testname: "_shardsvrGetStatsForBalancing",
command: {_shardsvrGetStatsForBalancing: "ns", collections: [], scaleFactor: 1},
},
_shardsvrJoinMigrations: {
testname: "_shardsvrJoinMigrations",
command: {_shardsvrJoinMigrations: 1},
},
_shardsvrMergeAllChunksOnShard: {
testname: "_shardsvrMergeAllChunksOnShard",
command: {
_shardsvrMergeAllChunksOnShard: "x.y",
shard: shard0name,
maxNumberOfChunksToMerge: NumberInt(2)
},
},
_shardsvrMovePrimary: {
testname: "_shardsvrMovePrimary",
command: {
_shardsvrMovePrimary: "test",
expectedDatabaseVersion: {
uuid: new UUID(),
timestamp: new Timestamp(1691525961, 12),
lastMod: NumberInt(5),
},
to: shard0name
},
},
_shardsvrMovePrimaryEnterCriticalSection: {
testname: "_shardsvrMovePrimaryEnterCriticalSection",
command: {_shardsvrMovePrimaryEnterCriticalSection: "test", reason: {}},
},
_shardsvrMovePrimaryExitCriticalSection: {
testname: "_shardsvrMovePrimaryExitCriticalSection",
command: {_shardsvrMovePrimaryExitCriticalSection: "test", reason: {}},
},
_shardsvrMoveRange: {
testname: "_shardsvrMoveRange",
command: {
_shardsvrMoveRange: "test.view",
fromShard: shard0name,
toShard: "shard0001",
maxChunkSizeBytes: NumberInt(100)
},
},
_shardsvrNotifyShardingEvent: {
testname: "_shardsvrNotifyShardingEvent",
command: {_shardsvrNotifyShardingEvent: "test", eventType: "databasesAdded", details: {}},
},
_shardsvrRenameCollection: {
testname: "_shardsvrRenameCollection",
command: {_shardsvrRenameCollection: "test.collection", to: "db.collection_renamed"},
},
_shardsvrRenameCollectionParticipant: {
testname: "_shardsvrRenameCollectionParticipant",
command: {
_shardsvrRenameCollectionParticipant: "test.collection",
to: "db.collection_renamed",
sourceUUID: UUID()
},
},
_shardsvrRenameCollectionParticipantUnblock: {
testname: "_shardsvrRenameCollectionParticipantUnblock",
command: {
_shardsvrRenameCollectionParticipantUnblock: "test.collection",
to: "db.collection_renamed",
sourceUUID: UUID()
},
},
_shardsvrRenameIndexMetadata: {
testname: "_shardsvrRenameIndexMetadata",
command: {
_shardsvrRenameIndexMetadata: "test.collection",
toNss: ns,
indexVersion: {uuid: UUID(), version: Timestamp()},
},
},
_shardsvrDropDatabase: {
testname: "_shardsvrDropDatabase",
command: {
_shardsvrDropDatabase: 1,
},
},
_shardsvrDropDatabaseParticipant: {
testname: "_shardsvrDropDatabaseParticipant",
command: {
_shardsvrDropDatabaseParticipant: "test.x",
},
},
_shardsvrReshardCollection: {
testname: "_shardsvrReshardCollection",
command: {
_shardsvrReshardCollection: "test.x",
phase: "unset",
key: {},
},
},
_shardsvrReshardingOperationTime: {
testname: "_shardsvrReshardingOperationTime",
command: {
_shardsvrReshardingOperationTime: "test.x",
},
},
_shardsvrRefineCollectionShardKey: {
testname: "_shardsvrRefineCollectionShardKey",
command: {_shardsvrRefineCollectionShardKey: "test.x", newShardKey: {}},
},
_shardsvrSetAllowMigrations: {
testname: "_shardsvrSetAllowMigrations",
command: {_shardsvrSetAllowMigrations: "db.collection", allowMigrations: true},
},
_shardsvrSetClusterParameter: {
testname: "_shardsvrSetClusterParameter",
command: {_shardsvrSetClusterParameter: {}, clusterParameterTime: Timestamp()},
},
_shardsvrSetUserWriteBlockMode: {
testname: "_shardsvrSetUserWriteBlockMode",
command: {
_shardsvrSetUserWriteBlockMode: 1,
global: true,
phase: 'complete',
},
},
_shardsvrValidateShardKeyCandidate: {
testname: "_shardsvrValidateShardKeyCandidate",
command: {_shardsvrValidateShardKeyCandidate: "x.y", key: {a: 1}},
},
_shardsvrCollModParticipant: {
testname: "_shardsvrCollModParticipant",
command: {
_shardsvrCollModParticipant: "x.y",
collModRequest: {},
},
},
_shardsvrCollMod: {
testname: "_shardsvrCollMod",
command: {
_shardsvrCollMod: "x.y",
},
},
_shardsvrParticipantBlock: {
testname: "_shardsvrParticipantBlock",
command: {
_shardsvrParticipantBlock: "x.y",
},
},
_shardsvrUnregisterIndex: {
testname: "_shardsvrUnregisterIndex",
command: {
_shardsvrUnregisterIndex: "x.y",
name: 'x_1',
collectionUUID: UUID(),
lastmod: Timestamp(1, 0),
},
},
_shardsvrUntrackUnsplittableCollection: {
testname: "_shardsvrUntrackUnsplittableCollection",
command: {_shardsvrUntrackUnsplittableCollection: "x.y", writeConcern: {w: 'majority'}},
},
_shardsvrCheckMetadataConsistency: {
testname: "_shardsvrCheckMetadataConsistency",
command: {
_shardsvrCheckMetadataConsistency: "x.y",
},
},
_shardsvrCheckMetadataConsistencyParticipant: {
testname: "_shardsvrCheckMetadataConsistencyParticipant",
command: {
_shardsvrCheckMetadataConsistencyParticipant: "x.y",
primaryShardId: shard0name,
},
},
_transferMods: {
testname: "_transferMods",
command: {
_transferMods: "x.y",
sessionId: {id: UUID()},
},
},
};
/**
* Parameters:
* db -- database object where the user is created.
* userName -- the username.
* roles -- roles for the user
*
* Returns:
* void after creating the user for the test case.
*/
function createUser(db, userName, roles) {
assert(db.auth("admin", "password"));
db.createUser({user: userName, pwd: "password", roles: roles});
db.logout();
return userName;
}
/**
* runOneCommandAuthorizationTest runs authorization failure and success tests for a single command.
* If the user with __system role can run the command without getting Unauthorized error AND if the
* user with no roles can run the command and get an 'Unauthorized` error, then we consider the test
* as passed. Otherwise, the command fails the authorization check.
*
* Parameters:
* testObject -- testObject contains the test information for a single command.
* commandName -- command Name for the test.
* db -- db on which the command is going to run.
* secondDb -- the precommands are run on the second db.
* coll -- collection for the second db command.
* Returns:
* result includes the pass/fail value and the command results for both system role
* and no roles.
*/
function runOneCommandAuthorizationTest(testObject, commandName, db, secondDb, coll) {
const cmdOK = {commandWorked: 1, commandFailed: 0};
let result = {pass: true};
if (testObject.precommand != undefined) {
if (secondDb == undefined) {
return result;
}
testObject.precommand(secondDb, sysUser.user, sysUser.pwd, coll);
}
assert(db.auth(noroleUser.user, noroleUser.pwd));
result.noRoleRes = db.runCommand(testObject.command);
db.logout();
if (result.noRoleRes.ok === cmdOK.commandWorked ||
result.noRoleRes.code !== ErrorCodes.Unauthorized) {
result.pass = false;
return result;
}
assert(db.auth(sysUser.user, sysUser.pwd));
result.sysRes = db.runCommand(testObject.command);
if (result.sysRes.ok === cmdOK.commandWorked && testObject.postcommand !== undefined) {
testObject.postcommand(db);
}
db.logout();
const sysRolePass = (result.sysRes.ok === cmdOK.commandWorked ||
result.sysRes.code !== ErrorCodes.Unauthorized);
assert(sysRolePass);
return result;
}
/**
* Some commands may be skipped if they are test only commands. isSelf command is also skipped.
* @param testObjectForCommand test object for the command.
* @param commandName command Name.
* @returns true if the command is a test only command or if the command needs to be skipped(
* currently only isSelf is skipped. It is used by atlas tools without __system role).
*/
function skipCommand(testObjectForCommand, commandName) {
if (testOnlyCommandsSet.has(commandName) || testObjectForCommand.skip) {
return true;
}
return false;
}
/**
* Parameters:
* conn -- connection, either to standalone mongod,
* or to mongos in sharded cluster
* firstDb -- all commands are tested on the first db.
* secondDb -- the precommands are run on the second db.
* coll -- collection for the second db command.
*
* Returns:
* results of the test
*/
function runAuthorizationTestsOnAllInternalCommands(conn, firstDb, secondDb, coll) {
let results = {};
let fails = [];
const availableCommandsList =
AllCommandsTest.checkCommandCoverage(conn, internalCommandsMap, function(cmdName) {
return !cmdName.startsWith('_') || testOnlyCommandsSet.hasOwnProperty(cmdName);
});
for (const commandName of availableCommandsList) {
const test = internalCommandsMap[commandName];
assert(test, "Coverage failure: must explicitly define a test for " + commandName);
if (skipCommand(test, commandName)) {
continue;
}
results[commandName] =
runOneCommandAuthorizationTest(test, commandName, firstDb, secondDb, coll);
}
return results;
}
/**
* Sets up the standalone test setup and runs authorization tests on all internal commands.
*/
function runStandaloneTest() {
jsTestLog("Starting standalone test");
// Setup standalone mongod, create a DB and create the admin
const dbPath = MongoRunner.toRealDir("$dataDir/commands_built_in_roles_standalone/");
mkdir(dbPath);
const opts = {
auth: "",
setParameter: {
trafficRecordingDirectory: dbPath,
mongotHost: "localhost:27017", // We have to set the mongotHost parameter for the
// $search-relatead tests to pass configuration checks.
syncdelay:
0 // Disable checkpoints as this can cause some commands to fail transiently.
}
};
const conn = MongoRunner.runMongod(opts);
const adminDb = conn.getDB(adminDbName);
adminDb.createUser({user: "admin", pwd: "password", roles: ["__system"]});
createUser(adminDb, noroleUser.user, noroleUser.roles);
const results = runAuthorizationTestsOnAllInternalCommands(conn, adminDb);
MongoRunner.stopMongod(conn);
return results;
}
/**
* Sets up the sharded cluster test setup.
*/
function setupShardedClusterTest() {
mkdir(dbPath);
const opts = {
auth: "",
setParameter: {
trafficRecordingDirectory: dbPath,
mongotHost: "localhost:27017", // We have to set the mongotHost parameter for the
// $search-related tests to pass configuration checks.
syncdelay:
0 // Disable checkpoints as this can cause some commands to fail transiently.
}
};
return opts;
}
/**
* run mongos test.
*/
function runMongosTest(opts) {
jsTestLog("Starting mongos test");
const shardingTest = new ShardingTest({
shards: 2,
mongos: 1,
config: 1,
keyFile: "jstests/libs/key1",
other: {
rsOptions: opts,
// We have to set the mongotHost parameter for the $search-related tests to pass
// configuration checks.
mongosOptions:
{setParameter: {trafficRecordingDirectory: dbPath, mongotHost: "localhost:27017"}}
}
});
const mongos = shardingTest.s0;
const mongosAdminDB = mongos.getDB("admin");
mongosAdminDB.createUser({user: "admin", pwd: "password", roles: ["__system"]});
createUser(mongosAdminDB, noroleUser.user, noroleUser.roles);
const results = runAuthorizationTestsOnAllInternalCommands(mongos, mongosAdminDB);
shardingTest.stop();
return results;
}
/**
* run sharded server test.
*/
function runShardedServerTest(opts) {
const shardingTest = new ShardingTest({
shards: 1,
mongos: 1,
config: 1,
keyFile: "jstests/libs/key1",
useHostname: false,
other: {
rsOptions: opts,
// We have to set the mongotHost parameter for the $search-related tests to pass
// configuration checks.
mongosOptions:
{setParameter: {trafficRecordingDirectory: dbPath, mongotHost: "localhost:27017"}}
}
});
const shardPrimary = shardingTest.rs0.getPrimary();
const shardAdminDB = shardPrimary.getDB("admin");
const mongosDB = shardingTest.s0.getDB("admin");
const coll = mongosDB.getCollection(collName);
mongosDB.createUser({user: "admin", pwd: "password", roles: ["__system"]});
if (!TestData.configShard) {
shardAdminDB.createUser({user: "admin", pwd: "password", roles: ["__system"]});
}
createUser(shardAdminDB, noroleUser.user, noroleUser.roles);
const results =
runAuthorizationTestsOnAllInternalCommands(shardPrimary, shardAdminDB, mongosDB, coll);
shardingTest.stop();
return results;
}
/**
* run config server test.
*/
function runConfigServer(opts) {
const shardingTest = new ShardingTest({
shards: 1,
mongos: 1,
config: 1,
keyFile: "jstests/libs/key1",
other: {
rsOptions: opts,
// We have to set the mongotHost parameter for the $search-related tests to pass
// configuration checks.
mongosOptions:
{setParameter: {trafficRecordingDirectory: dbPath, mongotHost: "localhost:27017"}}
}
});
const configPrimary = shardingTest.configRS.getPrimary();
const configAdminDB = configPrimary.getDB("admin");
configAdminDB.createUser({user: "admin", pwd: "password", roles: ["__system"]});
createUser(configAdminDB, noroleUser.user, noroleUser.roles);
const results = runAuthorizationTestsOnAllInternalCommands(configPrimary, configAdminDB);
shardingTest.stop();
return results;
}
/**
* singleCommandCheckResult gets the update from four setups(runStandaloneTest, sharded cluster,
* sharded server, config server) and returns the combined result for the command.
*
* * Parameters:
* commandName -- command name.
* resultmap -- an object that has setups as the keys and results for the setup as the values.
*
* Returns: a combined result for different test setups for a single command.
*/
function singleCommandCheckResult(commandName, resultmap) {
let singleCommandCombinedResult = {pass: true, absent: true};
for (const [setupName, resultsForSetup] of Object.entries(resultmap)) {
if (!resultsForSetup.hasOwnProperty(commandName)) {
continue;
}
if (singleCommandCombinedResult.pass) {
singleCommandCombinedResult.pass = resultsForSetup[commandName].pass;
}
singleCommandCombinedResult.absent = false;
if (!resultsForSetup[commandName].pass) {
jsTestLog("Test Failure at setup:" + setupName + " command:" + commandName +
tojson(resultsForSetup[commandName]));
}
}
return singleCommandCombinedResult;
}
/**
* checkResults summarize the results from all the results from all the setups.
* * Parameters:
* resultmap -- an object that has setups as the keys and results for the setup as the values.
*
* Returns: None.
*
* The results for all the test objects are accumulated and a combined result for the all the tests
* is announced.
*/
function checkResults(resultmap) {
let summaryResultsCount = {passCount: 0, failCount: 0, absentCount: 0};
for (const [commandName, testObject] of Object.entries(internalCommandsMap)) {
if (skipCommand(testObject, commandName)) {
continue;
}
const currentResult = singleCommandCheckResult(commandName, resultmap);
if (currentResult.absent) {
summaryResultsCount.absentCount++;
jsTestLog(
"Command ${commandName} did not get tested. This may be because a feature flag is not enabled, or this command does not exist in mongod and mongos.");
} else if (currentResult.pass === true) {
summaryResultsCount.passCount++;
} else {
jsTestLog("Test Result Failed command:" + tojson(currentResult));
summaryResultsCount.failCount++;
}
}
jsTest.log("Result: tests passed " + summaryResultsCount.passCount +
". Failed Commands Count: " + summaryResultsCount.failCount +
". Absent Commands Count: " + summaryResultsCount.absentCount + ".");
assert.eq(0, summaryResultsCount.failCount);
}
let resultmap = {};
resultmap.Standalone = runStandaloneTest();
const opts = setupShardedClusterTest();
resultmap.ShardedClusterMongos = runMongosTest(opts);
resultmap.ShardedServer = runShardedServerTest(opts);
resultmap.ConfigServer = runConfigServer(opts);
checkResults(resultmap);