summaryrefslogtreecommitdiff
path: root/src/mongo/db/commands/user_management_commands.cpp
diff options
context:
space:
mode:
authorVarun Ravichandran <varun.ravichandran@mongodb.com>2021-10-12 20:19:24 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-10-19 14:55:51 +0000
commit13d81879027e51742205433d4b3573a0c9dbeaec (patch)
tree8241148d3dcaf240c6f4c827e446c297672df9a2 /src/mongo/db/commands/user_management_commands.cpp
parent40b6c60df9c863a1f473287fcc139f71dcd2954a (diff)
downloadmongo-13d81879027e51742205433d4b3573a0c9dbeaec.tar.gz
SERVER-60425: Cache users during exact-match usersInfo commands
Diffstat (limited to 'src/mongo/db/commands/user_management_commands.cpp')
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp94
1 files changed, 60 insertions, 34 deletions
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index 28c1590e8d5..8944e3cdb52 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -1343,41 +1343,64 @@ UsersInfoReply CmdUMCTyped<UsersInfoCommand, UMCInfoParams>::Invocation::typedRu
"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.
+ // Exact-match usersInfo queries can be optimized to utilize the user cache if custom data
+ // can be omitted. This is especially helpful when config servers execute exact-match
+ // usersInfo queries on behalf of mongoses gathering roles + privileges for recently
+ // authenticated users.
for (const auto& userName : arg.getElements(dbname)) {
- 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;
- for (const BSONElement& e : userDetails) {
- if (e.fieldNameStringData() == "credentials") {
- BSONArrayBuilder mechanismNamesBuilder;
- BSONObj mechanismsObj = e.Obj();
- for (const BSONElement& mechanismElement : mechanismsObj) {
- mechanismNamesBuilder.append(mechanismElement.fieldNameStringData());
+ if (cmd.getShowCustomData()) {
+ 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;
+ 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 (!cmd.getShowCredentials()) {
+ continue;
+ }
}
- strippedUser.append("mechanisms", mechanismNamesBuilder.arr());
- if (!cmd.getShowCredentials()) {
+ if ((e.fieldNameStringData() == "authenticationRestrictions") &&
+ !cmd.getShowAuthenticationRestrictions()) {
continue;
}
- }
- if ((e.fieldNameStringData() == "authenticationRestrictions") &&
- !cmd.getShowAuthenticationRestrictions()) {
+ strippedUser.append(e);
+ }
+ users.push_back(strippedUser.obj());
+ } else {
+ // Custom data is not required in the output, so it can be generated from a cached
+ // user object.
+ auto swUserHandle = authzManager->acquireUser(opCtx, userName);
+ if (swUserHandle.getStatus().code() == ErrorCodes::UserNotFound) {
continue;
}
-
- strippedUser.append(e);
+ UserHandle user = uassertStatusOK(swUserHandle);
+
+ // The returned User object will need to be marshalled back into a BSON document and
+ // stripped of credentials and restrictions if they were not explicitly requested.
+ BSONObjBuilder userObjBuilder;
+ user->reportForUsersInfo(&userObjBuilder,
+ cmd.getShowCredentials(),
+ cmd.getShowPrivileges(),
+ cmd.getShowAuthenticationRestrictions());
+ BSONObj userObj = userObjBuilder.obj();
+ users.push_back(userObj);
+ userObjBuilder.doneFast();
}
- users.push_back(strippedUser.obj());
}
} else {
// If you don't need privileges, or authenticationRestrictions, you can just do a
@@ -1411,15 +1434,18 @@ UsersInfoReply CmdUMCTyped<UsersInfoCommand, UMCInfoParams>::Invocation::typedRu
<< "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")));
+ // Authentication restrictions are only rendered in the single user case.
+ BSONArrayBuilder fieldsToRemoveBuilder;
+ fieldsToRemoveBuilder.append("authenticationRestrictions");
+ if (!cmd.getShowCredentials()) {
+ // Remove credentials as well, they're not required in the output.
+ fieldsToRemoveBuilder.append("credentials");
+ }
+ if (!cmd.getShowCustomData()) {
+ // Remove customData as well, it's not required in the output.
+ fieldsToRemoveBuilder.append("customData");
}
+ pipeline.push_back(BSON("$unset" << fieldsToRemoveBuilder.arr()));
// Handle a user specified filter.
if (auto filter = cmd.getFilter()) {