diff options
author | Josef Ahmad <josef.ahmad@mongodb.com> | 2021-12-15 11:30:22 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-12-21 13:33:45 +0000 |
commit | ba133ee0044dad667cbdb697ff89958b6fce1957 (patch) | |
tree | b6ddc07d0a4d9aed4926b8e4293b43cb4dfe6467 | |
parent | 481e16fd5be189f9d4cf2cff212a46a73f70da29 (diff) | |
download | mongo-ba133ee0044dad667cbdb697ff89958b6fce1957.tar.gz |
SERVER-61955 Make dbCheck a generally available command
Remove the dependency on enableTestCommands and make dbCheck available
to users with clusterManager built-in role.
(cherry picked from commit eddd659580fc123251a0bb0430bf10faf1732f2d)
-rw-r--r-- | jstests/auth/dbcheck.js | 49 | ||||
-rw-r--r-- | src/mongo/db/auth/action_types.txt | 1 | ||||
-rw-r--r-- | src/mongo/db/auth/role_graph_builtin_roles.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/commands/dbcheck.cpp | 19 |
4 files changed, 62 insertions, 14 deletions
diff --git a/jstests/auth/dbcheck.js b/jstests/auth/dbcheck.js new file mode 100644 index 00000000000..460a4c6a89f --- /dev/null +++ b/jstests/auth/dbcheck.js @@ -0,0 +1,49 @@ +/** + * Validate dbCheck authorization. + */ + +// Multiple users cannot be authenticated on one connection within a session. +TestData.disableImplicitSessions = true; + +const m = MongoRunner.runMongod({auth: ""}); + +const db = m.getDB("test"); +const admin = m.getDB('admin'); + +// Set up users and add initial data to be dbChecked later. +{ + admin.createUser({user: 'root', pwd: 'password', roles: [{role: "root", db: "admin"}]}); + admin.auth('root', 'password'); + admin.createUser({ + user: 'userReadWriteAnyDatabase', + pwd: 'pwdReadWriteAnyDatabase', + roles: [{role: "readWriteAnyDatabase", db: "admin"}] + }); + admin.createUser({ + user: 'userClusterManager', + pwd: 'pwdClusterManager', + roles: [{role: "clusterManager", db: "admin"}] + }); + assert.commandWorked(db.c.insertOne({})); + admin.logout(); +} +// Validate that a non-clusterManager user cannot run dbCheck. +{ + assert(admin.auth('userReadWriteAnyDatabase', 'pwdReadWriteAnyDatabase')); + assert.commandWorked(db.c.insertOne({})); + assert.commandFailedWithCode(db.runCommand({dbCheck: 1}), ErrorCodes.Unauthorized); + admin.logout(); +} +// Validate that clusterManager can run dbCheck and inspect its output. +{ + assert(admin.auth('userClusterManager', 'pwdClusterManager')); + const local = db.getSiblingDB('local'); + assert.eq(0, local.system.healthlog.find().itcount()); + assert.commandWorked(db.runCommand({dbCheck: 1})); + + // Wait for the dbCheck deferred writer to populate the healthlog. See SERVER-61765. + assert.soon(() => local.system.healthlog.find().itcount() > 0); + admin.logout(); +} + +MongoRunner.stopMongod(m, null, {user: 'root', pwd: 'password'}); diff --git a/src/mongo/db/auth/action_types.txt b/src/mongo/db/auth/action_types.txt index 24aa0990bdf..88575e2462d 100644 --- a/src/mongo/db/auth/action_types.txt +++ b/src/mongo/db/auth/action_types.txt @@ -36,6 +36,7 @@ "createIndex", # Not used for permissions checks, but to id the event in logs. "createRole", "createUser", +"dbCheck", "dbHash", "dbStats", "dropAllRolesFromDatabase", # Not used for permissions checks, but to id the event in logs. diff --git a/src/mongo/db/auth/role_graph_builtin_roles.cpp b/src/mongo/db/auth/role_graph_builtin_roles.cpp index 0ff5b8a51d5..b001cb2dc70 100644 --- a/src/mongo/db/auth/role_graph_builtin_roles.cpp +++ b/src/mongo/db/auth/role_graph_builtin_roles.cpp @@ -462,6 +462,13 @@ void addClusterManagerPrivileges(PrivilegeVector* privileges) { readRoleActions)); addReadOnlyDbPrivileges(privileges, "config"); + Privilege::addPrivilegeToPrivilegeVector( + privileges, Privilege(ResourcePattern::forAnyResource(), ActionType::dbCheck)); + Privilege::addPrivilegeToPrivilegeVector( + privileges, + Privilege(ResourcePattern::forExactNamespace(NamespaceString("local", "system.healthlog")), + readRoleActions)); + ActionSet writeActions; writeActions << ActionType::insert << ActionType::update << ActionType::remove; Privilege::addPrivilegeToPrivilegeVector( diff --git a/src/mongo/db/commands/dbcheck.cpp b/src/mongo/db/commands/dbcheck.cpp index 627d804f42e..98f7d6ef9f7 100644 --- a/src/mongo/db/commands/dbcheck.cpp +++ b/src/mongo/db/commands/dbcheck.cpp @@ -536,18 +536,10 @@ public: virtual Status checkAuthForCommand(Client* client, const std::string& dbname, const BSONObj& cmdObj) const { - // For now, just use `find` permissions. - const NamespaceString nss(parseNs(dbname, cmdObj)); - - // First, check that we can read this collection. - Status status = AuthorizationSession::get(client)->checkAuthForFind(nss, false); - - if (!status.isOK()) { - return status; - } - - // Then check that we can read the health log. - return AuthorizationSession::get(client)->checkAuthForFind(HealthLog::nss, false); + const bool isAuthorized = + AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( + ResourcePattern::forAnyResource(), ActionType::dbCheck); + return isAuthorized ? Status::OK() : Status(ErrorCodes::Unauthorized, "Unauthorized"); } virtual bool run(OperationContext* opCtx, @@ -565,8 +557,7 @@ public: result.append("ok", true); return true; } -}; +} dbCheckCmd; -MONGO_REGISTER_TEST_COMMAND(DbCheckCmd); } // namespace } // namespace mongo |