summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2017-06-26 16:22:29 -0400
committerMathias Stearn <mathias@10gen.com>2017-07-13 16:53:12 -0400
commitc4883a9d289a01e8e4f45ccac7f19f59f2892c42 (patch)
treee853e7ce79e6c07b2390d5f64940f4a49d24924d
parentb32c49eadcfab7c7e321a4d539e770d2a70e9730 (diff)
downloadmongo-c4883a9d289a01e8e4f45ccac7f19f59f2892c42.tar.gz
SERVER-29731 Auth checks get access to document sequences
-rw-r--r--src/mongo/db/commands.cpp43
-rw-r--r--src/mongo/db/commands.h111
-rw-r--r--src/mongo/db/commands/SConscript16
-rw-r--r--src/mongo/db/commands/apply_ops_cmd_common.cpp2
-rw-r--r--src/mongo/db/commands/explain_cmd.cpp3
-rw-r--r--src/mongo/db/commands/write_commands/write_commands.cpp35
-rw-r--r--src/mongo/db/commands/write_commands/write_commands_common.cpp49
-rw-r--r--src/mongo/db/commands/write_commands/write_commands_common.h4
-rw-r--r--src/mongo/db/ops/write_ops_document_stream_integration_test.cpp35
-rw-r--r--src/mongo/db/service_entry_point_mongod.cpp2
-rw-r--r--src/mongo/s/commands/SConscript1
-rw-r--r--src/mongo/s/commands/cluster_explain_cmd.cpp3
-rw-r--r--src/mongo/s/commands/cluster_write_cmd.cpp12
-rw-r--r--src/mongo/s/commands/strategy.cpp2
14 files changed, 180 insertions, 138 deletions
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp
index 2ba830fb4de..8b54dc93534 100644
--- a/src/mongo/db/commands.cpp
+++ b/src/mongo/db/commands.cpp
@@ -250,15 +250,20 @@ void Command::appendOperationTime(BSONObjBuilder& result, LogicalTime operationT
result.append("operationTime", operationTime.asTimestamp());
}
-Status Command::checkAuthForOperation(OperationContext* opCtx,
- const std::string& dbname,
- const BSONObj& cmdObj) {
+Status BasicCommand::checkAuthForRequest(OperationContext* opCtx, const OpMsgRequest& request) {
+ uassertNoDocumentSequences(request);
+ return checkAuthForOperation(opCtx, request.getDatabase().toString(), request.body);
+}
+
+Status BasicCommand::checkAuthForOperation(OperationContext* opCtx,
+ const std::string& dbname,
+ const BSONObj& cmdObj) {
return checkAuthForCommand(opCtx->getClient(), dbname, cmdObj);
}
-Status Command::checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) {
+Status BasicCommand::checkAuthForCommand(Client* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj) {
std::vector<Privilege> privileges;
this->addRequiredPrivileges(dbname, cmdObj, &privileges);
if (AuthorizationSession::get(client)->isAuthorizedForPrivileges(privileges))
@@ -279,19 +284,19 @@ BSONObj Command::getRedactedCopyForLogging(const BSONObj& cmdObj) {
static Status _checkAuthorizationImpl(Command* c,
OperationContext* opCtx,
- const std::string& dbname,
- const BSONObj& cmdObj) {
+ const OpMsgRequest& request) {
namespace mmb = mutablebson;
auto client = opCtx->getClient();
+ auto dbname = request.getDatabase();
if (c->adminOnly() && dbname != "admin") {
return Status(ErrorCodes::Unauthorized,
str::stream() << c->getName()
<< " may only be run against the admin database.");
}
if (AuthorizationSession::get(client)->getAuthorizationManager().isAuthEnabled()) {
- Status status = c->checkAuthForOperation(opCtx, dbname, cmdObj);
+ Status status = c->checkAuthForRequest(opCtx, request);
if (status == ErrorCodes::Unauthorized) {
- mmb::Document cmdToLog(cmdObj, mmb::Document::kInPlaceDisabled);
+ mmb::Document cmdToLog(request.body, mmb::Document::kInPlaceDisabled);
c->redactForLogging(&cmdToLog);
return Status(ErrorCodes::Unauthorized,
str::stream() << "not authorized on " << dbname << " to execute command "
@@ -311,14 +316,13 @@ static Status _checkAuthorizationImpl(Command* c,
Status Command::checkAuthorization(Command* c,
OperationContext* opCtx,
- const std::string& dbname,
- const BSONObj& cmdObj) {
- namespace mmb = mutablebson;
- Status status = _checkAuthorizationImpl(c, opCtx, dbname, cmdObj);
+ const OpMsgRequest& request) {
+ Status status = _checkAuthorizationImpl(c, opCtx, request);
if (!status.isOK()) {
log(LogComponent::kAccessControl) << status;
}
- audit::logCommandAuthzCheck(opCtx->getClient(), dbname, cmdObj, c, status.code());
+ audit::logCommandAuthzCheck(
+ opCtx->getClient(), request.getDatabase().toString(), request.body, c, status.code());
return status;
}
@@ -364,13 +368,16 @@ bool Command::isUserManagementCommand(const std::string& name) {
return userManagementCommands.count(name);
}
-bool BasicCommand::enhancedRun(OperationContext* opCtx,
- const OpMsgRequest& request,
- BSONObjBuilder& result) {
+void BasicCommand::uassertNoDocumentSequences(const OpMsgRequest& request) {
uassert(40472,
str::stream() << "The " << getName() << " command does not support document sequences.",
request.sequences.empty());
+}
+bool BasicCommand::enhancedRun(OperationContext* opCtx,
+ const OpMsgRequest& request,
+ BSONObjBuilder& result) {
+ uassertNoDocumentSequences(request);
return run(opCtx, request.getDatabase().toString(), request.body, result);
}
diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h
index ab0ec1c7bfd..5eb48f794f9 100644
--- a/src/mongo/db/commands.h
+++ b/src/mongo/db/commands.h
@@ -171,13 +171,10 @@ public:
BSONObjBuilder* out) const = 0;
/**
- * Checks if the client associated with the given OperationContext, "opCtx", is authorized to
- * run
- * this command on database "dbname" with the invocation described by "cmdObj".
+ * Checks if the client associated with the given OperationContext is authorized to run this
+ * command.
*/
- virtual Status checkAuthForOperation(OperationContext* opCtx,
- const std::string& dbname,
- const BSONObj& cmdObj) = 0;
+ virtual Status checkAuthForRequest(OperationContext* opCtx, const OpMsgRequest& request) = 0;
/**
* Redacts "cmdObj" in-place to a form suitable for writing to logs.
@@ -243,26 +240,6 @@ public:
* Increment counter for how many times this command has failed.
*/
virtual void incrementCommandsFailed() = 0;
-
-private:
- /**
- * Checks if the given client is authorized to run this command on database "dbname"
- * with the invocation described by "cmdObj".
- *
- * NOTE: Implement checkAuthForOperation that takes an OperationContext* instead.
- */
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) = 0;
-
- /**
- * 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) = 0;
};
/**
@@ -333,10 +310,6 @@ public:
ExplainOptions::Verbosity verbosity,
BSONObjBuilder* out) const override;
- Status checkAuthForOperation(OperationContext* opCtx,
- const std::string& dbname,
- const BSONObj& cmdObj) override;
-
void redactForLogging(mutablebson::Document* cmdObj) override;
BSONObj getRedactedCopyForLogging(const BSONObj& cmdObj) override;
@@ -472,9 +445,8 @@ public:
* authorized.
*/
static Status checkAuthorization(Command* c,
- OperationContext* client,
- const std::string& dbname,
- const BSONObj& cmdObj);
+ OperationContext* opCtx,
+ const OpMsgRequest& request);
/**
* Appends passthrough fields from a cmdObj to a given request.
@@ -536,17 +508,6 @@ public:
static BSONObj filterCommandReplyForPassthrough(const BSONObj& reply);
private:
- Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) override;
-
- void addRequiredPrivileges(const std::string& dbname,
- const BSONObj& cmdObj,
- std::vector<Privilege>* out) override {
- // The default implementation of addRequiredPrivileges should never be hit.
- fassertFailed(16940);
- }
-
// Counters for how many times this command has been executed and failed
Counter64 _commandsExecuted;
Counter64 _commandsFailed;
@@ -567,12 +528,9 @@ class BasicCommand : public Command {
public:
using Command::Command;
- /**
- * Calls run() as defined below.
- */
- bool enhancedRun(OperationContext* opCtx,
- const OpMsgRequest& request,
- BSONObjBuilder& result) final;
+ //
+ // Interface for subclasses to implement
+ //
/**
* run the given command
@@ -584,6 +542,59 @@ public:
const std::string& db,
const BSONObj& cmdObj,
BSONObjBuilder& result) = 0;
+
+ /**
+ * Checks if the client associated with the given OperationContext is authorized to run this
+ * command. Default implementation defers to checkAuthForCommand.
+ */
+ virtual Status checkAuthForOperation(OperationContext* opCtx,
+ const std::string& dbname,
+ const BSONObj& cmdObj);
+
+private:
+ //
+ // Deprecated virtual methods.
+ //
+
+ /**
+ * Checks if the given client is authorized to run this command on database "dbname"
+ * with the invocation described by "cmdObj".
+ *
+ * NOTE: Implement checkAuthForOperation that takes an OperationContext* instead.
+ */
+ virtual Status checkAuthForCommand(Client* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj);
+
+ /**
+ * 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) {
+ // The default implementation of addRequiredPrivileges should never be hit.
+ fassertFailed(16940);
+ }
+
+ //
+ // Methods provided for subclasses if they implement above interface.
+ //
+
+ /**
+ * Calls run().
+ */
+ bool enhancedRun(OperationContext* opCtx,
+ const OpMsgRequest& request,
+ BSONObjBuilder& result) final;
+
+ /**
+ * Calls checkAuthForOperation.
+ */
+ Status checkAuthForRequest(OperationContext* opCtx, const OpMsgRequest& request) final;
+
+ void uassertNoDocumentSequences(const OpMsgRequest& request);
};
/**
diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript
index 6c711a48810..ed571c55ca3 100644
--- a/src/mongo/db/commands/SConscript
+++ b/src/mongo/db/commands/SConscript
@@ -35,6 +35,18 @@ env.Library(
)
env.Library(
+ target="write_commands_common",
+ source=[
+ "write_commands/write_commands_common.cpp",
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/db/commands',
+ '$BUILD_DIR/mongo/db/ops/write_ops_parsers',
+ ],
+)
+
+env.Library(
target="core",
source=[
"authentication_commands.cpp",
@@ -52,7 +64,6 @@ env.Library(
"parameters.cpp",
"rename_collection_common.cpp",
"user_management_commands_common.cpp",
- "write_commands/write_commands_common.cpp",
],
LIBDEPS=[
'$BUILD_DIR/mongo/client/clientdriver',
@@ -205,7 +216,8 @@ env.Library(
'current_op_common',
'dcommands_fcv',
'dcommands_fsync',
- 'killcursors_common'
+ 'killcursors_common',
+ 'write_commands_common',
],
)
diff --git a/src/mongo/db/commands/apply_ops_cmd_common.cpp b/src/mongo/db/commands/apply_ops_cmd_common.cpp
index 55b463abc04..06628e63fd5 100644
--- a/src/mongo/db/commands/apply_ops_cmd_common.cpp
+++ b/src/mongo/db/commands/apply_ops_cmd_common.cpp
@@ -79,7 +79,7 @@ Status checkOperationAuthorization(OperationContext* opCtx,
return Status(ErrorCodes::FailedToParse, "Unrecognized command in op");
}
- return Command::checkAuthorization(command, opCtx, dbname, o);
+ return Command::checkAuthorization(command, opCtx, OpMsgRequest::fromDBAndBody(dbname, o));
}
if (opType == "i"_sd) {
diff --git a/src/mongo/db/commands/explain_cmd.cpp b/src/mongo/db/commands/explain_cmd.cpp
index c2b3893c15e..d0a218a2e1a 100644
--- a/src/mongo/db/commands/explain_cmd.cpp
+++ b/src/mongo/db/commands/explain_cmd.cpp
@@ -117,7 +117,8 @@ public:
return Status(ErrorCodes::CommandNotFound, ss);
}
- return commToExplain->checkAuthForOperation(opCtx, dbname, explainObj);
+ return commToExplain->checkAuthForRequest(
+ opCtx, OpMsgRequest::fromDBAndBody(dbname, std::move(explainObj)));
}
virtual bool run(OperationContext* opCtx,
diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp
index 2c9d5a37c8f..695e5cd3710 100644
--- a/src/mongo/db/commands/write_commands/write_commands.cpp
+++ b/src/mongo/db/commands/write_commands/write_commands.cpp
@@ -73,10 +73,9 @@ void redactTooLongLog(mutablebson::Document* cmdObj, StringData fieldName) {
Status checkAuthForWriteCommand(Client* client,
BatchedCommandRequest::BatchType batchType,
- NamespaceString ns,
- const BSONObj& cmdObj) {
+ const OpMsgRequest& request) {
Status status =
- auth::checkAuthForWriteCommand(AuthorizationSession::get(client), batchType, ns, cmdObj);
+ auth::checkAuthForWriteCommand(AuthorizationSession::get(client), batchType, request);
if (!status.isOK()) {
LastError::get(client).setLastError(status.code(), status.reason());
}
@@ -232,13 +231,9 @@ public:
help << "insert documents";
}
- Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) final {
- return checkAuthForWriteCommand(client,
- BatchedCommandRequest::BatchType_Insert,
- NamespaceString(parseNs(dbname, cmdObj)),
- cmdObj);
+ Status checkAuthForRequest(OperationContext* opCtx, const OpMsgRequest& request) final {
+ return checkAuthForWriteCommand(
+ opCtx->getClient(), BatchedCommandRequest::BatchType_Insert, request);
}
void runImpl(OperationContext* opCtx,
@@ -267,13 +262,9 @@ public:
help << "update documents";
}
- Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) final {
- return checkAuthForWriteCommand(client,
- BatchedCommandRequest::BatchType_Update,
- NamespaceString(parseNs(dbname, cmdObj)),
- cmdObj);
+ Status checkAuthForRequest(OperationContext* opCtx, const OpMsgRequest& request) final {
+ return checkAuthForWriteCommand(
+ opCtx->getClient(), BatchedCommandRequest::BatchType_Update, request);
}
void runImpl(OperationContext* opCtx,
@@ -338,13 +329,9 @@ public:
help << "delete documents";
}
- Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) final {
- return checkAuthForWriteCommand(client,
- BatchedCommandRequest::BatchType_Delete,
- NamespaceString(parseNs(dbname, cmdObj)),
- cmdObj);
+ Status checkAuthForRequest(OperationContext* opCtx, const OpMsgRequest& request) final {
+ return checkAuthForWriteCommand(
+ opCtx->getClient(), BatchedCommandRequest::BatchType_Delete, request);
}
void runImpl(OperationContext* opCtx,
diff --git a/src/mongo/db/commands/write_commands/write_commands_common.cpp b/src/mongo/db/commands/write_commands/write_commands_common.cpp
index 9a5eb5d6cd8..98acc3dd66b 100644
--- a/src/mongo/db/commands/write_commands/write_commands_common.cpp
+++ b/src/mongo/db/commands/write_commands/write_commands_common.cpp
@@ -44,6 +44,7 @@ namespace mongo {
namespace auth {
namespace {
+using write_ops::Delete;
using write_ops::Insert;
using write_ops::Update;
using write_ops::UpdateOpEntry;
@@ -51,17 +52,9 @@ using write_ops::UpdateOpEntry;
/**
* Helper to determine whether or not there are any upserts in the batch
*/
-bool containsUpserts(const BSONObj& writeCmdObj) {
- BSONElement updatesEl = writeCmdObj[Update::kUpdatesFieldName];
- if (updatesEl.type() != Array) {
- return false;
- }
-
- for (const auto& updateEl : updatesEl.Array()) {
- if (!updateEl.isABSONObj())
- continue;
-
- if (updateEl.Obj()[UpdateOpEntry::kUpsertFieldName].trueValue())
+bool containsUpserts(const std::vector<UpdateOpEntry>& updates) {
+ for (auto&& update : updates) {
+ if (update.getUpsert())
return true;
}
@@ -73,26 +66,18 @@ bool containsUpserts(const BSONObj& writeCmdObj) {
*
* TODO: Remove when we have parsing hooked before authorization.
*/
-StatusWith<NamespaceString> getIndexedNss(const BSONObj& writeCmdObj) {
- BSONElement documentsEl = writeCmdObj[Insert::kDocumentsFieldName];
- if (documentsEl.type() != Array) {
- return {ErrorCodes::FailedToParse, "index write batch is invalid"};
- }
-
- BSONObjIterator it(documentsEl.Obj());
- if (!it.more()) {
+StatusWith<NamespaceString> getIndexedNss(const std::vector<BSONObj>& documentsToInsert) {
+ if (documentsToInsert.empty()) {
return {ErrorCodes::FailedToParse, "index write batch is empty"};
}
- BSONElement indexDescEl = it.next();
-
- const std::string nsToIndex = indexDescEl["ns"].str();
+ const std::string nsToIndex = documentsToInsert.front()["ns"].str();
if (nsToIndex.empty()) {
return {ErrorCodes::FailedToParse,
"index write batch contains an invalid index descriptor"};
}
- if (it.more()) {
+ if (documentsToInsert.size() != 1) {
return {ErrorCodes::FailedToParse,
"index write batches may only contain a single index descriptor"};
}
@@ -104,21 +89,23 @@ StatusWith<NamespaceString> getIndexedNss(const BSONObj& writeCmdObj) {
Status checkAuthForWriteCommand(AuthorizationSession* authzSession,
BatchedCommandRequest::BatchType cmdType,
- const NamespaceString& cmdNSS,
- const BSONObj& cmdObj) {
+ const OpMsgRequest& request) {
std::vector<Privilege> privileges;
ActionSet actionsOnCommandNSS;
- if (shouldBypassDocumentValidationForCommand(cmdObj)) {
+ if (shouldBypassDocumentValidationForCommand(request.body)) {
actionsOnCommandNSS.addAction(ActionType::bypassDocumentValidation);
}
+ NamespaceString cmdNSS;
if (cmdType == BatchedCommandRequest::BatchType_Insert) {
- if (!cmdNSS.isSystemDotIndexes()) {
+ auto op = Insert::parse(IDLParserErrorContext("insert"), request);
+ cmdNSS = op.getNamespace();
+ if (!op.getNamespace().isSystemDotIndexes()) {
actionsOnCommandNSS.addAction(ActionType::insert);
} else {
// Special-case indexes until we have a command
- const auto swNssToIndex = getIndexedNss(cmdObj);
+ const auto swNssToIndex = getIndexedNss(op.getDocuments());
if (!swNssToIndex.isOK()) {
return swNssToIndex.getStatus();
}
@@ -128,14 +115,18 @@ Status checkAuthForWriteCommand(AuthorizationSession* authzSession,
Privilege(ResourcePattern::forExactNamespace(nssToIndex), ActionType::createIndex));
}
} else if (cmdType == BatchedCommandRequest::BatchType_Update) {
+ auto op = Update::parse(IDLParserErrorContext("update"), request);
+ cmdNSS = op.getNamespace();
actionsOnCommandNSS.addAction(ActionType::update);
// Upsert also requires insert privs
- if (containsUpserts(cmdObj)) {
+ if (containsUpserts(op.getUpdates())) {
actionsOnCommandNSS.addAction(ActionType::insert);
}
} else {
fassert(17251, cmdType == BatchedCommandRequest::BatchType_Delete);
+ auto op = Delete::parse(IDLParserErrorContext("delete"), request);
+ cmdNSS = op.getNamespace();
actionsOnCommandNSS.addAction(ActionType::remove);
}
diff --git a/src/mongo/db/commands/write_commands/write_commands_common.h b/src/mongo/db/commands/write_commands/write_commands_common.h
index 8f8206d3c70..897ee283fe1 100644
--- a/src/mongo/db/commands/write_commands/write_commands_common.h
+++ b/src/mongo/db/commands/write_commands/write_commands_common.h
@@ -32,6 +32,7 @@
#include "mongo/db/jsobj.h"
#include "mongo/db/namespace_string.h"
#include "mongo/s/write_ops/batched_command_request.h"
+#include "mongo/util/net/op_msg.h"
/**
* Contains common functionality shared between the batch write commands in mongos and mongod.
@@ -42,8 +43,7 @@ namespace auth {
Status checkAuthForWriteCommand(AuthorizationSession* authzSession,
BatchedCommandRequest::BatchType cmdType,
- const NamespaceString& cmdNSS,
- const BSONObj& cmdObj);
+ const OpMsgRequest& request);
} // namespace auth
} // namespace mongo
diff --git a/src/mongo/db/ops/write_ops_document_stream_integration_test.cpp b/src/mongo/db/ops/write_ops_document_stream_integration_test.cpp
index adfc5842e3d..3ef382f3ef4 100644
--- a/src/mongo/db/ops/write_ops_document_stream_integration_test.cpp
+++ b/src/mongo/db/ops/write_ops_document_stream_integration_test.cpp
@@ -66,4 +66,39 @@ TEST(WriteOpsDocSeq, InsertDocStreamWorks) {
ASSERT_EQ(conn->count(ns.ns()), 5u);
}
+TEST(WriteOpsDocSeq, InsertDocStreamWorksWithSystemDotIndexes) {
+ std::string errMsg;
+ auto conn = std::unique_ptr<DBClientBase>(
+ unittest::getFixtureConnectionString().connect("integration_test", errMsg));
+ uassert(ErrorCodes::SocketException, errMsg, conn);
+
+ NamespaceString ns("test", "doc_seq");
+ conn->dropCollection(ns.ns());
+ ASSERT_EQ(conn->count(ns.ns()), 0u);
+
+ OpMsgRequest request;
+ request.body = BSON("insert"
+ << "system.indexes"
+ << "$db"
+ << ns.db());
+ request.sequences = {{"documents",
+ {
+ BSON("ns" << ns.ns() << "key" << BSON("x" << 1) << "name"
+ << "my_special_index"),
+ }}};
+
+ const auto reply = conn->runCommand(std::move(request));
+ ASSERT_EQ(int(reply->getProtocol()), int(rpc::Protocol::kOpMsg));
+ auto body = reply->getCommandReply();
+ ASSERT_OK(getStatusFromCommandResult(body));
+ ASSERT_EQ(body["n"].Int(), 1);
+
+ auto indexes = conn->getIndexSpecs(ns.ns());
+ ASSERT_EQ(indexes.size(), 2u); // my_special_index + _id
+
+ indexes.sort([](auto&& l, auto&& r) { return l["name"].String() < r["name"].String(); });
+ ASSERT_EQ(indexes.front()["name"].String(), "_id_");
+ ASSERT_EQ(indexes.back()["name"].String(), "my_special_index");
+}
+
} // namespace mongo
diff --git a/src/mongo/db/service_entry_point_mongod.cpp b/src/mongo/db/service_entry_point_mongod.cpp
index 0491274939f..67790e417fc 100644
--- a/src/mongo/db/service_entry_point_mongod.cpp
+++ b/src/mongo/db/service_entry_point_mongod.cpp
@@ -573,7 +573,7 @@ void execCommandDatabase(OperationContext* opCtx,
OperationContextSession sessionTxnState(opCtx);
ImpersonationSessionGuard guard(opCtx);
- uassertStatusOK(Command::checkAuthorization(command, opCtx, dbname, request.body));
+ uassertStatusOK(Command::checkAuthorization(command, opCtx, request));
repl::ReplicationCoordinator* replCoord =
repl::ReplicationCoordinator::get(opCtx->getClient()->getServiceContext());
diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript
index 58588b5a7b7..eceafa93e4f 100644
--- a/src/mongo/s/commands/SConscript
+++ b/src/mongo/s/commands/SConscript
@@ -87,6 +87,7 @@ env.Library(
'$BUILD_DIR/mongo/db/commands/apply_ops_cmd_common',
'$BUILD_DIR/mongo/db/commands/killcursors_common',
'$BUILD_DIR/mongo/db/ftdc/ftdc_server',
+ '$BUILD_DIR/mongo/db/commands/write_commands_common',
'$BUILD_DIR/mongo/db/pipeline/aggregation',
'$BUILD_DIR/mongo/db/views/views',
'$BUILD_DIR/mongo/rpc/client_metadata',
diff --git a/src/mongo/s/commands/cluster_explain_cmd.cpp b/src/mongo/s/commands/cluster_explain_cmd.cpp
index 6397a2d3f07..0b7897f416c 100644
--- a/src/mongo/s/commands/cluster_explain_cmd.cpp
+++ b/src/mongo/s/commands/cluster_explain_cmd.cpp
@@ -102,7 +102,8 @@ public:
return Status(ErrorCodes::CommandNotFound, ss);
}
- return commToExplain->checkAuthForOperation(opCtx, dbname, explainObj);
+ return commToExplain->checkAuthForRequest(
+ opCtx, OpMsgRequest::fromDBAndBody(dbname, std::move(explainObj)));
}
virtual bool run(OperationContext* opCtx,
diff --git a/src/mongo/s/commands/cluster_write_cmd.cpp b/src/mongo/s/commands/cluster_write_cmd.cpp
index b0c5e248c8f..1f1ad290f47 100644
--- a/src/mongo/s/commands/cluster_write_cmd.cpp
+++ b/src/mongo/s/commands/cluster_write_cmd.cpp
@@ -76,17 +76,13 @@ public:
return true;
}
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) {
- Status status = auth::checkAuthForWriteCommand(AuthorizationSession::get(client),
- _writeType,
- NamespaceString(parseNs(dbname, cmdObj)),
- cmdObj);
+ Status checkAuthForRequest(OperationContext* opCtx, const OpMsgRequest& request) final {
+ Status status = auth::checkAuthForWriteCommand(
+ AuthorizationSession::get(opCtx->getClient()), _writeType, request);
// TODO: Remove this when we standardize GLE reporting from commands
if (!status.isOK()) {
- LastError::get(client).setLastError(status.code(), status.reason());
+ LastError::get(opCtx->getClient()).setLastError(status.code(), status.reason());
}
return status;
diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp
index 915809a03aa..eb7d7a53b34 100644
--- a/src/mongo/s/commands/strategy.cpp
+++ b/src/mongo/s/commands/strategy.cpp
@@ -179,7 +179,7 @@ void execCommandClient(OperationContext* opCtx,
topLevelFields[fieldName]++ == 0);
}
- Status status = Command::checkAuthorization(c, opCtx, dbname, request.body);
+ Status status = Command::checkAuthorization(c, opCtx, request);
if (!status.isOK()) {
Command::appendCommandStatus(result, status);
return;