diff options
author | Sara Golemon <sara.golemon@mongodb.com> | 2020-06-23 14:20:48 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-07-02 15:34:37 +0000 |
commit | ebe622f95a071d7d769298b68ecf45b6cdff8e39 (patch) | |
tree | 28fe923dbe17deac6e73fffcac4074d9d860c72c /src/mongo/s | |
parent | 986028e17b939b4246b3d071ca6945a15604f0fc (diff) | |
download | mongo-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.h | 10 | ||||
-rw-r--r-- | src/mongo/s/catalog/sharding_catalog_client_impl.cpp | 52 | ||||
-rw-r--r-- | src/mongo/s/catalog/sharding_catalog_client_impl.h | 10 | ||||
-rw-r--r-- | src/mongo/s/catalog/sharding_catalog_client_mock.cpp | 8 | ||||
-rw-r--r-- | src/mongo/s/catalog/sharding_catalog_client_mock.h | 12 | ||||
-rw-r--r-- | src/mongo/s/catalog/sharding_catalog_test.cpp | 71 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_user_management_commands.cpp | 738 |
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; |