summaryrefslogtreecommitdiff
path: root/src/mongo/s
diff options
context:
space:
mode:
authorSara Golemon <sara.golemon@mongodb.com>2020-06-23 14:20:48 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-07-02 15:34:37 +0000
commitebe622f95a071d7d769298b68ecf45b6cdff8e39 (patch)
tree28fe923dbe17deac6e73fffcac4074d9d860c72c /src/mongo/s
parent986028e17b939b4246b3d071ca6945a15604f0fc (diff)
downloadmongo-ebe622f95a071d7d769298b68ecf45b6cdff8e39.tar.gz
SERVER-49077 IDLify UMC Mutation commands
Diffstat (limited to 'src/mongo/s')
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client.h10
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_impl.cpp52
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_impl.h10
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_mock.cpp8
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_mock.h12
-rw-r--r--src/mongo/s/catalog/sharding_catalog_test.cpp71
-rw-r--r--src/mongo/s/commands/cluster_user_management_commands.cpp738
7 files changed, 215 insertions, 686 deletions
diff --git a/src/mongo/s/catalog/sharding_catalog_client.h b/src/mongo/s/catalog/sharding_catalog_client.h
index 44b557d789e..a0f0901952c 100644
--- a/src/mongo/s/catalog/sharding_catalog_client.h
+++ b/src/mongo/s/catalog/sharding_catalog_client.h
@@ -228,11 +228,11 @@ public:
* @param result: contains data returned from config servers
* Returns true on success.
*/
- virtual bool runUserManagementWriteCommand(OperationContext* opCtx,
- const std::string& commandName,
- const std::string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder* result) = 0;
+ virtual Status runUserManagementWriteCommand(OperationContext* opCtx,
+ StringData commandName,
+ StringData dbname,
+ const BSONObj& cmdObj,
+ BSONObjBuilder* result) = 0;
/**
* Runs a user management related read-only command on a config server.
diff --git a/src/mongo/s/catalog/sharding_catalog_client_impl.cpp b/src/mongo/s/catalog/sharding_catalog_client_impl.cpp
index 69aee09575c..10751b45ed6 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_impl.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_client_impl.cpp
@@ -580,11 +580,11 @@ StatusWith<repl::OpTimeWith<std::vector<ShardType>>> ShardingCatalogClientImpl::
findStatus.getValue().opTime};
}
-bool ShardingCatalogClientImpl::runUserManagementWriteCommand(OperationContext* opCtx,
- const std::string& commandName,
- const std::string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder* result) {
+Status ShardingCatalogClientImpl::runUserManagementWriteCommand(OperationContext* opCtx,
+ StringData commandName,
+ StringData dbname,
+ const BSONObj& cmdObj,
+ BSONObjBuilder* result) {
BSONObj cmdToRun = cmdObj;
{
// Make sure that if the command has a write concern that it is w:1 or w:majority, and
@@ -596,18 +596,16 @@ bool ShardingCatalogClientImpl::runUserManagementWriteCommand(OperationContext*
if (initialCmdHadWriteConcern) {
auto sw = WriteConcernOptions::parse(writeConcernElement.Obj());
if (!sw.isOK()) {
- return CommandHelpers::appendCommandStatusNoThrow(*result, sw.getStatus());
+ return sw.getStatus();
}
writeConcern = sw.getValue();
- if (!(writeConcern.wNumNodes == 1 ||
- writeConcern.wMode == WriteConcernOptions::kMajority)) {
- return CommandHelpers::appendCommandStatusNoThrow(
- *result,
- {ErrorCodes::InvalidOptions,
- str::stream() << "Invalid replication write concern. User management write "
- "commands may only use w:1 or w:'majority', got: "
- << writeConcern.toBSON()});
+ if ((writeConcern.wNumNodes != 1) &&
+ (writeConcern.wMode != WriteConcernOptions::kMajority)) {
+ return {ErrorCodes::InvalidOptions,
+ str::stream() << "Invalid replication write concern. User management write "
+ "commands may only use w:1 or w:'majority', got: "
+ << writeConcern.toBSON()};
}
}
@@ -631,29 +629,31 @@ bool ShardingCatalogClientImpl::runUserManagementWriteCommand(OperationContext*
cmdToRun = modifiedCmd.obj();
}
- auto response =
+ auto swResponse =
Grid::get(opCtx)->shardRegistry()->getConfigShard()->runCommandWithFixedRetryAttempts(
opCtx,
ReadPreferenceSetting{ReadPreference::PrimaryOnly},
- dbname,
+ dbname.toString(),
cmdToRun,
Shard::kDefaultConfigCommandTimeout,
Shard::RetryPolicy::kNotIdempotent);
- if (!response.isOK()) {
- return CommandHelpers::appendCommandStatusNoThrow(*result, response.getStatus());
+ if (!swResponse.isOK()) {
+ return swResponse.getStatus();
}
- if (!response.getValue().commandStatus.isOK()) {
- return CommandHelpers::appendCommandStatusNoThrow(*result,
- response.getValue().commandStatus);
+
+ auto response = std::move(swResponse.getValue());
+
+ if (!response.commandStatus.isOK()) {
+ return response.commandStatus;
}
- if (!response.getValue().writeConcernStatus.isOK()) {
- return CommandHelpers::appendCommandStatusNoThrow(*result,
- response.getValue().writeConcernStatus);
+
+ if (!response.writeConcernStatus.isOK()) {
+ return response.writeConcernStatus;
}
- CommandHelpers::filterCommandReplyForPassthrough(response.getValue().response, result);
- return true;
+ CommandHelpers::filterCommandReplyForPassthrough(response.response, result);
+ return Status::OK();
}
bool ShardingCatalogClientImpl::runUserManagementReadCommand(OperationContext* opCtx,
diff --git a/src/mongo/s/catalog/sharding_catalog_client_impl.h b/src/mongo/s/catalog/sharding_catalog_client_impl.h
index 269305ae323..7d6f6c4f119 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_impl.h
+++ b/src/mongo/s/catalog/sharding_catalog_client_impl.h
@@ -110,11 +110,11 @@ public:
StatusWith<repl::OpTimeWith<std::vector<ShardType>>> getAllShards(
OperationContext* opCtx, repl::ReadConcernLevel readConcern) override;
- bool runUserManagementWriteCommand(OperationContext* opCtx,
- const std::string& commandName,
- const std::string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder* result) override;
+ Status runUserManagementWriteCommand(OperationContext* opCtx,
+ StringData commandName,
+ StringData dbname,
+ const BSONObj& cmdObj,
+ BSONObjBuilder* result) override;
bool runUserManagementReadCommand(OperationContext* opCtx,
const std::string& dbname,
diff --git a/src/mongo/s/catalog/sharding_catalog_client_mock.cpp b/src/mongo/s/catalog/sharding_catalog_client_mock.cpp
index 35c22b68ff2..f8c87cd2c75 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_mock.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_client_mock.cpp
@@ -118,14 +118,6 @@ StatusWith<repl::OpTimeWith<std::vector<ShardType>>> ShardingCatalogClientMock::
return {ErrorCodes::InternalError, "Method not implemented"};
}
-bool ShardingCatalogClientMock::runUserManagementWriteCommand(OperationContext* opCtx,
- const string& commandName,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder* result) {
- return true;
-}
-
bool ShardingCatalogClientMock::runUserManagementReadCommand(OperationContext* opCtx,
const string& dbname,
const BSONObj& cmdObj,
diff --git a/src/mongo/s/catalog/sharding_catalog_client_mock.h b/src/mongo/s/catalog/sharding_catalog_client_mock.h
index c4123518ea3..7be7629d44a 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_mock.h
+++ b/src/mongo/s/catalog/sharding_catalog_client_mock.h
@@ -83,11 +83,13 @@ public:
StatusWith<repl::OpTimeWith<std::vector<ShardType>>> getAllShards(
OperationContext* opCtx, repl::ReadConcernLevel readConcern) override;
- bool runUserManagementWriteCommand(OperationContext* opCtx,
- const std::string& commandName,
- const std::string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder* result) override;
+ Status runUserManagementWriteCommand(OperationContext* opCtx,
+ StringData commandName,
+ StringData dbname,
+ const BSONObj& cmdObj,
+ BSONObjBuilder* result) override {
+ return Status::OK();
+ }
bool runUserManagementReadCommand(OperationContext* opCtx,
const std::string& dbname,
diff --git a/src/mongo/s/catalog/sharding_catalog_test.cpp b/src/mongo/s/catalog/sharding_catalog_test.cpp
index b30c044739d..65bc0c746ce 100644
--- a/src/mongo/s/catalog/sharding_catalog_test.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_test.cpp
@@ -584,16 +584,14 @@ TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandSuccess) {
auto future = launchAsync([this] {
BSONObjBuilder responseBuilder;
- bool ok = catalogClient()->runUserManagementWriteCommand(operationContext(),
- "dropUser",
- "test",
- BSON("dropUser"
- << "test"),
- &responseBuilder);
- ASSERT_FALSE(ok);
-
- Status commandStatus = getStatusFromCommandResult(responseBuilder.obj());
- ASSERT_EQUALS(ErrorCodes::UserNotFound, commandStatus);
+ auto status = catalogClient()->runUserManagementWriteCommand(operationContext(),
+ "dropUser",
+ "test",
+ BSON("dropUser"
+ << "test"),
+ &responseBuilder);
+ ASSERT_NOT_OK(status);
+ ASSERT_EQUALS(ErrorCodes::UserNotFound, status);
});
onCommand([](const RemoteCommandRequest& request) {
@@ -625,7 +623,7 @@ TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandInvalidWriteConce
configTargeter()->setFindHostReturnValue(HostAndPort("TestHost1"));
BSONObjBuilder responseBuilder;
- bool ok =
+ auto status =
catalogClient()->runUserManagementWriteCommand(operationContext(),
"dropUser",
"test",
@@ -633,11 +631,9 @@ TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandInvalidWriteConce
<< "test"
<< "writeConcern" << BSON("w" << 2)),
&responseBuilder);
- ASSERT_FALSE(ok);
-
- Status commandStatus = getStatusFromCommandResult(responseBuilder.obj());
- ASSERT_EQUALS(ErrorCodes::InvalidOptions, commandStatus);
- ASSERT_STRING_CONTAINS(commandStatus.reason(), "Invalid replication write concern");
+ ASSERT_NOT_OK(status);
+ ASSERT_EQUALS(ErrorCodes::InvalidOptions, status);
+ ASSERT_STRING_CONTAINS(status.reason(), "Invalid replication write concern");
}
TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandRewriteWriteConcern) {
@@ -654,7 +650,7 @@ TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandRewriteWriteConce
auto future =
launchAsync([this] {
BSONObjBuilder responseBuilder;
- bool ok =
+ auto status =
catalogClient()->runUserManagementWriteCommand(
operationContext(),
"dropUser",
@@ -663,10 +659,8 @@ TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandRewriteWriteConce
<< "test"
<< "writeConcern" << BSON("w" << 1 << "wtimeout" << 30)),
&responseBuilder);
- ASSERT_FALSE(ok);
-
- Status commandStatus = getStatusFromCommandResult(responseBuilder.obj());
- ASSERT_EQUALS(ErrorCodes::UserNotFound, commandStatus);
+ ASSERT_NOT_OK(status);
+ ASSERT_EQUALS(ErrorCodes::UserNotFound, status);
});
onCommand([](const RemoteCommandRequest& request) {
@@ -698,16 +692,14 @@ TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandNotMaster) {
auto future = launchAsync([this] {
BSONObjBuilder responseBuilder;
- bool ok = catalogClient()->runUserManagementWriteCommand(operationContext(),
- "dropUser",
- "test",
- BSON("dropUser"
- << "test"),
- &responseBuilder);
- ASSERT_FALSE(ok);
-
- Status commandStatus = getStatusFromCommandResult(responseBuilder.obj());
- ASSERT_EQUALS(ErrorCodes::NotMaster, commandStatus);
+ auto status = catalogClient()->runUserManagementWriteCommand(operationContext(),
+ "dropUser",
+ "test",
+ BSON("dropUser"
+ << "test"),
+ &responseBuilder);
+ ASSERT_NOT_OK(status);
+ ASSERT_EQUALS(ErrorCodes::NotMaster, status);
});
for (int i = 0; i < 3; ++i) {
@@ -731,16 +723,13 @@ TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandNotMasterRetrySuc
auto future = launchAsync([this] {
BSONObjBuilder responseBuilder;
- bool ok = catalogClient()->runUserManagementWriteCommand(operationContext(),
- "dropUser",
- "test",
- BSON("dropUser"
- << "test"),
- &responseBuilder);
- ASSERT_TRUE(ok);
-
- Status commandStatus = getStatusFromCommandResult(responseBuilder.obj());
- ASSERT_OK(commandStatus);
+ auto status = catalogClient()->runUserManagementWriteCommand(operationContext(),
+ "dropUser",
+ "test",
+ BSON("dropUser"
+ << "test"),
+ &responseBuilder);
+ ASSERT_OK(status);
});
onCommand([&](const RemoteCommandRequest& request) {
diff --git a/src/mongo/s/commands/cluster_user_management_commands.cpp b/src/mongo/s/commands/cluster_user_management_commands.cpp
index 7dfdf9efae5..c3d7d154cfb 100644
--- a/src/mongo/s/commands/cluster_user_management_commands.cpp
+++ b/src/mongo/s/commands/cluster_user_management_commands.cpp
@@ -31,6 +31,8 @@
#include "mongo/platform/basic.h"
+#include <fmt/format.h>
+
#include "mongo/base/status.h"
#include "mongo/bson/mutable/document.h"
#include "mongo/config.h"
@@ -38,6 +40,7 @@
#include "mongo/db/auth/user_management_commands_parser.h"
#include "mongo/db/commands.h"
#include "mongo/db/commands/user_management_commands_common.h"
+#include "mongo/db/commands/user_management_commands_gen.h"
#include "mongo/db/jsobj.h"
#include "mongo/rpc/write_concern_error_detail.h"
#include "mongo/s/catalog/type_shard.h"
@@ -50,6 +53,7 @@ namespace mongo {
using std::string;
using std::stringstream;
using std::vector;
+using namespace fmt::literals;
namespace {
@@ -60,278 +64,138 @@ const WriteConcernOptions kMajorityWriteConcern(WriteConcernOptions::kMajority,
WriteConcernOptions::SyncMode::UNSET,
WriteConcernOptions::kWriteConcernTimeoutSharding);
-class CmdCreateUser : public BasicCommand {
-public:
- CmdCreateUser() : BasicCommand("createUser") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Adds a user to the system";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForCreateUserCommand(client, dbname, cmdObj);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- return Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
- }
+template <typename Request>
+void uassertEmptyReply(BSONObj obj) {
+ uassert(ErrorCodes::BadValue,
+ "Received unexpected response from {} command: {}"_format(Request::kCommandName,
+ tojson(obj)),
+ (obj.nFields() == 1) && obj["ok"]);
+}
+
+template <typename Request, typename Reply>
+Reply parseUMCReply(BSONObj obj) try {
+ return Reply::parse(IDLParserErrorContext(Request::kCommandName), obj);
+} catch (const AssertionException& ex) {
+ uasserted(ex.code(),
+ "Received invalid response from {} command: {}, error: {}"_format(
+ Request::kCommandName, tojson(obj), ex.reason()));
+}
+
+struct UserCacheInvalidatorNOOP {
+ static constexpr bool kRequireUserName = false;
+ static void invalidate(OperationContext*, StringData) {}
+};
+struct UserCacheInvalidatorUser {
+ static constexpr bool kRequireUserName = true;
+ static void invalidate(OperationContext* opCtx, const UserName& userName) {
+ AuthorizationManager::get(opCtx->getServiceContext())
+ ->invalidateUserByName(opCtx, userName);
+ }
+};
+struct UserCacheInvalidatorDB {
+ static constexpr bool kRequireUserName = false;
+ static void invalidate(OperationContext* opCtx, StringData dbname) {
+ AuthorizationManager::get(opCtx->getServiceContext())->invalidateUsersFromDB(opCtx, dbname);
+ }
+};
+struct UserCacheInvalidatorAll {
+ static constexpr bool kRequireUserName = false;
+ static void invalidate(OperationContext* opCtx, StringData) {
+ AuthorizationManager::get(opCtx->getServiceContext())->invalidateUserCache(opCtx);
+ }
+};
+/**
+ * Most user management commands follow a very predictable pattern:
+ * 1. Proxy command to config servers.
+ * 2. Invalidate whatever we were just working on.
+ * 3. Panic if anything went wrong.
+ */
+template <typename RequestT, typename ReplyT, typename InvalidatorT>
+class CmdUMCPassthrough : public TypedCommand<CmdUMCPassthrough<RequestT, ReplyT, InvalidatorT>> {
+public:
+ using Request = RequestT;
+ using Reply = ReplyT;
+ using TC = TypedCommand<CmdUMCPassthrough<RequestT, ReplyT, InvalidatorT>>;
+
+ class Invocation final : public TC::InvocationBase {
+ public:
+ using TC::InvocationBase::InvocationBase;
+ using TC::InvocationBase::request;
+
+ Reply typedRun(OperationContext* opCtx) {
+ const auto& cmd = request();
+
+ BSONObjBuilder builder;
+ auto status = Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
+ opCtx,
+ Request::kCommandName,
+ cmd.getDbName(),
+ applyReadWriteConcern(
+ opCtx,
+ this,
+ CommandHelpers::filterCommandRequestForPassthrough(cmd.toBSON({}))),
+ &builder);
+
+ if constexpr (InvalidatorT::kRequireUserName) {
+ InvalidatorT::invalidate(opCtx,
+ UserName(cmd.getCommandParameter(), cmd.getDbName()));
+ } else {
+ InvalidatorT::invalidate(opCtx, cmd.getDbName());
+ }
+
+ uassertStatusOK(status);
+
+ if constexpr (std::is_void_v<Reply>) {
+ uassertEmptyReply<Request>(builder.obj());
+ } else {
+ return parseUMCReply<Request, Reply>(builder.obj());
+ }
+ }
+
+ private:
+ bool supportsWriteConcern() const final {
+ return true;
+ }
+
+ void doCheckAuthorization(OperationContext* opCtx) const final {
+ auth::checkAuthForTypedCommand(opCtx->getClient(), request());
+ }
+
+ NamespaceString ns() const override {
+ return NamespaceString(request().getDbName(), "");
+ }
+ };
+
+ typename TC::AllowedOnSecondary secondaryAllowed(ServiceContext*) const final {
+ return TC::AllowedOnSecondary::kNever;
+ }
+};
+
+class CmdCreateUser : public CmdUMCPassthrough<CreateUserCommand, void, UserCacheInvalidatorNOOP> {
+public:
+ static constexpr StringData kPwdField = "pwd"_sd;
StringData sensitiveFieldName() const final {
- return "pwd"_sd;
+ return kPwdField;
}
-
} cmdCreateUser;
-class CmdUpdateUser : public BasicCommand {
+class CmdUpdateUser : public CmdUMCPassthrough<UpdateUserCommand, void, UserCacheInvalidatorUser> {
public:
- CmdUpdateUser() : BasicCommand("updateUser") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Used to update a user, for example to change its password";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForUpdateUserCommand(client, dbname, cmdObj);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- auth::CreateOrUpdateUserArgs args;
- Status status = auth::parseCreateOrUpdateUserCommands(cmdObj, getName(), dbname, &args);
- uassertStatusOK(status);
-
- const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
-
- const auto authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- authzManager->invalidateUserByName(opCtx, args.userName);
- return ok;
- }
-
+ static constexpr StringData kPwdField = "pwd"_sd;
StringData sensitiveFieldName() const final {
- return "pwd"_sd;
+ return kPwdField;
}
-
} cmdUpdateUser;
-class CmdDropUser : public BasicCommand {
-public:
- CmdDropUser() : BasicCommand("dropUser") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Drops a single user.";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForDropUserCommand(client, dbname, cmdObj);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- UserName userName;
- Status status = auth::parseAndValidateDropUserCommand(cmdObj, dbname, &userName);
- uassertStatusOK(status);
-
- const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
-
- const auto authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- authzManager->invalidateUserByName(opCtx, userName);
- return ok;
- }
-
-} cmdDropUser;
-
-class CmdDropAllUsersFromDatabase : public BasicCommand {
-public:
- CmdDropAllUsersFromDatabase() : BasicCommand("dropAllUsersFromDatabase") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Drops all users for a single database.";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForDropAllUsersFromDatabaseCommand(client, dbname);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
-
- const auto authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- authzManager->invalidateUsersFromDB(opCtx, dbname);
- return ok;
- }
-
-} cmdDropAllUsersFromDatabase;
-
-class CmdGrantRolesToUser : public BasicCommand {
-public:
- CmdGrantRolesToUser() : BasicCommand("grantRolesToUser") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Grants roles to a user.";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForGrantRolesToUserCommand(client, dbname, cmdObj);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- string userNameString;
- vector<RoleName> roles;
- Status status = auth::parseRolePossessionManipulationCommands(
- cmdObj, getName(), dbname, &userNameString, &roles);
- uassertStatusOK(status);
-
- const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
-
- const auto authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- authzManager->invalidateUserByName(opCtx, UserName(userNameString, dbname));
- return ok;
- }
-
-} cmdGrantRolesToUser;
-
-class CmdRevokeRolesFromUser : public BasicCommand {
-public:
- CmdRevokeRolesFromUser() : BasicCommand("revokeRolesFromUser") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Revokes roles from a user.";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForRevokeRolesFromUserCommand(client, dbname, cmdObj);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- string userNameString;
- vector<RoleName> unusedRoles;
- Status status = auth::parseRolePossessionManipulationCommands(
- cmdObj, getName(), dbname, &userNameString, &unusedRoles);
- uassertStatusOK(status);
-
- const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
-
- const auto authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- authzManager->invalidateUserByName(opCtx, UserName(userNameString, dbname));
- return ok;
- }
-
-} cmdRevokeRolesFromUser;
+CmdUMCPassthrough<DropUserCommand, void, UserCacheInvalidatorUser> cmdDropUser;
+CmdUMCPassthrough<DropAllUsersFromDatabaseCommand,
+ DropAllUsersFromDatabaseReply,
+ UserCacheInvalidatorDB>
+ cmdDropAllUsersFromDatabase;
+CmdUMCPassthrough<GrantRolesToUserCommand, void, UserCacheInvalidatorUser> cmdGrantRolesToUser;
+CmdUMCPassthrough<RevokeRolesFromUserCommand, void, UserCacheInvalidatorUser>
+ cmdRevokeRolesFromUser;
class CmdUsersInfo : public BasicCommand {
public:
@@ -369,338 +233,19 @@ public:
} cmdUsersInfo;
-class CmdCreateRole : public BasicCommand {
-public:
- CmdCreateRole() : BasicCommand("createRole") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Adds a role to the system";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForCreateRoleCommand(client, dbname, cmdObj);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- return Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
- }
-
-} cmdCreateRole;
-
-class CmdUpdateRole : public BasicCommand {
-public:
- CmdUpdateRole() : BasicCommand("updateRole") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Used to update a role";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForUpdateRoleCommand(client, dbname, cmdObj);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
-
- const auto authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- authzManager->invalidateUserCache(opCtx);
- return ok;
- }
-
-} cmdUpdateRole;
-
-class CmdGrantPrivilegesToRole : public BasicCommand {
-public:
- CmdGrantPrivilegesToRole() : BasicCommand("grantPrivilegesToRole") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Grants privileges to a role";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForGrantPrivilegesToRoleCommand(client, dbname, cmdObj);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
-
- const auto authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- authzManager->invalidateUserCache(opCtx);
- return ok;
- }
-
-} cmdGrantPrivilegesToRole;
-
-class CmdRevokePrivilegesFromRole : public BasicCommand {
-public:
- CmdRevokePrivilegesFromRole() : BasicCommand("revokePrivilegesFromRole") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Revokes privileges from a role";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForRevokePrivilegesFromRoleCommand(client, dbname, cmdObj);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
-
- const auto authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- authzManager->invalidateUserCache(opCtx);
- return ok;
- }
-
-} cmdRevokePrivilegesFromRole;
-
-class CmdGrantRolesToRole : public BasicCommand {
-public:
- CmdGrantRolesToRole() : BasicCommand("grantRolesToRole") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Grants roles to another role.";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForGrantRolesToRoleCommand(client, dbname, cmdObj);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
-
- const auto authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- authzManager->invalidateUserCache(opCtx);
- return ok;
- }
-
-} cmdGrantRolesToRole;
-
-class CmdRevokeRolesFromRole : public BasicCommand {
-public:
- CmdRevokeRolesFromRole() : BasicCommand("revokeRolesFromRole") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Revokes roles from another role.";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForRevokeRolesFromRoleCommand(client, dbname, cmdObj);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
-
- const auto authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- authzManager->invalidateUserCache(opCtx);
- return ok;
- }
-
-} cmdRevokeRolesFromRole;
-
-class CmdDropRole : public BasicCommand {
-public:
- CmdDropRole() : BasicCommand("dropRole") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Drops a single role. Before deleting the role completely it must remove it "
- "from any users or roles that reference it. If any errors occur in the middle "
- "of that process it's possible to be left in a state where the role has been "
- "removed from some user/roles but otherwise still exists.";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForDropRoleCommand(client, dbname, cmdObj);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
-
- const auto authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- authzManager->invalidateUserCache(opCtx);
- return ok;
- }
-
-} cmdDropRole;
-
-class CmdDropAllRolesFromDatabase : public BasicCommand {
-public:
- CmdDropAllRolesFromDatabase() : BasicCommand("dropAllRolesFromDatabase") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kNever;
- }
-
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return true;
- }
-
- std::string help() const override {
- return "Drops all roles from the given database. Before deleting the roles completely "
- "it must remove them from any users or other roles that reference them. If any "
- "errors occur in the middle of that process it's possible to be left in a state "
- "where the roles have been removed from some user/roles but otherwise still "
- "exist.";
- }
-
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const {
- return auth::checkAuthForDropAllRolesFromDatabaseCommand(client, dbname);
- }
-
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
- opCtx,
- getName(),
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
-
- const auto authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- authzManager->invalidateUserCache(opCtx);
- return ok;
- }
-
-} cmdDropAllRolesFromDatabase;
+CmdUMCPassthrough<CreateRoleCommand, void, UserCacheInvalidatorNOOP> cmdCreateRole;
+CmdUMCPassthrough<UpdateRoleCommand, void, UserCacheInvalidatorAll> cmdUpdateRole;
+CmdUMCPassthrough<GrantPrivilegesToRoleCommand, void, UserCacheInvalidatorAll>
+ cmdGrantPrivilegesToRole;
+CmdUMCPassthrough<RevokePrivilegesFromRoleCommand, void, UserCacheInvalidatorAll>
+ cmdRevokePrivilegesFromRole;
+CmdUMCPassthrough<GrantRolesToRoleCommand, void, UserCacheInvalidatorAll> cmdGrantRolesToRole;
+CmdUMCPassthrough<RevokeRolesFromRoleCommand, void, UserCacheInvalidatorAll> cmdRevokeRolesFromRole;
+CmdUMCPassthrough<DropRoleCommand, void, UserCacheInvalidatorAll> cmdDropRole;
+CmdUMCPassthrough<DropAllRolesFromDatabaseCommand,
+ DropAllRolesFromDatabaseReply,
+ UserCacheInvalidatorAll>
+ cmdDropAllRolesFromDatabase;
class CmdRolesInfo : public BasicCommand {
public:
@@ -816,13 +361,14 @@ public:
const string& dbname,
const BSONObj& cmdObj,
BSONObjBuilder& result) {
- return Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
+ uassertStatusOK(Grid::get(opCtx)->catalogClient()->runUserManagementWriteCommand(
opCtx,
getName(),
dbname,
applyReadWriteConcern(
opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- &result);
+ &result));
+ return true;
}
} cmdMergeAuthzCollections;