summaryrefslogtreecommitdiff
path: root/src/mongo/db/auth
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/auth
parent40b6c60df9c863a1f473287fcc139f71dcd2954a (diff)
downloadmongo-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/SConscript1
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_s.cpp14
-rw-r--r--src/mongo/db/auth/user.cpp72
-rw-r--r--src/mongo/db/auth/user.h57
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;