summaryrefslogtreecommitdiff
path: root/src/mongo/db/commands
diff options
context:
space:
mode:
authorSara Golemon <sara.golemon@mongodb.com>2020-10-26 17:26:31 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-11-09 18:16:52 +0000
commit5e0d73d0d8e559e34203740af93b6ca03d573ea5 (patch)
tree3ddc4e4ddde8af5fb575ffe819d0bb4b3acee271 /src/mongo/db/commands
parentfa826f6a5b77eb059fe03d411276c3ee7eb303d5 (diff)
downloadmongo-5e0d73d0d8e559e34203740af93b6ca03d573ea5.tar.gz
SERVER-51864 IDLify usersInfo and rolesInfo commands
Diffstat (limited to 'src/mongo/db/commands')
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp360
-rw-r--r--src/mongo/db/commands/user_management_commands.idl88
-rw-r--r--src/mongo/db/commands/user_management_commands_common.cpp104
-rw-r--r--src/mongo/db/commands/user_management_commands_common.h10
4 files changed, 296 insertions, 266 deletions
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index bdc40e745cb..44edd0d4fd8 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -906,12 +906,24 @@ private:
TransactionState _state = TransactionState::kInit;
};
-template <typename RequestT, typename ReplyT>
-class CmdUMCTyped : public TypedCommand<CmdUMCTyped<RequestT, ReplyT>> {
+// Used by most UMC commands.
+struct UMCStdParams {
+ static constexpr bool supportsWriteConcern = true;
+ static constexpr auto allowedOnSecondary = BasicCommand::AllowedOnSecondary::kNever;
+};
+
+// Used by {usersInfo:...} and {rolesInfo:...}
+struct UMCInfoParams {
+ static constexpr bool supportsWriteConcern = false;
+ static constexpr auto allowedOnSecondary = BasicCommand::AllowedOnSecondary::kOptIn;
+};
+
+template <typename RequestT, typename ReplyT, typename Params = UMCStdParams>
+class CmdUMCTyped : public TypedCommand<CmdUMCTyped<RequestT, ReplyT, Params>> {
public:
using Request = RequestT;
using Reply = ReplyT;
- using TC = TypedCommand<CmdUMCTyped<RequestT, ReplyT>>;
+ using TC = TypedCommand<CmdUMCTyped<RequestT, ReplyT, Params>>;
class Invocation final : public TC::InvocationBase {
public:
@@ -922,7 +934,7 @@ public:
private:
bool supportsWriteConcern() const final {
- return true;
+ return Params::supportsWriteConcern;
}
void doCheckAuthorization(OperationContext* opCtx) const final {
@@ -935,7 +947,7 @@ public:
};
typename TC::AllowedOnSecondary secondaryAllowed(ServiceContext*) const final {
- return TC::AllowedOnSecondary::kNever;
+ return Params::allowedOnSecondary;
}
};
@@ -1282,160 +1294,134 @@ void CmdUMCTyped<RevokeRolesFromUserCommand, void>::Invocation::typedRun(Operati
uassertStatusOK(status);
}
-class CmdUsersInfo : public BasicCommand {
-public:
- CmdUsersInfo() : BasicCommand("usersInfo") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kOptIn;
- }
-
- bool supportsWriteConcern(const BSONObj& cmd) const override {
- return false;
- }
+CmdUMCTyped<UsersInfoCommand, UsersInfoReply, UMCInfoParams> cmdUsersInfo;
+template <>
+UsersInfoReply CmdUMCTyped<UsersInfoCommand, UsersInfoReply, UMCInfoParams>::Invocation::typedRun(
+ OperationContext* opCtx) {
+ const auto& cmd = request();
+ const auto& arg = cmd.getCommandParameter();
+ const auto& dbname = cmd.getDbName();
- std::string help() const override {
- return "Returns information about users.";
- }
+ auto* authzManager = AuthorizationManager::get(opCtx->getServiceContext());
+ auto lk = uassertStatusOK(requireReadableAuthSchema26Upgrade(opCtx, authzManager));
- Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const override {
- return auth::checkAuthForUsersInfoCommand(client, dbname, cmdObj);
- }
+ std::vector<BSONObj> users;
+ if (cmd.getShowPrivileges() || cmd.getShowAuthenticationRestrictions()) {
+ uassert(ErrorCodes::IllegalOperation,
+ "Privilege or restriction details require exact-match usersInfo queries",
+ !cmd.getFilter() && arg.isExact());
+
+ // If you want privileges or restrictions you need to call getUserDescription
+ // on each user.
+ for (const auto& userName : arg.getElements(dbname)) {
+ BSONObj userDetails;
+ auto status = authzManager->getUserDescription(opCtx, userName, &userDetails);
+ if (status.code() == ErrorCodes::UserNotFound) {
+ continue;
+ }
+ uassertStatusOK(status);
- bool run(OperationContext* opCtx,
- const std::string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) override {
- auth::UsersInfoArgs args;
- uassertStatusOK(auth::parseUsersInfoCommand(cmdObj, dbname, &args));
-
- auto* authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- auto lk = uassertStatusOK(requireReadableAuthSchema26Upgrade(opCtx, authzManager));
-
- BSONArrayBuilder usersArrayBuilder(result.subarrayStart("users"));
- if (args.showPrivileges ||
- (args.authenticationRestrictionsFormat == AuthenticationRestrictionsFormat::kShow)) {
- uassert(ErrorCodes::IllegalOperation,
- "Privilege or restriction details require exact-match usersInfo queries",
- !args.filter && (args.target == auth::UsersInfoArgs::Target::kExplicitUsers));
-
- // If you want privileges or restrictions you need to call getUserDescription
- // on each user.
- for (const auto& userName : args.userNames) {
- BSONObj userDetails;
- auto status = authzManager->getUserDescription(opCtx, userName, &userDetails);
- if (status.code() == ErrorCodes::UserNotFound) {
- continue;
- }
- uassertStatusOK(status);
-
- // getUserDescription always includes credentials and restrictions, which may need
- // to be stripped out
- BSONObjBuilder strippedUser(usersArrayBuilder.subobjStart());
- for (const BSONElement& e : userDetails) {
- if (e.fieldNameStringData() == "credentials") {
- BSONArrayBuilder mechanismNamesBuilder;
- BSONObj mechanismsObj = e.Obj();
- for (const BSONElement& mechanismElement : mechanismsObj) {
- mechanismNamesBuilder.append(mechanismElement.fieldNameStringData());
- }
- strippedUser.append("mechanisms", mechanismNamesBuilder.arr());
-
- if (!args.showCredentials) {
- continue;
- }
+ // getUserDescription always includes credentials and restrictions, which may need
+ // to be stripped out
+ BSONObjBuilder strippedUser;
+ for (const BSONElement& e : userDetails) {
+ if (e.fieldNameStringData() == "credentials") {
+ BSONArrayBuilder mechanismNamesBuilder;
+ BSONObj mechanismsObj = e.Obj();
+ for (const BSONElement& mechanismElement : mechanismsObj) {
+ mechanismNamesBuilder.append(mechanismElement.fieldNameStringData());
}
+ strippedUser.append("mechanisms", mechanismNamesBuilder.arr());
- if (e.fieldNameStringData() == "authenticationRestrictions" &&
- args.authenticationRestrictionsFormat ==
- AuthenticationRestrictionsFormat::kOmit) {
+ if (!cmd.getShowCredentials()) {
continue;
}
-
- strippedUser.append(e);
}
- strippedUser.doneFast();
- }
- } else {
- // If you don't need privileges, or authenticationRestrictions, you can just do a
- // regular query on system.users
- std::vector<BSONObj> pipeline;
-
- if (args.target == auth::UsersInfoArgs::Target::kGlobal) {
- // Leave the pipeline unconstrained, we want to return every user.
- } else if (args.target == auth::UsersInfoArgs::Target::kDB) {
- pipeline.push_back(
- BSON("$match" << BSON(AuthorizationManager::USER_DB_FIELD_NAME << dbname)));
- } else {
- BSONArrayBuilder usersMatchArray;
- for (size_t i = 0; i < args.userNames.size(); ++i) {
- usersMatchArray.append(BSON(AuthorizationManager::USER_NAME_FIELD_NAME
- << args.userNames[i].getUser()
- << AuthorizationManager::USER_DB_FIELD_NAME
- << args.userNames[i].getDB()));
+
+ if ((e.fieldNameStringData() == "authenticationRestrictions") &&
+ !cmd.getShowAuthenticationRestrictions()) {
+ continue;
}
- pipeline.push_back(BSON("$match" << BSON("$or" << usersMatchArray.arr())));
- }
- // Order results by user field then db field, matching how UserNames are ordered
- pipeline.push_back(BSON("$sort" << BSON("user" << 1 << "db" << 1)));
+ strippedUser.append(e);
+ }
+ users.push_back(strippedUser.obj());
+ }
+ } else {
+ // If you don't need privileges, or authenticationRestrictions, you can just do a
+ // regular query on system.users
+ std::vector<BSONObj> pipeline;
- // Rewrite the credentials object into an array of its fieldnames.
+ if (arg.isAllForAllDBs()) {
+ // Leave the pipeline unconstrained, we want to return every user.
+ } else if (arg.isAllOnCurrentDB()) {
pipeline.push_back(
- BSON("$addFields" << BSON("mechanisms"
- << BSON("$map" << BSON("input" << BSON("$objectToArray"
- << "$credentials")
- << "as"
- << "cred"
- << "in"
- << "$$cred.k")))));
-
- if (args.showCredentials) {
- // Authentication restrictions are only rendered in the single user case.
- pipeline.push_back(BSON("$unset"
- << "authenticationRestrictions"));
- } else {
- // Remove credentials as well, they're not required in the output
- pipeline.push_back(BSON("$unset" << BSON_ARRAY("authenticationRestrictions"
- << "credentials")));
+ BSON("$match" << BSON(AuthorizationManager::USER_DB_FIELD_NAME << dbname)));
+ } else {
+ invariant(arg.isExact());
+ BSONArrayBuilder usersMatchArray;
+ for (const auto& userName : arg.getElements(dbname)) {
+ usersMatchArray.append(userName.toBSON());
}
+ pipeline.push_back(BSON("$match" << BSON("$or" << usersMatchArray.arr())));
+ }
- // Handle a user specified filter.
- if (args.filter) {
- pipeline.push_back(BSON("$match" << *args.filter));
- }
+ // Order results by user field then db field, matching how UserNames are ordered
+ pipeline.push_back(BSON("$sort" << BSON("user" << 1 << "db" << 1)));
+
+ // Rewrite the credentials object into an array of its fieldnames.
+ pipeline.push_back(
+ BSON("$addFields" << BSON("mechanisms"
+ << BSON("$map" << BSON("input" << BSON("$objectToArray"
+ << "$credentials")
+ << "as"
+ << "cred"
+ << "in"
+ << "$$cred.k")))));
+
+ if (cmd.getShowCredentials()) {
+ // Authentication restrictions are only rendered in the single user case.
+ pipeline.push_back(BSON("$unset"
+ << "authenticationRestrictions"));
+ } else {
+ // Remove credentials as well, they're not required in the output
+ pipeline.push_back(BSON("$unset" << BSON_ARRAY("authenticationRestrictions"
+ << "credentials")));
+ }
- DBDirectClient client(opCtx);
-
- rpc::OpMsgReplyBuilder replyBuilder;
- AggregationRequest aggRequest(AuthorizationManager::usersCollectionNamespace,
- std::move(pipeline));
- // Impose no cursor privilege requirements, as cursor is drained internally
- uassertStatusOK(runAggregate(opCtx,
- AuthorizationManager::usersCollectionNamespace,
- aggRequest,
- aggRequest.serializeToCommandObj().toBson(),
- PrivilegeVector(),
- &replyBuilder));
- auto bodyBuilder = replyBuilder.getBodyBuilder();
- CommandHelpers::appendSimpleCommandStatus(bodyBuilder, true);
- bodyBuilder.doneFast();
- auto response = CursorResponse::parseFromBSONThrowing(replyBuilder.releaseBody());
- DBClientCursor cursor(
- &client, response.getNSS(), response.getCursorId(), 0, 0, response.releaseBatch());
-
- while (cursor.more()) {
- usersArrayBuilder.append(cursor.next());
- }
+ // Handle a user specified filter.
+ if (auto filter = cmd.getFilter()) {
+ pipeline.push_back(BSON("$match" << *filter));
}
- usersArrayBuilder.doneFast();
- return true;
+ DBDirectClient client(opCtx);
+
+ rpc::OpMsgReplyBuilder replyBuilder;
+ AggregationRequest aggRequest(AuthorizationManager::usersCollectionNamespace,
+ std::move(pipeline));
+ // Impose no cursor privilege requirements, as cursor is drained internally
+ uassertStatusOK(runAggregate(opCtx,
+ AuthorizationManager::usersCollectionNamespace,
+ aggRequest,
+ aggRequest.serializeToCommandObj().toBson(),
+ PrivilegeVector(),
+ &replyBuilder));
+ auto bodyBuilder = replyBuilder.getBodyBuilder();
+ CommandHelpers::appendSimpleCommandStatus(bodyBuilder, true);
+ bodyBuilder.doneFast();
+ auto response = CursorResponse::parseFromBSONThrowing(replyBuilder.releaseBody());
+ DBClientCursor cursor(
+ &client, response.getNSS(), response.getCursorId(), 0, 0, response.releaseBatch());
+
+ while (cursor.more()) {
+ users.push_back(cursor.next().getOwned());
+ }
}
-} cmdUsersInfo;
+ UsersInfoReply reply;
+ reply.setUsers(std::move(users));
+ return reply;
+}
CmdUMCTyped<CreateRoleCommand, void> cmdCreateRole;
template <>
@@ -1907,71 +1893,55 @@ CmdUMCTyped<DropAllRolesFromDatabaseCommand, DropAllRolesFromDatabaseReply>::Inv
* these roles. This format may change over time with changes to the auth
* schema.
*/
-class CmdRolesInfo : public BasicCommand {
-public:
- CmdRolesInfo() : BasicCommand("rolesInfo") {}
-
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kOptIn;
- }
-
- bool supportsWriteConcern(const BSONObj& cmd) const override {
- return false;
- }
+CmdUMCTyped<RolesInfoCommand, RolesInfoReply, UMCInfoParams> cmdRolesInfo;
+template <>
+RolesInfoReply CmdUMCTyped<RolesInfoCommand, RolesInfoReply, UMCInfoParams>::Invocation::typedRun(
+ OperationContext* opCtx) {
+ const auto& cmd = request();
+ const auto& arg = cmd.getCommandParameter();
+ const auto& dbname = cmd.getDbName();
- std::string help() const override {
- return "Returns information about roles.";
- }
+ auto* authzManager = AuthorizationManager::get(opCtx->getServiceContext());
+ auto lk = uassertStatusOK(requireReadableAuthSchema26Upgrade(opCtx, authzManager));
- Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) const override {
- return auth::checkAuthForRolesInfoCommand(client, dbname, cmdObj);
- }
+ // Only usersInfo actually supports {forAllDBs: 1} mode.
+ invariant(!arg.isAllForAllDBs());
- bool run(OperationContext* opCtx,
- const std::string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) override {
- auth::RolesInfoArgs args;
- uassertStatusOK(auth::parseRolesInfoCommand(cmdObj, dbname, &args));
+ auto privFmt = *(cmd.getShowPrivileges());
+ auto restrictionFormat = cmd.getShowAuthenticationRestrictions()
+ ? AuthenticationRestrictionsFormat::kShow
+ : AuthenticationRestrictionsFormat::kOmit;
- AuthorizationManager* authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- auto lk = uassertStatusOK(requireReadableAuthSchema26Upgrade(opCtx, authzManager));
+ RolesInfoReply reply;
+ if (arg.isAllOnCurrentDB()) {
- if (args.allForDB) {
- if (args.privilegeFormat == PrivilegeFormat::kShowAsUserFragment) {
- uasserted(ErrorCodes::IllegalOperation,
- "Cannot get user fragment for all roles in a database");
- }
+ uassert(ErrorCodes::IllegalOperation,
+ "Cannot get user fragment for all roles in a database",
+ privFmt != PrivilegeFormat::kShowAsUserFragment);
- BSONArrayBuilder rolesBuilder(result.subarrayStart("roles"));
- uassertStatusOK(
- authzManager->getRoleDescriptionsForDB(opCtx,
- dbname,
- args.privilegeFormat,
- args.authenticationRestrictionsFormat,
- args.showBuiltinRoles,
- &rolesBuilder));
+ std::vector<BSONObj> roles;
+ uassertStatusOK(authzManager->getRoleDescriptionsForDB(
+ opCtx, dbname, privFmt, restrictionFormat, cmd.getShowBuiltinRoles(), &roles));
+ reply.setRoles(std::move(roles));
+ } else {
+ invariant(arg.isExact());
+ auto roleNames = arg.getElements(dbname);
+
+ if (privFmt == PrivilegeFormat::kShowAsUserFragment) {
+ BSONObj fragment;
+ uassertStatusOK(authzManager->getRolesAsUserFragment(
+ opCtx, roleNames, restrictionFormat, &fragment));
+ reply.setUserFragment(fragment);
} else {
- BSONObj roleDetails;
- uassertStatusOK(authzManager->getRolesDescription(opCtx,
- args.roleNames,
- args.privilegeFormat,
- args.authenticationRestrictionsFormat,
- &roleDetails));
-
- if (args.privilegeFormat == PrivilegeFormat::kShowAsUserFragment) {
- result.append("userFragment", roleDetails);
- } else {
- result.append("roles", BSONArray(roleDetails));
- }
+ std::vector<BSONObj> roles;
+ uassertStatusOK(authzManager->getRolesDescription(
+ opCtx, roleNames, privFmt, restrictionFormat, &roles));
+ reply.setRoles(std::move(roles));
}
-
- return true;
}
-} cmdRolesInfo;
+ return reply;
+}
class CmdInvalidateUserCache : public BasicCommand {
public:
diff --git a/src/mongo/db/commands/user_management_commands.idl b/src/mongo/db/commands/user_management_commands.idl
index 406b5924164..0dfbdd9fb17 100644
--- a/src/mongo/db/commands/user_management_commands.idl
+++ b/src/mongo/db/commands/user_management_commands.idl
@@ -32,6 +32,7 @@ imports:
- "mongo/idl/basic_types.idl"
- "mongo/db/auth/auth_types.idl"
- "mongo/db/auth/address_restriction.idl"
+ - "mongo/db/auth/user_management_commands_parser.idl"
server_parameters:
enforceUserClusterSeparation:
@@ -60,6 +61,27 @@ structs:
type: int
cpp_name: count
+ usersInfoReply:
+ description: "Reply from usersInfo command"
+ strict: false
+ fields:
+ users:
+ description: "Users descriptions"
+ type: array<object_owned>
+
+ rolesInfoReply:
+ description: "Reply from usersInfo command"
+ strict: false
+ fields:
+ roles:
+ description: "Users descriptions"
+ type: array<object_owned>
+ optional: true
+ userFragment:
+ description: "Roles as user document fragment"
+ type: object_owned
+ optional: true
+
UMCTransactionFailPoint:
description: Data for umcTransaction failpoint
fields:
@@ -90,7 +112,7 @@ commands:
type: array<RoleNameOrString>
digestPassword:
description: "True if the server should digest the password, false for pre-digested"
- type: bool
+ type: safeBool
default: true
writeConcern:
description: "The level of write concern for the creation operation"
@@ -127,7 +149,7 @@ commands:
optional: true
digestPassword:
description: "True if the server should digest the password, false for pre-digested"
- type: bool
+ type: safeBool
default: true
writeConcern:
description: "The level of write concern for the update operation"
@@ -291,3 +313,65 @@ commands:
namespace: ignored
cpp_name: DropAllRolesFromDatabaseCommand
strict: true
+
+ usersInfo:
+ description: "Returns information about users."
+ command_name: usersInfo
+ namespace: type
+ type: UsersInfoCommandArg
+ cpp_name: UsersInfoCommand
+ strict: true
+ fields:
+ showPrivileges:
+ description: >-
+ Set the field to true to show the user’s full set of privileges,
+ including expanded information for the inherited roles.
+ If viewing all users, you cannot specify this field.
+ type: safeBool
+ default: false
+ showCredentials:
+ description: >-
+ Set the field to true to display the user’s password hash.
+ type: safeBool
+ default: false
+ showAuthenticationRestrictions:
+ description: >-
+ Set the field to true to show the user’s authentication restrictions.
+ If viewing all users, you cannot specify this field.
+ type: safeBool
+ default: false
+ filter:
+ description: >-
+ A document that specifies $match stage conditions to return information
+ for users that match the filter conditions.
+ type: object
+ optional: true
+
+ rolesInfo:
+ description: "returns information about roles."
+ command_name: rolesInfo
+ namespace: type
+ type: RolesInfoCommandArg
+ cpp_name: RolesInfoCommand
+ strict: true
+ fields:
+ showPrivileges:
+ description: >-
+ Set the field to true to show the user’s full set of privileges,
+ including expanded information for the inherited roles.
+ If viewing all roles, you cannot specify this field.
+ type: ParsedPrivilegeFormat
+ default: false
+ showBuiltinRoles:
+ description: >-
+ When the rolesInfo field is set to 1, set showBuiltinRoles to true
+ to include built-in roles in the output.
+ Otherwise the output for rolesInfo: 1 displays only user-defined roles.
+ type: safeBool
+ default: false
+ showAuthenticationRestrictions:
+ description: >-
+ Set the field to true to show the user’s authentication restrictions.
+ If viewing all users, you cannot specify this field.
+ type: safeBool
+ default: false
diff --git a/src/mongo/db/commands/user_management_commands_common.cpp b/src/mongo/db/commands/user_management_commands_common.cpp
index d10742585a1..06c4f2683ea 100644
--- a/src/mongo/db/commands/user_management_commands_common.cpp
+++ b/src/mongo/db/commands/user_management_commands_common.cpp
@@ -273,45 +273,35 @@ void checkAuthForTypedCommand(Client* client, const RevokeRolesFromRoleCommand&
uassertStatusOK(checkAuthorizedToRevokeRoles(as, rolesToRemove));
}
-Status checkAuthForUsersInfoCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) {
- AuthorizationSession* authzSession = AuthorizationSession::get(client);
- auth::UsersInfoArgs args;
- Status status = auth::parseUsersInfoCommand(cmdObj, dbname, &args);
- if (!status.isOK()) {
- return status;
- }
+void checkAuthForTypedCommand(Client* client, const UsersInfoCommand& request) {
+ const auto& dbname = request.getDbName();
+ const auto& arg = request.getCommandParameter();
+ auto* as = AuthorizationSession::get(client);
- if (args.target == auth::UsersInfoArgs::Target::kDB) {
- if (!authzSession->isAuthorizedForActionsOnResource(
- ResourcePattern::forDatabaseName(dbname), ActionType::viewUser)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream()
- << "Not authorized to view users from the " << dbname << " database");
- }
- } else if (args.target == auth::UsersInfoArgs::Target::kGlobal) {
- if (!authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
- ActionType::viewUser)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "Not authorized to view users from all"
- << " databases");
- }
+ if (arg.isAllOnCurrentDB()) {
+ uassert(ErrorCodes::Unauthorized,
+ str::stream() << "Not authorized to view users from the " << dbname << " database",
+ as->isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(dbname),
+ ActionType::viewUser));
+ } else if (arg.isAllForAllDBs()) {
+ uassert(ErrorCodes::Unauthorized,
+ str::stream() << "Not authorized to view users from all databases",
+ as->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
+ ActionType::viewUser));
} else {
- for (size_t i = 0; i < args.userNames.size(); ++i) {
- if (authzSession->lookupUser(args.userNames[i])) {
- continue; // Can always view users you are logged in as
- }
- if (!authzSession->isAuthorizedForActionsOnResource(
- ResourcePattern::forDatabaseName(args.userNames[i].getDB()),
- ActionType::viewUser)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "Not authorized to view users from the " << dbname
- << " database");
+ invariant(arg.isExact());
+ for (const auto& userName : arg.getElements(dbname)) {
+ if (as->lookupUser(userName)) {
+ // Can always view users you are logged in as.
+ continue;
}
+ uassert(ErrorCodes::Unauthorized,
+ str::stream() << "Not authorized to view users from the " << dbname
+ << " database",
+ as->isAuthorizedForActionsOnResource(
+ ResourcePattern::forDatabaseName(userName.getDB()), ActionType::viewUser));
}
}
- return Status::OK();
}
void checkAuthForTypedCommand(Client* client, const RevokePrivilegesFromRoleCommand& request) {
@@ -328,40 +318,32 @@ void checkAuthForTypedCommand(Client* client, const DropAllRolesFromDatabaseComm
ActionType::dropRole));
}
-Status checkAuthForRolesInfoCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) {
- AuthorizationSession* authzSession = AuthorizationSession::get(client);
- auth::RolesInfoArgs args;
- Status status = auth::parseRolesInfoCommand(cmdObj, dbname, &args);
- if (!status.isOK()) {
- return status;
- }
+void checkAuthForTypedCommand(Client* client, const RolesInfoCommand& request) {
+ const auto& dbname = request.getDbName();
+ const auto& arg = request.getCommandParameter();
+ auto* as = AuthorizationSession::get(client);
- if (args.allForDB) {
- if (!authzSession->isAuthorizedForActionsOnResource(
- ResourcePattern::forDatabaseName(dbname), ActionType::viewRole)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream()
- << "Not authorized to view roles from the " << dbname << " database");
- }
+ invariant(!arg.isAllForAllDBs());
+ if (arg.isAllOnCurrentDB()) {
+ uassert(ErrorCodes::Unauthorized,
+ str::stream() << "Not authorized to view roles from the " << dbname << " database",
+ as->isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(dbname),
+ ActionType::viewRole));
} else {
- for (size_t i = 0; i < args.roleNames.size(); ++i) {
- if (authzSession->isAuthenticatedAsUserWithRole(args.roleNames[i])) {
+ invariant(arg.isExact());
+ auto roles = arg.getElements(dbname);
+ for (const auto& role : roles) {
+ if (as->isAuthenticatedAsUserWithRole(role)) {
continue; // Can always see roles that you are a member of
}
- if (!authzSession->isAuthorizedForActionsOnResource(
- ResourcePattern::forDatabaseName(args.roleNames[i].getDB()),
- ActionType::viewRole)) {
- return Status(ErrorCodes::Unauthorized,
- str::stream() << "Not authorized to view roles from the "
- << args.roleNames[i].getDB() << " database");
- }
+ uassert(ErrorCodes::Unauthorized,
+ str::stream() << "Not authorized to view roles from the " << role.getDB()
+ << " database",
+ as->isAuthorizedForActionsOnResource(
+ ResourcePattern::forDatabaseName(role.getDB()), ActionType::viewRole));
}
}
-
- return Status::OK();
}
Status checkAuthForInvalidateUserCacheCommand(Client* client) {
diff --git a/src/mongo/db/commands/user_management_commands_common.h b/src/mongo/db/commands/user_management_commands_common.h
index 7bc4caaffe3..3e162039d9f 100644
--- a/src/mongo/db/commands/user_management_commands_common.h
+++ b/src/mongo/db/commands/user_management_commands_common.h
@@ -93,14 +93,8 @@ void checkAuthForTypedCommand(Client*, const DropUserCommand&);
void checkAuthForTypedCommand(Client*, const DropRoleCommand&);
void checkAuthForTypedCommand(Client*, const RevokePrivilegesFromRoleCommand&);
void checkAuthForTypedCommand(Client*, const DropAllRolesFromDatabaseCommand&);
-
-Status checkAuthForUsersInfoCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj);
-
-Status checkAuthForRolesInfoCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj);
+void checkAuthForTypedCommand(Client*, const UsersInfoCommand&);
+void checkAuthForTypedCommand(Client*, const RolesInfoCommand&);
Status checkAuthForInvalidateUserCacheCommand(Client* client);