diff options
author | Sara Golemon <sara.golemon@mongodb.com> | 2022-09-26 14:56:04 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-10-05 15:25:09 +0000 |
commit | 27d9725cf5272c63b412588a061e1dae0f65e682 (patch) | |
tree | c14538f5f1c27be8995c325fef49eecaa400d9ee | |
parent | fed2a61d2bfaaaa5183caa2d67df5b68d27e4080 (diff) | |
download | mongo-27d9725cf5272c63b412588a061e1dae0f65e682.tar.gz |
SERVER-70147 Migrate addRequiredPrivileges to checkAuthForOperation
69 files changed, 772 insertions, 473 deletions
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp index 24ef5e32b36..e3371fde4e4 100644 --- a/src/mongo/db/commands.cpp +++ b/src/mongo/db/commands.cpp @@ -994,18 +994,6 @@ Status BasicCommandWithReplyBuilderInterface::explain(OperationContext* opCtx, return {ErrorCodes::IllegalOperation, str::stream() << "Cannot explain cmd: " << getName()}; } -Status BasicCommandWithReplyBuilderInterface::checkAuthForOperation(OperationContext* opCtx, - const DatabaseName& dbName, - const BSONObj& cmdObj) const { - std::vector<Privilege> privileges; - this->addRequiredPrivileges(dbName.db(), cmdObj, &privileges); - if (!AuthorizationSession::get(opCtx->getClient())->isAuthorizedForPrivileges(privileges)) { - return {ErrorCodes::Unauthorized, "unauthorized"}; - } - - return Status::OK(); -} - void Command::generateHelpResponse(OperationContext* opCtx, rpc::ReplyBuilderInterface* replyBuilder, const Command& command) { diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index 3e5b9d7d4e4..1f151f58435 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -902,11 +902,13 @@ public: /** * Checks if the client associated with the given OperationContext is authorized to run this - * command. Default implementation checks via addRequiredPrivileges(). + * command. + * Command imlpementations MUST provide a method here, even if no authz checks are required. + * Such commands should return Status::OK(), with a comment stating "No auth required". */ virtual Status checkAuthForOperation(OperationContext* opCtx, const DatabaseName& dbName, - const BSONObj& cmdObj) const; + const BSONObj& cmdObj) const = 0; /** * supportsWriteConcern returns true if this command should be parsed for a writeConcern @@ -969,22 +971,6 @@ public: private: std::unique_ptr<CommandInvocation> parse(OperationContext* opCtx, const OpMsgRequest& request) final; - - // - // Deprecated virtual methods. - // - - /** - * Appends to "*out" the privileges required to run this command on database "dbname" with - * the invocation described by "cmdObj". New commands shouldn't implement this, they should - * implement checkAuthForOperation (which takes an OperationContext*), instead. - */ - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - // The default implementation of addRequiredPrivileges should never be hit. - fassertFailed(16940); - } }; /** diff --git a/src/mongo/db/commands/authentication_commands.cpp b/src/mongo/db/commands/authentication_commands.cpp index 826bc6b23a0..b8af6c12551 100644 --- a/src/mongo/db/commands/authentication_commands.cpp +++ b/src/mongo/db/commands/authentication_commands.cpp @@ -113,11 +113,13 @@ public: bool requiresAuth() const override { return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const final { + + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { // No auth required since this command was explicitly part // of an authentication workflow. + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/db/commands/collection_to_capped.cpp b/src/mongo/db/commands/collection_to_capped.cpp index 456c76ceb13..c709a7b2617 100644 --- a/src/mongo/db/commands/collection_to_capped.cpp +++ b/src/mongo/db/commands/collection_to_capped.cpp @@ -30,6 +30,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/catalog/capped_utils.h" #include "mongo/db/client.h" #include "mongo/db/commands.h" @@ -50,34 +51,40 @@ public: AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + + bool supportsWriteConcern(const BSONObj& cmd) const override { return true; } + std::string help() const override { return "{ cloneCollectionAsCapped:<fromName>, toCollection:<toName>, size:<sizeInBytes> }"; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet sourceActions; - sourceActions.addAction(ActionType::find); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), sourceActions)); - - ActionSet targetActions; - targetActions.addAction(ActionType::insert); - targetActions.addAction(ActionType::createIndex); - targetActions.addAction(ActionType::convertToCapped); + + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::find)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } const auto nssElt = cmdObj["toCollection"]; uassert(ErrorCodes::TypeMismatch, "'toCollection' must be of type String", nssElt.type() == BSONType::String); - const NamespaceString nss(dbname, nssElt.valueStringData()); + const NamespaceString nss(dbName, nssElt.valueStringData()); uassert(ErrorCodes::InvalidNamespace, str::stream() << "Invalid target namespace: " << nss.ns(), nss.isValid()); - out->push_back(Privilege(ResourcePattern::forExactNamespace(nss), targetActions)); + if (!as->isAuthorizedForActionsOnResource( + ResourcePattern::forExactNamespace(nss), + {ActionType::insert, ActionType::createIndex, ActionType::convertToCapped})) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, @@ -154,12 +161,17 @@ public: std::string help() const override { return "{ convertToCapped:<fromCollectionName>, size:<sizeInBytes> }"; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::convertToCapped); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::convertToCapped)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/db/commands/compact.cpp b/src/mongo/db/commands/compact.cpp index e20e9905b19..db2e6ecf75f 100644 --- a/src/mongo/db/commands/compact.cpp +++ b/src/mongo/db/commands/compact.cpp @@ -49,22 +49,30 @@ using std::stringstream; class CompactCmd : public BasicCommand { public: - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } - virtual bool adminOnly() const { + + bool adminOnly() const override { return false; } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::compact); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::compact)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } + std::string help() const override { return "compact collection\n" "warning: this operation locks the database and is slow. you can cancel with " @@ -72,6 +80,7 @@ public: "{ compact : <collection_name>, [force:<bool>] }\n" " force - allows to run on a replica set primary\n"; } + CompactCmd() : BasicCommand("compact") {} bool run(OperationContext* opCtx, diff --git a/src/mongo/db/commands/conn_pool_stats.cpp b/src/mongo/db/commands/conn_pool_stats.cpp index 25c0a385952..da62689917c 100644 --- a/src/mongo/db/commands/conn_pool_stats.cpp +++ b/src/mongo/db/commands/conn_pool_stats.cpp @@ -36,6 +36,7 @@ #include "mongo/client/connpool.h" #include "mongo/client/dbclient_connection.h" #include "mongo/client/global_conn_pool.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/repl/replication_coordinator.h" #include "mongo/executor/connection_pool_stats.h" @@ -62,12 +63,16 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::connPoolStats); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::connPoolStats)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/db/commands/conn_pool_sync.cpp b/src/mongo/db/commands/conn_pool_sync.cpp index 2111ec42931..e83a4ef41d3 100644 --- a/src/mongo/db/commands/conn_pool_sync.cpp +++ b/src/mongo/db/commands/conn_pool_sync.cpp @@ -30,6 +30,7 @@ #include "mongo/platform/basic.h" #include "mongo/client/global_conn_pool.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" namespace mongo { @@ -51,12 +52,16 @@ public: return AllowedOnSecondary::kAlways; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::connPoolSync); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::connPoolSync)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/db/commands/cpuload.cpp b/src/mongo/db/commands/cpuload.cpp index 7699275426b..532354d7d4e 100644 --- a/src/mongo/db/commands/cpuload.cpp +++ b/src/mongo/db/commands/cpuload.cpp @@ -45,13 +45,16 @@ public: AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } + virtual bool isWriteCommandForConfigServer() const { return false; } + bool skipApiVersionCheck() const override { // Internal command (server to server). return true; } + std::string help() const override { return "internal. for testing only." "{ cpuload : 1, cpuFactor : 1 } Runs a straight CPU load. Length of execution " @@ -59,13 +62,17 @@ public: "Useful for testing the stability of the performance of the underlying system," "by running the command repeatedly and observing the variation in execution time."; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const {} // No auth required - virtual bool run(OperationContext* txn, - const DatabaseName&, - const BSONObj& cmdObj, - BSONObjBuilder& result) { + + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required + } + + bool run(OperationContext* txn, + const DatabaseName&, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { double cpuFactor = 1; if (cmdObj["cpuFactor"].isNumber()) { cpuFactor = cmdObj["cpuFactor"].number(); diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp index 19fd21c513e..9d134a12685 100644 --- a/src/mongo/db/commands/dbcommands.cpp +++ b/src/mongo/db/commands/dbcommands.cpp @@ -729,9 +729,12 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const final {} // No auth required + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); + } + std::string help() const final { return "get version #, etc.\n" "{ buildinfo:1 }"; diff --git a/src/mongo/db/commands/dbcommands_d.cpp b/src/mongo/db/commands/dbcommands_d.cpp index b1596fdc81b..86aebefde31 100644 --- a/src/mongo/db/commands/dbcommands_d.cpp +++ b/src/mongo/db/commands/dbcommands_d.cpp @@ -217,7 +217,7 @@ public: } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } @@ -225,8 +225,7 @@ public: return true; } - virtual NamespaceString parseNs(const DatabaseName& dbName, - const BSONObj& cmdObj) const override { + NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { std::string collectionName; if (const auto rootElt = cmdObj["root"]) { uassert(ErrorCodes::InvalidNamespace, @@ -240,16 +239,22 @@ public: return NamespaceString(dbName, collectionName); } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), ActionType::find)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::find)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, const DatabaseName& dbName, const BSONObj& jsobj, - BSONObjBuilder& result) { + BSONObjBuilder& result) override { const NamespaceString nss(parseNs(dbName, jsobj)); md5digest d; diff --git a/src/mongo/db/commands/dbhash.cpp b/src/mongo/db/commands/dbhash.cpp index 627e2fe4d86..442c3fe728d 100644 --- a/src/mongo/db/commands/dbhash.cpp +++ b/src/mongo/db/commands/dbhash.cpp @@ -106,12 +106,16 @@ public: kDefaultReadConcernNotPermitted}; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::dbHash); - out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(dbName.db()), + ActionType::dbHash)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/db/commands/driverHelpers.cpp b/src/mongo/db/commands/driverHelpers.cpp index f6db10738db..7328eab0633 100644 --- a/src/mongo/db/commands/driverHelpers.cpp +++ b/src/mongo/db/commands/driverHelpers.cpp @@ -67,9 +67,13 @@ public: class ObjectIdTest : public BasicDriverHelper { public: ObjectIdTest() : BasicDriverHelper("driverOIDTest") {} - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const {} // No auth required + + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required + } + bool run(OperationContext* opCtx, const DatabaseName& dbName, const BSONObj& cmdObj, diff --git a/src/mongo/db/commands/drop_indexes.cpp b/src/mongo/db/commands/drop_indexes.cpp index 4d899e91c6f..46122c7fe5d 100644 --- a/src/mongo/db/commands/drop_indexes.cpp +++ b/src/mongo/db/commands/drop_indexes.cpp @@ -136,13 +136,19 @@ public: std::string help() const override { return "re-index a collection (can only be run on a standalone mongod)"; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::reIndex); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::reIndex)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } + CmdReIndex() : BasicCommand("reIndex") {} bool run(OperationContext* opCtx, diff --git a/src/mongo/db/commands/fail_point_cmd.cpp b/src/mongo/db/commands/fail_point_cmd.cpp index 00a2626e8cc..7e868735f5b 100644 --- a/src/mongo/db/commands/fail_point_cmd.cpp +++ b/src/mongo/db/commands/fail_point_cmd.cpp @@ -87,9 +87,11 @@ public: } // No auth needed because it only works when enabled via command line. - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override {} + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + return Status::OK(); + } std::string help() const override { return "modifies the settings of a fail point"; diff --git a/src/mongo/db/commands/fsync.cpp b/src/mongo/db/commands/fsync.cpp index f84b77bff5c..db6dd91ff33 100644 --- a/src/mongo/db/commands/fsync.cpp +++ b/src/mongo/db/commands/fsync.cpp @@ -108,24 +108,32 @@ public: } } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } - virtual bool adminOnly() const { + + bool adminOnly() const override { return true; } + std::string help() const override { return url(); } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::fsync); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::fsync)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/db/commands/generic.cpp b/src/mongo/db/commands/generic.cpp index f61ead33f83..c5f8dde7e74 100644 --- a/src/mongo/db/commands/generic.cpp +++ b/src/mongo/db/commands/generic.cpp @@ -148,26 +148,35 @@ public: std::string help() const override { return "get a list of all db commands"; } + ListCommandsCmd() : BasicCommand("listCommands") {} - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } - virtual bool adminOnly() const { + + bool adminOnly() const override { return false; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const {} // No auth required + + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required + } + bool requiresAuth() const final { return false; } - virtual bool run(OperationContext* opCtx, - const DatabaseName&, - const BSONObj& cmdObj, - BSONObjBuilder& result) { + + bool run(OperationContext* opCtx, + const DatabaseName&, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { // Sort the command names before building the result BSON. std::vector<Command*> commands; for (const auto& command : globalCommandRegistry()->allCommands()) { diff --git a/src/mongo/db/commands/get_last_error.cpp b/src/mongo/db/commands/get_last_error.cpp index 23d7d68e3ed..7ef994bd772 100644 --- a/src/mongo/db/commands/get_last_error.cpp +++ b/src/mongo/db/commands/get_last_error.cpp @@ -49,9 +49,12 @@ public: AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const {} // No auth required + + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); + } bool requiresAuth() const override { return false; diff --git a/src/mongo/db/commands/hashcmd.cpp b/src/mongo/db/commands/hashcmd.cpp index ff6335ec6dc..7caee184863 100644 --- a/src/mongo/db/commands/hashcmd.cpp +++ b/src/mongo/db/commands/hashcmd.cpp @@ -52,17 +52,23 @@ using std::stringstream; // Testing only, enabled via command-line. class CmdHashElt : public BasicCommand { public: - CmdHashElt() : BasicCommand("_hashBSONElement"){}; - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + CmdHashElt() : BasicCommand("_hashBSONElement") {} + + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } + // No auth needed because it only works when enabled via command line. - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const {} + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); + } + std::string help() const override { return "returns the hash of the first BSONElement val in a BSONObj"; } diff --git a/src/mongo/db/commands/isself.cpp b/src/mongo/db/commands/isself.cpp index 2139d822c03..04c10b43f18 100644 --- a/src/mongo/db/commands/isself.cpp +++ b/src/mongo/db/commands/isself.cpp @@ -44,22 +44,30 @@ public: AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } + bool skipApiVersionCheck() const override { // Internal command (server to server). return true; } + std::string help() const override { return "{ _isSelf : 1 } INTERNAL ONLY"; } + bool requiresAuth() const override { return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override {} + + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); + } + bool run(OperationContext* opCtx, const DatabaseName&, const BSONObj& cmdObj, diff --git a/src/mongo/db/commands/map_reduce_command_base.h b/src/mongo/db/commands/map_reduce_command_base.h index 48a9522e0d8..a235b9345da 100644 --- a/src/mongo/db/commands/map_reduce_command_base.h +++ b/src/mongo/db/commands/map_reduce_command_base.h @@ -82,10 +82,10 @@ public: return true; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - map_reduce_common::addPrivilegesRequiredForMapReduce(this, dbname, cmdObj, out); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + return map_reduce_common::checkAuthForMapReduce(this, opCtx, dbName, cmdObj); } virtual void _explainImpl(OperationContext* opCtx, diff --git a/src/mongo/db/commands/mr_common.cpp b/src/mongo/db/commands/mr_common.cpp index 0cc2b224bf2..a75b69b9549 100644 --- a/src/mongo/db/commands/mr_common.cpp +++ b/src/mongo/db/commands/mr_common.cpp @@ -34,6 +34,7 @@ #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/privilege.h" #include "mongo/db/catalog/document_validation.h" #include "mongo/db/commands.h" @@ -330,18 +331,22 @@ OutputOptions parseOutputOptions(const std::string& dbname, const BSONObj& cmdOb return outputOptions; } -void addPrivilegesRequiredForMapReduce(const BasicCommand* commandTemplate, - const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { - OutputOptions outputOptions = parseOutputOptions(dbname, cmdObj); +Status checkAuthForMapReduce(const BasicCommand* commandTemplate, + OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) { + OutputOptions outputOptions = parseOutputOptions(dbName.db(), cmdObj); - ResourcePattern inputResource(commandTemplate->parseResourcePattern(dbname, cmdObj)); + ResourcePattern inputResource(commandTemplate->parseResourcePattern(dbName.db(), cmdObj)); uassert(ErrorCodes::InvalidNamespace, str::stream() << "Invalid input namespace " << inputResource.databaseToMatch() << "." << cmdObj["mapReduce"].String(), inputResource.isExactNamespacePattern()); - out->push_back(Privilege(inputResource, ActionType::find)); + + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(inputResource, ActionType::find)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } if (outputOptions.outType != OutputType::InMemory) { ActionSet outputActions; @@ -363,8 +368,12 @@ void addPrivilegesRequiredForMapReduce(const BasicCommand* commandTemplate, outputResource.ns().isValid()); // TODO: check if outputNs exists and add createCollection privilege if not - out->push_back(Privilege(outputResource, outputActions)); + if (!as->isAuthorizedForActionsOnResource(outputResource, outputActions)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } } + + return Status::OK(); } bool mrSupportsWriteConcern(const BSONObj& cmd) { diff --git a/src/mongo/db/commands/mr_common.h b/src/mongo/db/commands/mr_common.h index 344d819841f..965553e9ca8 100644 --- a/src/mongo/db/commands/mr_common.h +++ b/src/mongo/db/commands/mr_common.h @@ -51,10 +51,10 @@ struct OutputOptions { OutputOptions parseOutputOptions(const std::string& dbname, const BSONObj& cmdObj); -void addPrivilegesRequiredForMapReduce(const BasicCommand* commandTemplate, - const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out); +Status checkAuthForMapReduce(const BasicCommand* command, + OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj); /** * Returns true if the provided mapReduce command has an 'out' parameter. diff --git a/src/mongo/db/commands/parameters.cpp b/src/mongo/db/commands/parameters.cpp index 574f47e91bb..0cfb0f6dcf2 100644 --- a/src/mongo/db/commands/parameters.cpp +++ b/src/mongo/db/commands/parameters.cpp @@ -35,6 +35,7 @@ #include "mongo/client/replica_set_monitor.h" #include "mongo/config.h" #include "mongo/db/auth/authorization_manager.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/commands/parameters_gen.h" #include "mongo/db/commands/parse_log_component_settings.h" @@ -206,19 +207,27 @@ public: AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } - virtual bool adminOnly() const { + + bool adminOnly() const override { return true; } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::getParameter); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::getParameter)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } + std::string help() const override { std::string h = "get administrative option(s)\nexample:\n" @@ -265,19 +274,27 @@ public: AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } - virtual bool adminOnly() const { + + bool adminOnly() const override { return true; } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::setParameter); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::setParameter)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } + std::string help() const override { std::string h = "set administrative option(s)\n" diff --git a/src/mongo/db/commands/server_status.h b/src/mongo/db/commands/server_status.h index d5f08eef962..1d10d805968 100644 --- a/src/mongo/db/commands/server_status.h +++ b/src/mongo/db/commands/server_status.h @@ -65,10 +65,12 @@ public: virtual bool includeByDefault() const = 0; /** - * Adds the privileges that are required to view this section + * Perform authorization checks required to show this status section. * TODO: Remove this empty default implementation and implement for every section. */ - virtual void addRequiredPrivileges(std::vector<Privilege>* out){}; + virtual Status checkAuthForOperation(OperationContext* opCtx) const { + return Status::OK(); + } /** * actually generate the result diff --git a/src/mongo/db/commands/server_status_command.cpp b/src/mongo/db/commands/server_status_command.cpp index f1dbbcea879..62433e57e62 100644 --- a/src/mongo/db/commands/server_status_command.cpp +++ b/src/mongo/db/commands/server_status_command.cpp @@ -66,16 +66,20 @@ public: "retrieve all server status sections."; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const final { - ActionSet actions; - actions.addAction(ActionType::serverStatus); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::serverStatus)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, - const DatabaseName&, + const DatabaseName& dbName, const BSONObj& cmdObj, BSONObjBuilder& result) final { const auto service = opCtx->getServiceContext(); @@ -83,8 +87,6 @@ public: const auto runStart = clock->now(); BSONObjBuilder timeBuilder(256); - const auto authSession = AuthorizationSession::get(Client::getCurrent()); - // This command is important to observability, and like FTDC, does not need to acquire the // PBWM lock to return correct results. ShouldNotConflictWithSecondaryBatchApplicationBlock noPBWMBlock(opCtx->lockState()); @@ -115,10 +117,9 @@ public: for (auto i = registry->begin(); i != registry->end(); ++i) { ServerStatusSection* section = i->second; - std::vector<Privilege> requiredPrivileges; - section->addRequiredPrivileges(&requiredPrivileges); - if (!authSession->isAuthorizedForPrivileges(requiredPrivileges)) + if (!section->checkAuthForOperation(opCtx).isOK()) { continue; + } bool include = section->includeByDefault(); const auto& elem = cmdObj[section->getSectionName()]; @@ -264,8 +265,6 @@ public: return false; } - void addRequiredPrivileges(std::vector<Privilege>* out) final {} - BSONObj generateSection(OperationContext*, const BSONElement& configElement) const final { return HttpClient::getServerStatus(); } diff --git a/src/mongo/db/commands/shutdown.h b/src/mongo/db/commands/shutdown.h index 757f14b432c..446c78632e0 100644 --- a/src/mongo/db/commands/shutdown.h +++ b/src/mongo/db/commands/shutdown.h @@ -114,13 +114,6 @@ public: Command::AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return Command::AllowedOnSecondary::kAlways; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::shutdown); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); - } }; } // namespace mongo diff --git a/src/mongo/db/commands/sleep_command.cpp b/src/mongo/db/commands/sleep_command.cpp index efee82ad827..159a57e213f 100644 --- a/src/mongo/db/commands/sleep_command.cpp +++ b/src/mongo/db/commands/sleep_command.cpp @@ -66,9 +66,11 @@ public: } // No auth needed because it only works when enabled via command line. - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const {} + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); + } /** * An empty 'ns' causes the global lock to be taken. diff --git a/src/mongo/db/commands/test_api_version_2_commands.cpp b/src/mongo/db/commands/test_api_version_2_commands.cpp index be228e1afe3..713b5aacebd 100644 --- a/src/mongo/db/commands/test_api_version_2_commands.cpp +++ b/src/mongo/db/commands/test_api_version_2_commands.cpp @@ -51,6 +51,12 @@ public: return false; } + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required + } + bool run(OperationContext* opCtx, const DatabaseName&, const BSONObj& cmdObj, @@ -77,6 +83,12 @@ public: return false; } + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required + } + bool run(OperationContext* opCtx, const DatabaseName&, const BSONObj& cmdObj, @@ -107,6 +119,12 @@ public: return false; } + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required + } + bool run(OperationContext* opCtx, const DatabaseName&, const BSONObj& cmdObj, @@ -133,6 +151,12 @@ public: return false; } + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required + } + bool run(OperationContext* opCtx, const DatabaseName&, const BSONObj& cmdObj, diff --git a/src/mongo/db/commands/test_commands.cpp b/src/mongo/db/commands/test_commands.cpp index 5cedacf760f..4cea5de379d 100644 --- a/src/mongo/db/commands/test_commands.cpp +++ b/src/mongo/db/commands/test_commands.cpp @@ -64,19 +64,25 @@ using std::stringstream; class GodInsert : public BasicCommand { public: GodInsert() : BasicCommand("godinsert") {} - virtual bool adminOnly() const { + bool adminOnly() const override { return false; } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + + bool supportsWriteConcern(const BSONObj& cmd) const override { return true; } + // No auth needed because it only works when enabled via command line. - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const {} + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); + } + std::string help() const override { return "internal. for testing only."; } @@ -120,20 +126,26 @@ MONGO_REGISTER_TEST_COMMAND(GodInsert); class CapTrunc : public BasicCommand { public: CapTrunc() : BasicCommand("captrunc") {} + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + + bool supportsWriteConcern(const BSONObj& cmd) const override { return true; } + // No auth needed because it only works when enabled via command line. - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const {} - virtual bool run(OperationContext* opCtx, - const DatabaseName& dbName, - const BSONObj& cmdObj, - BSONObjBuilder& result) { + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); + } + + bool run(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { const NamespaceString fullNs = CommandHelpers::parseNsCollectionRequired(dbName, cmdObj); if (!fullNs.isValid()) { uasserted(ErrorCodes::InvalidNamespace, @@ -195,18 +207,22 @@ public: AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + + bool supportsWriteConcern(const BSONObj& cmd) const override { return true; } + // No auth needed because it only works when enabled via command line. - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const {} - - virtual bool run(OperationContext* opCtx, - const DatabaseName& dbName, - const BSONObj& cmdObj, - BSONObjBuilder& result) { + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); + } + + bool run(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { const NamespaceString nss = CommandHelpers::parseNsCollectionRequired(dbName, cmdObj); uassertStatusOK(emptyCapped(opCtx, nss)); @@ -237,9 +253,11 @@ public: } // No auth needed because it only works when enabled via command line. - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override {} + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); + } std::string help() const override { return "pins the oldest timestamp"; diff --git a/src/mongo/db/commands/test_deprecation_command.cpp b/src/mongo/db/commands/test_deprecation_command.cpp index 4e4362322ed..bdf5c0d0a4e 100644 --- a/src/mongo/db/commands/test_deprecation_command.cpp +++ b/src/mongo/db/commands/test_deprecation_command.cpp @@ -60,9 +60,11 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override {} + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); + } std::string help() const override { return "replies with the values of the OperationContext's API parameters"; diff --git a/src/mongo/db/commands/top_command.cpp b/src/mongo/db/commands/top_command.cpp index bea0c20f800..0eadc4fdecf 100644 --- a/src/mongo/db/commands/top_command.cpp +++ b/src/mongo/db/commands/top_command.cpp @@ -32,6 +32,7 @@ #include "mongo/base/init.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/privilege.h" #include "mongo/db/client.h" #include "mongo/db/commands.h" @@ -50,26 +51,35 @@ public: AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } - virtual bool adminOnly() const { + + bool adminOnly() const override { return true; } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } + std::string help() const override { return "usage by collection, in micros "; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::top); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::top)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } - virtual bool run(OperationContext* opCtx, - const DatabaseName&, - const BSONObj& cmdObj, - BSONObjBuilder& result) { + + bool run(OperationContext* opCtx, + const DatabaseName&, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { { BSONObjBuilder b(result.subobjStart("totals")); b.append("note", "all times in microseconds"); diff --git a/src/mongo/db/commands/validate.cpp b/src/mongo/db/commands/validate.cpp index 832f2f8f6e0..ed81cd48eab 100644 --- a/src/mongo/db/commands/validate.cpp +++ b/src/mongo/db/commands/validate.cpp @@ -30,6 +30,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/collection_validation.h" #include "mongo/db/client.h" @@ -113,12 +114,16 @@ public: return false; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::validate); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::validate)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/db/commands/whats_my_sni_command.cpp b/src/mongo/db/commands/whats_my_sni_command.cpp index f0d1838b312..3073fdfa033 100644 --- a/src/mongo/db/commands/whats_my_sni_command.cpp +++ b/src/mongo/db/commands/whats_my_sni_command.cpp @@ -70,9 +70,11 @@ public: return AllowedOnSecondary::kAlways; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override {} + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); + } }; MONGO_REGISTER_TEST_COMMAND(CmdWhatsMySNI) diff --git a/src/mongo/db/commands/whats_my_uri_cmd.cpp b/src/mongo/db/commands/whats_my_uri_cmd.cpp index 33634534444..e791d492a7b 100644 --- a/src/mongo/db/commands/whats_my_uri_cmd.cpp +++ b/src/mongo/db/commands/whats_my_uri_cmd.cpp @@ -55,9 +55,11 @@ public: return "{whatsmyuri:1}"; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override {} // No auth required + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + return Status::OK(); // No auth required + } bool run(OperationContext* opCtx, const DatabaseName&, diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp index 3d52323be75..8c909acffdf 100644 --- a/src/mongo/db/exec/stagedebug_cmd.cpp +++ b/src/mongo/db/exec/stagedebug_cmd.cpp @@ -116,11 +116,12 @@ public: return {}; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - // Command is testing-only, and can only be enabled at command line. Hence, no auth - // check needed. + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + // Command is testing-only, and can only be enabled at command line. + // Hence, no auth check needed. + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/db/free_mon/free_mon_status.cpp b/src/mongo/db/free_mon/free_mon_status.cpp index dc201956a8d..5d69473ea5e 100644 --- a/src/mongo/db/free_mon/free_mon_status.cpp +++ b/src/mongo/db/free_mon/free_mon_status.cpp @@ -29,6 +29,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands/server_status.h" #include "mongo/db/free_mon/free_mon_controller.h" #include "mongo/db/free_mon/free_mon_options.h" @@ -44,9 +45,14 @@ public: return true; } - void addRequiredPrivileges(std::vector<Privilege>* out) final { - out->push_back(Privilege(ResourcePattern::forClusterResource(), - ActionType::checkFreeMonitoringStatus)); + Status checkAuthForOperation(OperationContext* opCtx) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::checkFreeMonitoringStatus)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } BSONObj generateSection(OperationContext* opCtx, const BSONElement& configElement) const final { diff --git a/src/mongo/db/index/index_access_method.cpp b/src/mongo/db/index/index_access_method.cpp index a3ef4649369..bdc0db61e8d 100644 --- a/src/mongo/db/index/index_access_method.cpp +++ b/src/mongo/db/index/index_access_method.cpp @@ -92,8 +92,6 @@ public: return true; } - void addRequiredPrivileges(std::vector<Privilege>* out) final {} - BSONObj generateSection(OperationContext* opCtx, const BSONElement& configElement) const final { BSONObjBuilder builder; builder.append("count", count.loadRelaxed()); diff --git a/src/mongo/db/index_builds_coordinator.h b/src/mongo/db/index_builds_coordinator.h index 9431f157bee..bff4df93c56 100644 --- a/src/mongo/db/index_builds_coordinator.h +++ b/src/mongo/db/index_builds_coordinator.h @@ -497,8 +497,6 @@ public: return true; } - void addRequiredPrivileges(std::vector<Privilege>* out) final {} - BSONObj generateSection(OperationContext* opCtx, const BSONElement& configElement) const final { BSONObjBuilder indexBuilds; diff --git a/src/mongo/db/repl/replication_info.cpp b/src/mongo/db/repl/replication_info.cpp index 3cd9fa9c591..aa442ee1465 100644 --- a/src/mongo/db/repl/replication_info.cpp +++ b/src/mongo/db/repl/replication_info.cpp @@ -338,9 +338,11 @@ public: {kImplicitDefaultReadConcernNotPermitted}}; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const final {} // No auth required + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required + } bool runWithReplyBuilder(OperationContext* opCtx, const DatabaseName& dbName, diff --git a/src/mongo/db/s/check_sharding_index_command.cpp b/src/mongo/db/s/check_sharding_index_command.cpp index 79db79a2b56..9c642d8f6de 100644 --- a/src/mongo/db/s/check_sharding_index_command.cpp +++ b/src/mongo/db/s/check_sharding_index_command.cpp @@ -30,6 +30,7 @@ #include "mongo/platform/basic.h" #include "mongo/db/auth/action_type.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/privilege.h" #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/commands.h" @@ -58,12 +59,16 @@ public: return AllowedOnSecondary::kNever; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::find); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::find)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { diff --git a/src/mongo/db/s/cluster_count_cmd_d.cpp b/src/mongo/db/s/cluster_count_cmd_d.cpp index e291ec2ee29..27c64148cc9 100644 --- a/src/mongo/db/s/cluster_count_cmd_d.cpp +++ b/src/mongo/db/s/cluster_count_cmd_d.cpp @@ -27,6 +27,7 @@ * it in the license file. */ +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/s/sharding_state.h" #include "mongo/s/commands/cluster_count_cmd.h" #include "mongo/s/grid.h" @@ -44,12 +45,14 @@ struct ClusterCountCmdD { return kNoApiVersions; } - static void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { - ActionSet actions; - actions.addAction(ActionType::internal); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + static Status checkAuthForOperation(OperationContext* opCtx) { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::internal)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } static void checkCanRunHere(OperationContext* opCtx) { diff --git a/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp b/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp index 7f64c9614ad..8bb1cde264d 100644 --- a/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp +++ b/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp @@ -146,12 +146,16 @@ public: return true; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::internal); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::internal)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, @@ -213,12 +217,16 @@ public: return true; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::internal); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::internal)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, @@ -255,7 +263,7 @@ public: return "internal"; } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } @@ -263,16 +271,20 @@ public: return AllowedOnSecondary::kNever; } - virtual bool adminOnly() const { + bool adminOnly() const override { return true; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::internal); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::internal)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } /** diff --git a/src/mongo/db/s/migration_destination_manager_legacy_commands.cpp b/src/mongo/db/s/migration_destination_manager_legacy_commands.cpp index 6e820d5bef0..f0dfc08b1c1 100644 --- a/src/mongo/db/s/migration_destination_manager_legacy_commands.cpp +++ b/src/mongo/db/s/migration_destination_manager_legacy_commands.cpp @@ -80,12 +80,16 @@ public: return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::internal); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::internal)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool supportsRetryableWrite() const final { @@ -181,12 +185,16 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::internal); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::internal)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, @@ -226,16 +234,20 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::internal); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::internal)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, - const DatabaseName& dbname, + const DatabaseName& dbName, const BSONObj& cmdObj, BSONObjBuilder& result) override { auto const sessionId = uassertStatusOK(MigrationSessionId::extractFromBSON(cmdObj)); @@ -280,12 +292,16 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::internal); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::internal)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, @@ -338,12 +354,16 @@ public: return true; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::internal); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::internal)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/db/s/sharding_state_command.cpp b/src/mongo/db/s/sharding_state_command.cpp index c9f43ea3e0f..e2e52c5efc5 100644 --- a/src/mongo/db/s/sharding_state_command.cpp +++ b/src/mongo/db/s/sharding_state_command.cpp @@ -32,6 +32,7 @@ #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/privilege.h" #include "mongo/db/commands.h" #include "mongo/db/s/collection_sharding_state.h" @@ -60,12 +61,16 @@ public: return true; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::shardingState); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::shardingState)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/embedded/embedded_ismaster.cpp b/src/mongo/embedded/embedded_ismaster.cpp index 3894f9b83d5..bcd5089523b 100644 --- a/src/mongo/embedded/embedded_ismaster.cpp +++ b/src/mongo/embedded/embedded_ismaster.cpp @@ -60,9 +60,11 @@ public: return false; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const {} // No auth required + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required + } CmdIsMaster() : BasicCommand("isMaster", "ismaster") {} diff --git a/src/mongo/s/commands/cluster_add_shard_cmd.cpp b/src/mongo/s/commands/cluster_add_shard_cmd.cpp index 9b7e013accd..9c059c51e59 100644 --- a/src/mongo/s/commands/cluster_add_shard_cmd.cpp +++ b/src/mongo/s/commands/cluster_add_shard_cmd.cpp @@ -30,6 +30,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/grid.h" @@ -65,12 +66,16 @@ public: return "add a new shard to the system"; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::addShard); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::addShard)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_build_info.cpp b/src/mongo/s/commands/cluster_build_info.cpp index c946ab8e6af..18abb7c950b 100644 --- a/src/mongo/s/commands/cluster_build_info.cpp +++ b/src/mongo/s/commands/cluster_build_info.cpp @@ -90,9 +90,11 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const final {} // No auth required + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required + } std::string help() const final { return "get version #, etc.\n" diff --git a/src/mongo/s/commands/cluster_coll_stats_cmd.cpp b/src/mongo/s/commands/cluster_coll_stats_cmd.cpp index 25b3e15b578..b33da24608f 100644 --- a/src/mongo/s/commands/cluster_coll_stats_cmd.cpp +++ b/src/mongo/s/commands/cluster_coll_stats_cmd.cpp @@ -30,6 +30,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/timeseries/timeseries_commands_conversion_helper.h" #include "mongo/logv2/log.h" @@ -182,12 +183,16 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::collStats); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::collStats)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_compact_cmd.cpp b/src/mongo/s/commands/cluster_compact_cmd.cpp index 055e8d81688..e53ce4ef780 100644 --- a/src/mongo/s/commands/cluster_compact_cmd.cpp +++ b/src/mongo/s/commands/cluster_compact_cmd.cpp @@ -29,6 +29,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" namespace mongo { @@ -46,12 +47,16 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::compact); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::compact)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool supportsWriteConcern(const BSONObj& cmd) const override { diff --git a/src/mongo/s/commands/cluster_convert_to_capped_cmd.cpp b/src/mongo/s/commands/cluster_convert_to_capped_cmd.cpp index 35f7e9d9701..a34450631fb 100644 --- a/src/mongo/s/commands/cluster_convert_to_capped_cmd.cpp +++ b/src/mongo/s/commands/cluster_convert_to_capped_cmd.cpp @@ -91,12 +91,16 @@ public: return CommandHelpers::parseNsCollectionRequired(dbName, cmdObj); } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::convertToCapped); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::convertToCapped)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_count_cmd.h b/src/mongo/s/commands/cluster_count_cmd.h index 32aae8fb5f6..d90421f550f 100644 --- a/src/mongo/s/commands/cluster_count_cmd.h +++ b/src/mongo/s/commands/cluster_count_cmd.h @@ -32,6 +32,7 @@ #include <vector> #include "mongo/bson/util/bson_extract.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/fle_crud.h" #include "mongo/db/query/count_command_as_aggregation_command.h" @@ -86,13 +87,16 @@ public: Status::OK()}; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::find); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); - Impl::addRequiredPrivileges(dbname, cmdObj, out); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::find)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Impl::checkAuthForOperation(opCtx); } bool errmsgRun(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_count_cmd_s.cpp b/src/mongo/s/commands/cluster_count_cmd_s.cpp index d177d19d5ec..4226d06a189 100644 --- a/src/mongo/s/commands/cluster_count_cmd_s.cpp +++ b/src/mongo/s/commands/cluster_count_cmd_s.cpp @@ -42,10 +42,9 @@ struct ClusterCountCmdS { return kApiVersions1; } - static void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { + static Status checkAuthForOperation(OperationContext*) { // No additional required privileges on a mongos. + return Status::OK(); } static void checkCanRunHere(OperationContext* opCtx) { diff --git a/src/mongo/s/commands/cluster_create_indexes_cmd.cpp b/src/mongo/s/commands/cluster_create_indexes_cmd.cpp index 3a56ea99141..7699a802d01 100644 --- a/src/mongo/s/commands/cluster_create_indexes_cmd.cpp +++ b/src/mongo/s/commands/cluster_create_indexes_cmd.cpp @@ -68,10 +68,16 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const final { - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), ActionType::createIndex)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::createIndex)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool supportsWriteConcern(const BSONObj& cmd) const final { diff --git a/src/mongo/s/commands/cluster_distinct_cmd.cpp b/src/mongo/s/commands/cluster_distinct_cmd.cpp index a4690c8c4db..1bcddd4aa80 100644 --- a/src/mongo/s/commands/cluster_distinct_cmd.cpp +++ b/src/mongo/s/commands/cluster_distinct_cmd.cpp @@ -31,6 +31,7 @@ #include "mongo/platform/basic.h" #include "mongo/bson/bsonobj_comparator.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/query/collation/collator_factory_interface.h" #include "mongo/db/query/parsed_distinct.h" @@ -89,12 +90,16 @@ public: return ReadConcernSupportResult::allSupportedAndDefaultPermitted(); } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::find); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::find)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool allowedInTransactions() const final { diff --git a/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp b/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp index 45b20abae15..076b8a1d61d 100644 --- a/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp +++ b/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp @@ -30,6 +30,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/logv2/log.h" #include "mongo/rpc/get_status_from_command_result.h" @@ -62,12 +63,16 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::dropIndex); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::dropIndex)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } void validateResult(const BSONObj& resultObj) final { diff --git a/src/mongo/s/commands/cluster_filemd5_cmd.cpp b/src/mongo/s/commands/cluster_filemd5_cmd.cpp index 3922205749c..600f41ba3bd 100644 --- a/src/mongo/s/commands/cluster_filemd5_cmd.cpp +++ b/src/mongo/s/commands/cluster_filemd5_cmd.cpp @@ -30,6 +30,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/rpc/get_status_from_command_result.h" #include "mongo/s/cluster_commands_helpers.h" @@ -71,10 +72,16 @@ public: return NamespaceString(dbName, collectionName); } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), ActionType::find)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::find)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool supportsWriteConcern(const BSONObj& cmd) const override { diff --git a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp index d373c9d753b..e51c61b3acc 100644 --- a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp @@ -347,12 +347,12 @@ public: {{ErrorCodes::InvalidOptions, "default read concern not permitted"}}}; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - bool update = cmdObj["update"].trueValue(); - bool upsert = cmdObj["upsert"].trueValue(); - bool remove = cmdObj["remove"].trueValue(); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + const bool update = cmdObj["update"].trueValue(); + const bool upsert = cmdObj["upsert"].trueValue(); + const bool remove = cmdObj["remove"].trueValue(); ActionSet actions; actions.addAction(ActionType::find); @@ -369,12 +369,18 @@ public: actions.addAction(ActionType::bypassDocumentValidation); } - std::string ns = CommandHelpers::parseNsFromCommand(dbname, cmdObj); - ResourcePattern resource(CommandHelpers::resourcePatternForNamespace(ns)); + auto nss = CommandHelpers::parseNsFromCommand(dbName, cmdObj); + ResourcePattern resource(CommandHelpers::resourcePatternForNamespace(nss.ns())); uassert(17137, "Invalid target namespace " + resource.toString(), resource.isExactNamespacePattern()); - out->push_back(Privilege(resource, actions)); + + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(resource, actions)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } Status explain(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_fsync_cmd.cpp b/src/mongo/s/commands/cluster_fsync_cmd.cpp index 00972e17815..b79193f2b65 100644 --- a/src/mongo/s/commands/cluster_fsync_cmd.cpp +++ b/src/mongo/s/commands/cluster_fsync_cmd.cpp @@ -31,6 +31,7 @@ #include "mongo/client/read_preference.h" #include "mongo/client/remote_command_targeter.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/s/client/shard.h" #include "mongo/s/client/shard_registry.h" @@ -59,12 +60,16 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::fsync); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::fsync)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool errmsgRun(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_get_last_error_cmd.cpp b/src/mongo/s/commands/cluster_get_last_error_cmd.cpp index 008a4d349e3..2b7f8c322ff 100644 --- a/src/mongo/s/commands/cluster_get_last_error_cmd.cpp +++ b/src/mongo/s/commands/cluster_get_last_error_cmd.cpp @@ -39,7 +39,7 @@ class GetLastErrorCmd : public BasicCommand { public: GetLastErrorCmd() : BasicCommand("getLastError", "getlasterror") {} - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } @@ -51,17 +51,17 @@ public: return "no longer supported"; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - // No auth required for getlasterror + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required } bool requiresAuth() const override { return false; } - virtual bool run(OperationContext*, const DatabaseName&, const BSONObj&, BSONObjBuilder&) { + bool run(OperationContext*, const DatabaseName&, const BSONObj&, BSONObjBuilder&) override { uasserted(5739001, "getLastError command is not supported"); return false; } diff --git a/src/mongo/s/commands/cluster_hello_cmd.cpp b/src/mongo/s/commands/cluster_hello_cmd.cpp index 005a6e2ec26..9c6b2f4fb9f 100644 --- a/src/mongo/s/commands/cluster_hello_cmd.cpp +++ b/src/mongo/s/commands/cluster_hello_cmd.cpp @@ -104,10 +104,10 @@ public: return "Status information for clients negotiating a connection with this server"; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const final { - // No auth required + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required } bool requiresAuth() const final { diff --git a/src/mongo/s/commands/cluster_is_db_grid_cmd.cpp b/src/mongo/s/commands/cluster_is_db_grid_cmd.cpp index 6fc4f1b9263..d962e62e510 100644 --- a/src/mongo/s/commands/cluster_is_db_grid_cmd.cpp +++ b/src/mongo/s/commands/cluster_is_db_grid_cmd.cpp @@ -43,7 +43,7 @@ public: return false; } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } @@ -51,16 +51,16 @@ public: return AllowedOnSecondary::kAlways; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - // No auth required + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required } - virtual bool run(OperationContext* opCtx, - const DatabaseName&, - const BSONObj& cmdObj, - BSONObjBuilder& result) { + bool run(OperationContext* opCtx, + const DatabaseName&, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { result.append("isdbgrid", 1); result.append("hostname", getHostNameCached()); return true; diff --git a/src/mongo/s/commands/cluster_list_shards_cmd.cpp b/src/mongo/s/commands/cluster_list_shards_cmd.cpp index cb5fb91c6ec..e7b84626963 100644 --- a/src/mongo/s/commands/cluster_list_shards_cmd.cpp +++ b/src/mongo/s/commands/cluster_list_shards_cmd.cpp @@ -29,6 +29,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/s/catalog/type_shard.h" #include "mongo/s/grid.h" @@ -56,12 +57,16 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::listShards); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::listShards)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_multicast_cmd.cpp b/src/mongo/s/commands/cluster_multicast_cmd.cpp index 90ff772122f..0d82a3d85a1 100644 --- a/src/mongo/s/commands/cluster_multicast_cmd.cpp +++ b/src/mongo/s/commands/cluster_multicast_cmd.cpp @@ -83,9 +83,11 @@ public: } // no privs because it's a test command - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override {} + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); + } bool run(OperationContext* opCtx, const DatabaseName&, diff --git a/src/mongo/s/commands/cluster_netstat_cmd.cpp b/src/mongo/s/commands/cluster_netstat_cmd.cpp index 1b1fd469d6c..1003b9b0e44 100644 --- a/src/mongo/s/commands/cluster_netstat_cmd.cpp +++ b/src/mongo/s/commands/cluster_netstat_cmd.cpp @@ -29,6 +29,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/s/catalog/sharding_catalog_client.h" #include "mongo/s/client/shard_registry.h" @@ -57,12 +58,16 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::netstat); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::netstat)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_remove_shard_cmd.cpp b/src/mongo/s/commands/cluster_remove_shard_cmd.cpp index ef31d7dce15..28b3e549d22 100644 --- a/src/mongo/s/commands/cluster_remove_shard_cmd.cpp +++ b/src/mongo/s/commands/cluster_remove_shard_cmd.cpp @@ -32,6 +32,7 @@ #include <string> +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/s/client/shard.h" #include "mongo/s/client/shard_registry.h" @@ -63,12 +64,16 @@ public: return true; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::removeShard); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::removeShard)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_validate_cmd.cpp b/src/mongo/s/commands/cluster_validate_cmd.cpp index e54997ace56..237895fa301 100644 --- a/src/mongo/s/commands/cluster_validate_cmd.cpp +++ b/src/mongo/s/commands/cluster_validate_cmd.cpp @@ -30,6 +30,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/rpc/get_status_from_command_result.h" #include "mongo/s/cluster_commands_helpers.h" @@ -57,12 +58,16 @@ public: return false; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::validate); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName& dbName, + const BSONObj& cmdObj) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(parseResourcePattern(dbName.db(), cmdObj), + ActionType::validate)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool supportsWriteConcern(const BSONObj& cmd) const override { diff --git a/src/mongo/s/commands/cluster_whats_my_uri_cmd.cpp b/src/mongo/s/commands/cluster_whats_my_uri_cmd.cpp index d8581f2706e..6191134aec8 100644 --- a/src/mongo/s/commands/cluster_whats_my_uri_cmd.cpp +++ b/src/mongo/s/commands/cluster_whats_my_uri_cmd.cpp @@ -55,16 +55,16 @@ public: return false; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - // No auth required + Status checkAuthForOperation(OperationContext*, + const DatabaseName&, + const BSONObj&) const override { + return Status::OK(); // No auth required } - virtual bool run(OperationContext* opCtx, - const DatabaseName&, - const BSONObj& cmdObj, - BSONObjBuilder& result) { + bool run(OperationContext*, + const DatabaseName&, + const BSONObj&, + BSONObjBuilder& result) override { result << "you" << cc().getRemote().toString(); return true; } diff --git a/src/mongo/s/commands/flush_router_config_cmd.cpp b/src/mongo/s/commands/flush_router_config_cmd.cpp index addbd88edfc..e3bc756e510 100644 --- a/src/mongo/s/commands/flush_router_config_cmd.cpp +++ b/src/mongo/s/commands/flush_router_config_cmd.cpp @@ -30,6 +30,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/logv2/log.h" #include "mongo/s/grid.h" @@ -67,12 +68,16 @@ public: "{flushRouterconfig: 'db.coll'} flushes only the given collection"; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::flushRouterConfig); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::flushRouterConfig)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, diff --git a/src/mongo/s/commands/get_shard_map_cmd.cpp b/src/mongo/s/commands/get_shard_map_cmd.cpp index bbdf20d5ff0..f59d59717f4 100644 --- a/src/mongo/s/commands/get_shard_map_cmd.cpp +++ b/src/mongo/s/commands/get_shard_map_cmd.cpp @@ -31,6 +31,7 @@ #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/privilege.h" #include "mongo/db/commands.h" #include "mongo/s/grid.h" @@ -58,12 +59,16 @@ public: return true; } - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::getShardMap); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + Status checkAuthForOperation(OperationContext* opCtx, + const DatabaseName&, + const BSONObj&) const override { + auto* as = AuthorizationSession::get(opCtx->getClient()); + if (!as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::getShardMap)) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + return Status::OK(); } bool run(OperationContext* opCtx, |