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/auth | |
parent | 40b6c60df9c863a1f473287fcc139f71dcd2954a (diff) | |
download | mongo-13d81879027e51742205433d4b3573a0c9dbeaec.tar.gz |
SERVER-60425: Cache users during exact-match usersInfo commands
Diffstat (limited to 'src/mongo/db/auth')
-rw-r--r-- | src/mongo/db/auth/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_s.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/auth/user.cpp | 72 | ||||
-rw-r--r-- | src/mongo/db/auth/user.h | 57 |
4 files changed, 137 insertions, 7 deletions
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript index c99651c652e..9af94b20d27 100644 --- a/src/mongo/db/auth/SConscript +++ b/src/mongo/db/auth/SConscript @@ -98,6 +98,7 @@ env.Library( ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/crypto/sha_block_${MONGO_CRYPTO}', + 'auth', 'authentication_restriction', 'authprivilege', ], diff --git a/src/mongo/db/auth/authz_manager_external_state_s.cpp b/src/mongo/db/auth/authz_manager_external_state_s.cpp index 1b2c0b7331c..47cf83499bc 100644 --- a/src/mongo/db/auth/authz_manager_external_state_s.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_s.cpp @@ -132,13 +132,13 @@ Status AuthzManagerExternalStateMongos::getUserDescription(OperationContext* opC BSONObj* result) { const UserName& userName = user.name; if (!user.roles) { - BSONObj usersInfoCmd = - BSON("usersInfo" << BSON_ARRAY(BSON(AuthorizationManager::USER_NAME_FIELD_NAME - << userName.getUser() - << AuthorizationManager::USER_DB_FIELD_NAME - << userName.getDB())) - << "showPrivileges" << true << "showCredentials" << true - << "showAuthenticationRestrictions" << true); + BSONObj usersInfoCmd = BSON( + "usersInfo" << BSON_ARRAY(BSON(AuthorizationManager::USER_NAME_FIELD_NAME + << userName.getUser() + << AuthorizationManager::USER_DB_FIELD_NAME + << userName.getDB())) + << "showPrivileges" << true << "showCredentials" << true + << "showAuthenticationRestrictions" << true << "showCustomData" << false); BSONObjBuilder builder; const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementReadCommand( opCtx, "admin", usersInfoCmd, &builder); diff --git a/src/mongo/db/auth/user.cpp b/src/mongo/db/auth/user.cpp index ff967a9f8a0..6b6cf35d259 100644 --- a/src/mongo/db/auth/user.cpp +++ b/src/mongo/db/auth/user.cpp @@ -45,6 +45,19 @@ namespace mongo { namespace { +// Field names used when serializing User objects to BSON for usersInfo. +constexpr auto kIdFieldName = "_id"_sd; +constexpr auto kUserIdFieldName = "userId"_sd; +constexpr auto kUserFieldName = "user"_sd; +constexpr auto kDbFieldName = "db"_sd; +constexpr auto kMechanismsFieldName = "mechanisms"_sd; +constexpr auto kCredentialsFieldName = "credentials"_sd; +constexpr auto kRolesFieldName = "roles"_sd; +constexpr auto kInheritedRolesFieldName = "inheritedRoles"_sd; +constexpr auto kInheritedPrivilegesFieldName = "inheritedPrivileges"_sd; +constexpr auto kInheritedAuthenticationRestrictionsFieldName = + "inheritedAuthenticationRestrictions"_sd; +constexpr auto kAuthenticationRestrictionsFieldName = "authenticationRestrictions"_sd; SHA256Block computeDigest(const UserName& name) { auto fn = name.getDisplayName(); @@ -181,4 +194,63 @@ Status User::validateRestrictions(OperationContext* opCtx) const { return Status::OK(); } +void User::reportForUsersInfo(BSONObjBuilder* builder, + bool showCredentials, + bool showPrivileges, + bool showAuthenticationRestrictions) const { + builder->append(kIdFieldName, _name.getUnambiguousName()); + UUID::fromCDR(ConstDataRange(_id)).appendToBuilder(builder, kUserIdFieldName); + builder->append(kUserFieldName, _name.getUser()); + builder->append(kDbFieldName, _name.getDB()); + + BSONArrayBuilder mechanismNamesBuilder(builder->subarrayStart(kMechanismsFieldName)); + for (const StringData& mechanism : _credentials.toMechanismsVector()) { + mechanismNamesBuilder.append(mechanism); + } + mechanismNamesBuilder.doneFast(); + + BSONArrayBuilder rolesBuilder(builder->subarrayStart(kRolesFieldName)); + for (const auto& role : _roles) { + role.serializeToBSON(&rolesBuilder); + } + rolesBuilder.doneFast(); + + if (showCredentials) { + BSONObjBuilder credentialsBuilder(builder->subobjStart(kCredentialsFieldName)); + _credentials.toBSON(&credentialsBuilder); + credentialsBuilder.doneFast(); + } + + if (showPrivileges || showAuthenticationRestrictions) { + BSONArrayBuilder inheritedRolesBuilder(builder->subarrayStart(kInheritedRolesFieldName)); + for (const auto& indirectRole : _indirectRoles) { + indirectRole.serializeToBSON(&inheritedRolesBuilder); + } + inheritedRolesBuilder.doneFast(); + + BSONArrayBuilder privsBuilder(builder->subarrayStart(kInheritedPrivilegesFieldName)); + for (const auto& resourceToPrivilege : _privileges) { + privsBuilder.append(resourceToPrivilege.second.toBSON()); + } + privsBuilder.doneFast(); + + BSONArray indirectRestrictionsArr = _indirectRestrictions.toBSON(); + builder->append(kInheritedAuthenticationRestrictionsFieldName, indirectRestrictionsArr); + } + + if (showAuthenticationRestrictions) { + // The user document parser expects an array of documents, where each document represents + // a restriction. Since _restrictions is of type RestrictionDocuments, its serialization + // logic supports multiple arrays of documents rather than just one. Therefore, we only + // should append the first array here. + BSONArray authenticationRestrictionsArr = _restrictions.toBSON(); + if (authenticationRestrictionsArr.nFields() == 0) { + builder->append(kAuthenticationRestrictionsFieldName, BSONArray()); + } else { + builder->append(kAuthenticationRestrictionsFieldName, + BSONArray(authenticationRestrictionsArr.begin()->Obj())); + } + } +} + } // namespace mongo diff --git a/src/mongo/db/auth/user.h b/src/mongo/db/auth/user.h index 4a6b204ca76..4a1045ad4d7 100644 --- a/src/mongo/db/auth/user.h +++ b/src/mongo/db/auth/user.h @@ -66,6 +66,13 @@ class User { public: using UserId = std::vector<std::uint8_t>; + constexpr static auto kSHA1FieldName = "SCRAM-SHA-1"_sd; + constexpr static auto kSHA256FieldName = "SCRAM-SHA-256"_sd; + constexpr static auto kExternalFieldName = "external"_sd; + constexpr static auto kIterationCountFieldName = "iterationCount"_sd; + constexpr static auto kSaltFieldName = "salt"_sd; + constexpr static auto kServerKeyFieldName = "serverKey"_sd; + constexpr static auto kStoredKeyFieldName = "storedKey"_sd; template <typename HashBlock> struct SCRAMCredentials { @@ -89,6 +96,13 @@ public: bool empty() const { return !iterationCount && salt.empty() && serverKey.empty() && storedKey.empty(); } + + void toBSON(BSONObjBuilder* builder) const { + builder->append(kIterationCountFieldName, iterationCount); + builder->append(kSaltFieldName, salt); + builder->append(kStoredKeyFieldName, storedKey); + builder->append(kServerKeyFieldName, serverKey); + } }; struct CredentialData { @@ -106,6 +120,40 @@ public: template <typename HashBlock> const SCRAMCredentials<HashBlock>& scram() const; + + void toBSON(BSONObjBuilder* builder) const { + if (scram_sha1.isValid()) { + BSONObjBuilder sha1ObjBuilder(builder->subobjStart(kSHA1FieldName)); + scram_sha1.toBSON(&sha1ObjBuilder); + sha1ObjBuilder.doneFast(); + } + if (scram_sha256.isValid()) { + BSONObjBuilder sha256ObjBuilder(builder->subobjStart(kSHA256FieldName)); + scram_sha256.toBSON(&sha256ObjBuilder); + sha256ObjBuilder.doneFast(); + } + if (isExternal) { + builder->append(kExternalFieldName, true); + } + } + + std::vector<StringData> toMechanismsVector() const { + std::vector<StringData> mechanismsVec; + if (scram_sha1.isValid()) { + mechanismsVec.push_back(kSHA1FieldName); + } + if (scram_sha256.isValid()) { + mechanismsVec.push_back(kSHA256FieldName); + } + if (isExternal) { + mechanismsVec.push_back(kExternalFieldName); + } + + // Valid CredentialData objects must have at least one mechanism. + invariant(mechanismsVec.size() > 0); + + return mechanismsVec; + } }; using ResourcePrivilegeMap = stdx::unordered_map<ResourcePattern, Privilege>; @@ -245,6 +293,15 @@ public: */ Status validateRestrictions(OperationContext* opCtx) const; + /** + * Generates a BSON representation of the User object with all the information needed for + * usersInfo. + */ + void reportForUsersInfo(BSONObjBuilder* builder, + bool showCredentials, + bool showPrivileges, + bool showAuthenticationRestrictions) const; + private: // Unique ID (often UUID) for this user. May be empty for legacy users. UserId _id; |