summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosef Ahmad <josef.ahmad@mongodb.com>2021-12-15 11:30:22 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-12-21 13:33:45 +0000
commitba133ee0044dad667cbdb697ff89958b6fce1957 (patch)
treeb6ddc07d0a4d9aed4926b8e4293b43cb4dfe6467
parent481e16fd5be189f9d4cf2cff212a46a73f70da29 (diff)
downloadmongo-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.js49
-rw-r--r--src/mongo/db/auth/action_types.txt1
-rw-r--r--src/mongo/db/auth/role_graph_builtin_roles.cpp7
-rw-r--r--src/mongo/db/commands/dbcheck.cpp19
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