/** * Copyright (C) 2012 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "mongo/db/auth/privilege_document_parser.h" #include #include "mongo/base/init.h" #include "mongo/base/status.h" #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/auth/user.h" #include "mongo/db/jsobj.h" #include "mongo/util/mongoutils/str.h" namespace mongo { namespace { const std::string ADMIN_DBNAME = "admin"; const std::string LOCAL_DBNAME = "local"; const std::string ROLES_FIELD_NAME = "roles"; const std::string OTHER_DB_ROLES_FIELD_NAME = "otherDBRoles"; const std::string READONLY_FIELD_NAME = "readOnly"; const std::string SYSTEM_ROLE_READ = "read"; const std::string SYSTEM_ROLE_READ_WRITE = "readWrite"; const std::string SYSTEM_ROLE_USER_ADMIN = "userAdmin"; const std::string SYSTEM_ROLE_DB_ADMIN = "dbAdmin"; const std::string SYSTEM_ROLE_CLUSTER_ADMIN = "clusterAdmin"; const std::string SYSTEM_ROLE_READ_ANY_DB = "readAnyDatabase"; const std::string SYSTEM_ROLE_READ_WRITE_ANY_DB = "readWriteAnyDatabase"; const std::string SYSTEM_ROLE_USER_ADMIN_ANY_DB = "userAdminAnyDatabase"; const std::string SYSTEM_ROLE_DB_ADMIN_ANY_DB = "dbAdminAnyDatabase"; // System roles for backwards compatibility with 2.2 and prior const std::string SYSTEM_ROLE_V0_READ = "oldRead"; const std::string SYSTEM_ROLE_V0_READ_WRITE= "oldReadWrite"; const std::string SYSTEM_ROLE_V0_ADMIN_READ = "oldAdminRead"; const std::string SYSTEM_ROLE_V0_ADMIN_READ_WRITE= "oldAdminReadWrite"; // ActionSets for the various system roles. These ActionSets contain all the actions that // a user of each system role is granted. ActionSet readRoleActions; ActionSet readWriteRoleActions; ActionSet userAdminRoleActions; ActionSet dbAdminRoleActions; ActionSet clusterAdminRoleActions; // Can only be performed by internal connections. Nothing ever explicitly grants these actions, // but they're included when calling addAllActions on an ActionSet, which is how internal // connections are granted their privileges. ActionSet internalActions; // Old-style user roles ActionSet compatibilityReadOnlyActions; ActionSet compatibilityReadWriteActions; ActionSet compatibilityReadOnlyAdminActions; ActionSet compatibilityReadWriteAdminActions; } // namespace // This sets up the system role ActionSets. This is what determines what actions each role // is authorized to perform MONGO_INITIALIZER(AuthorizationSystemRoles)(InitializerContext* context) { // Read role readRoleActions.addAction(ActionType::cloneCollectionLocalSource); readRoleActions.addAction(ActionType::collStats); readRoleActions.addAction(ActionType::dbHash); readRoleActions.addAction(ActionType::dbStats); readRoleActions.addAction(ActionType::find); readRoleActions.addAction(ActionType::indexRead); readRoleActions.addAction(ActionType::killCursors); // Read-write role readWriteRoleActions.addAllActionsFromSet(readRoleActions); readWriteRoleActions.addAction(ActionType::cloneCollectionTarget); readWriteRoleActions.addAction(ActionType::convertToCapped); readWriteRoleActions.addAction(ActionType::createCollection); // db admin gets this also readWriteRoleActions.addAction(ActionType::dropCollection); readWriteRoleActions.addAction(ActionType::dropIndexes); readWriteRoleActions.addAction(ActionType::emptycapped); readWriteRoleActions.addAction(ActionType::ensureIndex); readWriteRoleActions.addAction(ActionType::insert); readWriteRoleActions.addAction(ActionType::remove); readWriteRoleActions.addAction(ActionType::renameCollectionSameDB); // db admin gets this also readWriteRoleActions.addAction(ActionType::update); // User admin role userAdminRoleActions.addAction(ActionType::userAdmin); // DB admin role dbAdminRoleActions.addAction(ActionType::clean); dbAdminRoleActions.addAction(ActionType::cloneCollectionLocalSource); dbAdminRoleActions.addAction(ActionType::collMod); dbAdminRoleActions.addAction(ActionType::collStats); dbAdminRoleActions.addAction(ActionType::compact); dbAdminRoleActions.addAction(ActionType::convertToCapped); dbAdminRoleActions.addAction(ActionType::createCollection); // read_write gets this also dbAdminRoleActions.addAction(ActionType::dbStats); dbAdminRoleActions.addAction(ActionType::dropCollection); dbAdminRoleActions.addAction(ActionType::dropIndexes); dbAdminRoleActions.addAction(ActionType::ensureIndex); dbAdminRoleActions.addAction(ActionType::indexRead); dbAdminRoleActions.addAction(ActionType::indexStats); dbAdminRoleActions.addAction(ActionType::profileEnable); dbAdminRoleActions.addAction(ActionType::profileRead); dbAdminRoleActions.addAction(ActionType::reIndex); dbAdminRoleActions.addAction(ActionType::renameCollectionSameDB); // read_write gets this also dbAdminRoleActions.addAction(ActionType::storageDetails); dbAdminRoleActions.addAction(ActionType::validate); // We separate clusterAdmin read-only and read-write actions for backwards // compatibility with old-style read-only admin users. This separation is not exposed to // the user, and could go away once we stop supporting old-style privilege documents. ActionSet clusterAdminRoleReadActions; ActionSet clusterAdminRoleWriteActions; // Cluster admin role clusterAdminRoleReadActions.addAction(ActionType::connPoolStats); clusterAdminRoleReadActions.addAction(ActionType::connPoolSync); clusterAdminRoleReadActions.addAction(ActionType::getCmdLineOpts); clusterAdminRoleReadActions.addAction(ActionType::getLog); clusterAdminRoleReadActions.addAction(ActionType::getParameter); clusterAdminRoleReadActions.addAction(ActionType::getShardMap); clusterAdminRoleReadActions.addAction(ActionType::getShardVersion); clusterAdminRoleReadActions.addAction(ActionType::hostInfo); clusterAdminRoleReadActions.addAction(ActionType::listDatabases); clusterAdminRoleReadActions.addAction(ActionType::listShards); clusterAdminRoleReadActions.addAction(ActionType::logRotate); clusterAdminRoleReadActions.addAction(ActionType::netstat); clusterAdminRoleReadActions.addAction(ActionType::replSetFreeze); clusterAdminRoleReadActions.addAction(ActionType::replSetGetStatus); clusterAdminRoleReadActions.addAction(ActionType::replSetMaintenance); clusterAdminRoleReadActions.addAction(ActionType::replSetStepDown); clusterAdminRoleReadActions.addAction(ActionType::replSetSyncFrom); clusterAdminRoleReadActions.addAction(ActionType::setParameter); clusterAdminRoleReadActions.addAction(ActionType::setShardVersion); // TODO: should this be internal? clusterAdminRoleReadActions.addAction(ActionType::serverStatus); clusterAdminRoleReadActions.addAction(ActionType::splitVector); // Shutdown is in read actions b/c that's how it was in 2.2 clusterAdminRoleReadActions.addAction(ActionType::shutdown); clusterAdminRoleReadActions.addAction(ActionType::top); clusterAdminRoleReadActions.addAction(ActionType::touch); clusterAdminRoleReadActions.addAction(ActionType::unlock); clusterAdminRoleReadActions.addAction(ActionType::unsetSharding); clusterAdminRoleReadActions.addAction(ActionType::writeBacksQueued); clusterAdminRoleWriteActions.addAction(ActionType::addShard); clusterAdminRoleWriteActions.addAction(ActionType::cleanupOrphaned); clusterAdminRoleWriteActions.addAction(ActionType::closeAllDatabases); clusterAdminRoleWriteActions.addAction(ActionType::cpuProfiler); clusterAdminRoleWriteActions.addAction(ActionType::cursorInfo); clusterAdminRoleWriteActions.addAction(ActionType::diagLogging); clusterAdminRoleWriteActions.addAction(ActionType::dropDatabase); // TODO: Should there be a CREATE_DATABASE also? clusterAdminRoleWriteActions.addAction(ActionType::enableSharding); clusterAdminRoleWriteActions.addAction(ActionType::flushRouterConfig); clusterAdminRoleWriteActions.addAction(ActionType::fsync); clusterAdminRoleWriteActions.addAction(ActionType::inprog); clusterAdminRoleWriteActions.addAction(ActionType::killop); clusterAdminRoleWriteActions.addAction(ActionType::mergeChunks); clusterAdminRoleWriteActions.addAction(ActionType::moveChunk); clusterAdminRoleWriteActions.addAction(ActionType::movePrimary); clusterAdminRoleWriteActions.addAction(ActionType::removeShard); clusterAdminRoleWriteActions.addAction(ActionType::repairDatabase); clusterAdminRoleWriteActions.addAction(ActionType::replSetInitiate); clusterAdminRoleWriteActions.addAction(ActionType::replSetReconfig); clusterAdminRoleWriteActions.addAction(ActionType::resync); clusterAdminRoleWriteActions.addAction(ActionType::shardCollection); clusterAdminRoleWriteActions.addAction(ActionType::shardingState); clusterAdminRoleWriteActions.addAction(ActionType::split); clusterAdminRoleWriteActions.addAction(ActionType::splitChunk); clusterAdminRoleActions.addAllActionsFromSet(clusterAdminRoleReadActions); clusterAdminRoleActions.addAllActionsFromSet(clusterAdminRoleWriteActions); clusterAdminRoleActions.addAction(ActionType::killCursors); // Old-style user actions, for backwards compatibility compatibilityReadOnlyActions.addAllActionsFromSet(readRoleActions); compatibilityReadWriteActions.addAllActionsFromSet(readWriteRoleActions); compatibilityReadWriteActions.addAllActionsFromSet(dbAdminRoleActions); compatibilityReadWriteActions.addAllActionsFromSet(userAdminRoleActions); compatibilityReadWriteActions.addAction(ActionType::clone); compatibilityReadWriteActions.addAction(ActionType::copyDBTarget); compatibilityReadWriteActions.addAction(ActionType::dropDatabase); compatibilityReadWriteActions.addAction(ActionType::repairDatabase); compatibilityReadOnlyAdminActions.addAllActionsFromSet(compatibilityReadOnlyActions); compatibilityReadOnlyAdminActions.addAllActionsFromSet(clusterAdminRoleReadActions); compatibilityReadWriteAdminActions.addAllActionsFromSet(compatibilityReadWriteActions); compatibilityReadWriteAdminActions.addAllActionsFromSet(compatibilityReadOnlyAdminActions); compatibilityReadWriteAdminActions.addAllActionsFromSet(clusterAdminRoleWriteActions); // Internal commands internalActions.addAction(ActionType::clone); internalActions.addAction(ActionType::handshake); internalActions.addAction(ActionType::mapReduceShardedFinish); internalActions.addAction(ActionType::replSetElect); internalActions.addAction(ActionType::replSetFresh); internalActions.addAction(ActionType::replSetGetRBID); internalActions.addAction(ActionType::replSetHeartbeat); internalActions.addAction(ActionType::writebacklisten); internalActions.addAction(ActionType::userAdminV1); internalActions.addAction(ActionType::_migrateClone); internalActions.addAction(ActionType::_recvChunkAbort); internalActions.addAction(ActionType::_recvChunkCommit); internalActions.addAction(ActionType::_recvChunkStart); internalActions.addAction(ActionType::_recvChunkStatus); internalActions.addAction(ActionType::_transferMods); return Status::OK(); } static inline Status _oldPrivilegeFormatNotSupported() { return Status(ErrorCodes::UnsupportedFormat, "Support for compatibility-form privilege documents disabled; " "All system.users entries must contain a 'roles' field"); } static inline Status _badValue(const char* reason, int location) { return Status(ErrorCodes::BadValue, reason, location); } static inline Status _badValue(const std::string& reason, int location) { return Status(ErrorCodes::BadValue, reason, location); } static inline StringData makeStringDataFromBSONElement(const BSONElement& element) { return StringData(element.valuestr(), element.valuestrsize() - 1); } ActionSet PrivilegeDocumentParser::getAllUserActions() const { ActionSet allActions; allActions.addAllActionsFromSet(readRoleActions); allActions.addAllActionsFromSet(readWriteRoleActions); allActions.addAllActionsFromSet(userAdminRoleActions); allActions.addAllActionsFromSet(dbAdminRoleActions); allActions.addAllActionsFromSet(clusterAdminRoleActions); return allActions; } Status _checkRolesArray(const BSONElement& rolesElement) { if (rolesElement.type() != Array) { return _badValue("Role fields must be an array when present in system.users entries", 0); } for (BSONObjIterator iter(rolesElement.embeddedObject()); iter.more(); iter.next()) { BSONElement element = *iter; if (element.type() != String || makeStringDataFromBSONElement(element).empty()) { return _badValue("Roles must be non-empty strings.", 0); } } return Status::OK(); } Status V1PrivilegeDocumentParser::checkValidPrivilegeDocument(const StringData& dbname, const BSONObj& doc) const { BSONElement userElement = doc[AuthorizationManager::USER_NAME_FIELD_NAME]; BSONElement userSourceElement = doc[AuthorizationManager::USER_SOURCE_FIELD_NAME]; BSONElement passwordElement = doc[AuthorizationManager::PASSWORD_FIELD_NAME]; BSONElement rolesElement = doc[ROLES_FIELD_NAME]; BSONElement otherDBRolesElement = doc[OTHER_DB_ROLES_FIELD_NAME]; BSONElement readOnlyElement = doc[READONLY_FIELD_NAME]; // Validate the "user" element. if (userElement.type() != String) return _badValue("system.users entry needs 'user' field to be a string", 14051); if (makeStringDataFromBSONElement(userElement).empty()) return _badValue("system.users entry needs 'user' field to be non-empty", 14053); // Must set exactly one of "userSource" and "pwd" fields. if (userSourceElement.eoo() == passwordElement.eoo()) { return _badValue("system.users entry must have either a 'pwd' field or a 'userSource' " "field, but not both", 0); } if (!AuthorizationManager::getSupportOldStylePrivilegeDocuments() && rolesElement.eoo()) { return _oldPrivilegeFormatNotSupported(); } // Cannot have both "roles" and "readOnly" elements. if (!rolesElement.eoo() && !readOnlyElement.eoo()) { return _badValue("system.users entry must not have both 'roles' and 'readOnly' fields", 0); } // Validate the "pwd" element, if present. if (!passwordElement.eoo()) { if (passwordElement.type() != String) return _badValue("system.users entry needs 'pwd' field to be a string", 14052); if (makeStringDataFromBSONElement(passwordElement).empty()) return _badValue("system.users entry needs 'pwd' field to be non-empty", 14054); } // Validate the "userSource" element, if present. if (!userSourceElement.eoo()) { if (userSourceElement.type() != String || makeStringDataFromBSONElement(userSourceElement).empty()) { return _badValue("system.users entry needs 'userSource' field to be a non-empty " "string, if present", 0); } if (userSourceElement.str() == dbname) { return _badValue(mongoutils::str::stream() << "'" << dbname << "' is not a valid value for the userSource field in " << dbname << ".system.users entries", 0); } if (rolesElement.eoo()) { return _badValue("system.users entry needs 'roles' field if 'userSource' field " "is present.", 0); } } // Validate the "roles" element. if (!rolesElement.eoo()) { Status status = _checkRolesArray(rolesElement); if (!status.isOK()) return status; } if (!otherDBRolesElement.eoo()) { if (dbname != ADMIN_DBNAME) { return _badValue("Only admin.system.users entries may contain 'otherDBRoles' " "fields", 0); } if (rolesElement.eoo()) { return _badValue("system.users entries with 'otherDBRoles' fields must contain " "'roles' fields", 0); } if (otherDBRolesElement.type() != Object) { return _badValue("'otherDBRoles' field must be an object when present in " "system.users entries", 0); } for (BSONObjIterator iter(otherDBRolesElement.embeddedObject()); iter.more(); iter.next()) { Status status = _checkRolesArray(*iter); if (!status.isOK()) return status; } } return Status::OK(); } Status V1PrivilegeDocumentParser::initializeUserCredentialsFromPrivilegeDocument( User* user, const BSONObj& privDoc) const { User::CredentialData credentials; if (privDoc.hasField(AuthorizationManager::PASSWORD_FIELD_NAME)) { credentials.password = privDoc[AuthorizationManager::PASSWORD_FIELD_NAME].String(); credentials.isExternal = false; } else if (privDoc.hasField(AuthorizationManager::USER_SOURCE_FIELD_NAME)) { std::string userSource = privDoc[AuthorizationManager::USER_SOURCE_FIELD_NAME].String(); if (userSource != "$external") { return Status(ErrorCodes::UnsupportedFormat, "Cannot extract credentials from user documents without a password " "and with userSource != \"$external\""); } else { credentials.isExternal = true; } } else { return Status(ErrorCodes::UnsupportedFormat, "Invalid user document: must have one of \"pwd\" and \"userSource\""); } user->setCredentials(credentials); return Status::OK(); } void _initializeUserRolesFromV0PrivilegeDocument( User* user, const BSONObj& privDoc, const StringData& dbname) { bool readOnly = privDoc["readOnly"].trueValue(); if (dbname == "admin") { if (readOnly) { user->addRole(RoleName(SYSTEM_ROLE_V0_ADMIN_READ, "admin")); } else { user->addRole(RoleName(SYSTEM_ROLE_V0_ADMIN_READ_WRITE, "admin")); } } else { if (readOnly) { user->addRole(RoleName(SYSTEM_ROLE_V0_READ, dbname)); } else { user->addRole(RoleName(SYSTEM_ROLE_V0_READ_WRITE, dbname)); } } } Status _initializeUserRolesFromV1RolesArray(User* user, const BSONElement& rolesElement, const StringData& dbname) { static const char privilegesTypeMismatchMessage[] = "Roles in V1 user documents must be enumerated in an array of strings."; if (dbname == AuthorizationManager::WILDCARD_RESOURCE_NAME) { return Status(ErrorCodes::BadValue, AuthorizationManager::WILDCARD_RESOURCE_NAME + " is an invalid database name."); } if (rolesElement.type() != Array) return Status(ErrorCodes::TypeMismatch, privilegesTypeMismatchMessage); for (BSONObjIterator iter(rolesElement.embeddedObject()); iter.more(); iter.next()) { BSONElement roleElement = *iter; if (roleElement.type() != String) return Status(ErrorCodes::TypeMismatch, privilegesTypeMismatchMessage); user->addRole(RoleName(roleElement.String(), dbname)); } return Status::OK(); } Status _initializeUserRolesFromV1PrivilegeDocument( User* user, const BSONObj& privDoc, const StringData& dbname) { if (!privDoc[READONLY_FIELD_NAME].eoo()) { return Status(ErrorCodes::UnsupportedFormat, "Privilege documents may not contain both \"readonly\" and " "\"roles\" fields"); } Status status = _initializeUserRolesFromV1RolesArray(user, privDoc[ROLES_FIELD_NAME], dbname); if (!status.isOK()) { return status; } // If "dbname" is the admin database, handle the otherDBPrivileges field, which // grants privileges on databases other than "dbname". BSONElement otherDbPrivileges = privDoc[OTHER_DB_ROLES_FIELD_NAME]; if (dbname == ADMIN_DBNAME) { switch (otherDbPrivileges.type()) { case EOO: break; case Object: { for (BSONObjIterator iter(otherDbPrivileges.embeddedObject()); iter.more(); iter.next()) { BSONElement rolesElement = *iter; status = _initializeUserRolesFromV1RolesArray(user, rolesElement, rolesElement.fieldName()); if (!status.isOK()) return status; } break; } default: return Status(ErrorCodes::TypeMismatch, "Field \"otherDBRoles\" must be an object, if present."); } } else if (!otherDbPrivileges.eoo()) { return Status(ErrorCodes::UnsupportedFormat, "Only the admin database may contain a field called \"otherDBRoles\""); } return Status::OK(); } Status V1PrivilegeDocumentParser::initializeUserRolesFromPrivilegeDocument( User* user, const BSONObj& privDoc, const StringData& dbname) const { if (!privDoc.hasField("roles")) { _initializeUserRolesFromV0PrivilegeDocument(user, privDoc, dbname); } else { return _initializeUserRolesFromV1PrivilegeDocument(user, privDoc, dbname); } // TODO(spencer): dassert that if you have a V0 or V1 privilege document that the _version // of the system is 1. return Status::OK(); } /** * Adds to "outPrivileges" the privileges associated with having the named "role" on "dbname". * * Returns non-OK status if "role" is not a defined role in "dbname". */ void _addPrivilegesForSystemRole(const std::string& dbname, const std::string& role, std::vector* outPrivileges) { const bool isAdminDB = (dbname == ADMIN_DBNAME); if (role == SYSTEM_ROLE_READ) { outPrivileges->push_back(Privilege(dbname, readRoleActions)); } else if (role == SYSTEM_ROLE_READ_WRITE) { outPrivileges->push_back(Privilege(dbname, readWriteRoleActions)); } else if (role == SYSTEM_ROLE_USER_ADMIN) { outPrivileges->push_back(Privilege(dbname, userAdminRoleActions)); } else if (role == SYSTEM_ROLE_DB_ADMIN) { outPrivileges->push_back(Privilege(dbname, dbAdminRoleActions)); } else if (role == SYSTEM_ROLE_V0_READ) { outPrivileges->push_back(Privilege(dbname, compatibilityReadOnlyActions)); } else if (role == SYSTEM_ROLE_V0_READ_WRITE) { outPrivileges->push_back(Privilege(dbname, compatibilityReadWriteActions)); } else if (isAdminDB && role == SYSTEM_ROLE_READ_ANY_DB) { outPrivileges->push_back(Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, readRoleActions)); } else if (isAdminDB && role == SYSTEM_ROLE_READ_WRITE_ANY_DB) { outPrivileges->push_back( Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, readWriteRoleActions)); } else if (isAdminDB && role == SYSTEM_ROLE_USER_ADMIN_ANY_DB) { outPrivileges->push_back( Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, userAdminRoleActions)); } else if (isAdminDB && role == SYSTEM_ROLE_DB_ADMIN_ANY_DB) { outPrivileges->push_back( Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, dbAdminRoleActions)); } else if (isAdminDB && role == SYSTEM_ROLE_CLUSTER_ADMIN) { outPrivileges->push_back( Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, clusterAdminRoleActions)); } else if (isAdminDB && role == SYSTEM_ROLE_V0_ADMIN_READ) { outPrivileges->push_back( Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, compatibilityReadOnlyAdminActions)); } else if (isAdminDB && role == SYSTEM_ROLE_V0_ADMIN_READ_WRITE) { outPrivileges->push_back( Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, compatibilityReadWriteAdminActions)); } else { warning() << "No such role, \"" << role << "\", in database " << dbname << ". No privileges will be acquired from this role" << endl; } } /** * Modifies the given User object by inspecting its roles and giving it the relevant * privileges from those roles. */ void V1PrivilegeDocumentParser::initializeUserPrivilegesFromRoles(User* user) const { std::vector privileges; RoleNameIterator it = user->getRoles(); while (it.more()) { const RoleName& roleName = it.next(); _addPrivilegesForSystemRole(roleName.getDB().toString(), roleName.getRole().toString(), &privileges); } user->addPrivileges(privileges); } Status V1PrivilegeDocumentParser::initializeUserFromPrivilegeDocument( User* user, const BSONObj& privDoc) const { std::string userName = privDoc[AuthorizationManager::USER_NAME_FIELD_NAME].str(); if (userName != user->getName().getUser()) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "User name from privilege document \"" << userName << "\" doesn't match name of provided User \"" << user->getName().getUser() << "\"", 0); } Status status = initializeUserCredentialsFromPrivilegeDocument(user, privDoc); if (!status.isOK()) { return status; } status = initializeUserRolesFromPrivilegeDocument(user, privDoc, user->getName().getDB()); if (!status.isOK()) { return status; } initializeUserPrivilegesFromRoles(user); return Status::OK(); } } // namespace mongo