diff options
author | Varun Ravichandran <varun.ravichandran@mongodb.com> | 2021-10-12 20:19:24 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-10-19 14:55:51 +0000 |
commit | 13d81879027e51742205433d4b3573a0c9dbeaec (patch) | |
tree | 8241148d3dcaf240c6f4c827e446c297672df9a2 /src/mongo/db/commands/user_management_commands.cpp | |
parent | 40b6c60df9c863a1f473287fcc139f71dcd2954a (diff) | |
download | mongo-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.cpp | 94 |
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()) { |