diff options
Diffstat (limited to 'src/mongo/db/auth/user_document_parser.cpp')
-rw-r--r-- | src/mongo/db/auth/user_document_parser.cpp | 787 |
1 files changed, 379 insertions, 408 deletions
diff --git a/src/mongo/db/auth/user_document_parser.cpp b/src/mongo/db/auth/user_document_parser.cpp index d4a095c661d..058829622f5 100644 --- a/src/mongo/db/auth/user_document_parser.cpp +++ b/src/mongo/db/auth/user_document_parser.cpp @@ -44,142 +44,135 @@ namespace mongo { namespace { - const std::string ADMIN_DBNAME = "admin"; - - const std::string ROLES_FIELD_NAME = "roles"; - const std::string PRIVILEGES_FIELD_NAME = "inheritedPrivileges"; - const std::string INHERITED_ROLES_FIELD_NAME = "inheritedRoles"; - const std::string OTHER_DB_ROLES_FIELD_NAME = "otherDBRoles"; - const std::string READONLY_FIELD_NAME = "readOnly"; - const std::string CREDENTIALS_FIELD_NAME = "credentials"; - const std::string ROLE_NAME_FIELD_NAME = "role"; - const std::string ROLE_DB_FIELD_NAME = "db"; - const std::string MONGODB_CR_CREDENTIAL_FIELD_NAME = "MONGODB-CR"; - const std::string SCRAM_CREDENTIAL_FIELD_NAME = "SCRAM-SHA-1"; - const std::string MONGODB_EXTERNAL_CREDENTIAL_FIELD_NAME = "external"; - - inline Status _badValue(const char* reason, int location) { - return Status(ErrorCodes::BadValue, reason, location); +const std::string ADMIN_DBNAME = "admin"; + +const std::string ROLES_FIELD_NAME = "roles"; +const std::string PRIVILEGES_FIELD_NAME = "inheritedPrivileges"; +const std::string INHERITED_ROLES_FIELD_NAME = "inheritedRoles"; +const std::string OTHER_DB_ROLES_FIELD_NAME = "otherDBRoles"; +const std::string READONLY_FIELD_NAME = "readOnly"; +const std::string CREDENTIALS_FIELD_NAME = "credentials"; +const std::string ROLE_NAME_FIELD_NAME = "role"; +const std::string ROLE_DB_FIELD_NAME = "db"; +const std::string MONGODB_CR_CREDENTIAL_FIELD_NAME = "MONGODB-CR"; +const std::string SCRAM_CREDENTIAL_FIELD_NAME = "SCRAM-SHA-1"; +const std::string MONGODB_EXTERNAL_CREDENTIAL_FIELD_NAME = "external"; + +inline Status _badValue(const char* reason, int location) { + return Status(ErrorCodes::BadValue, reason, location); +} + +inline Status _badValue(const std::string& reason, int location) { + return Status(ErrorCodes::BadValue, reason, location); +} + +Status _checkV1RolesArray(const BSONElement& rolesElement) { + if (rolesElement.type() != Array) { + return _badValue("Role fields must be an array when present in system.users entries", 0); } - - inline Status _badValue(const std::string& reason, int location) { - return Status(ErrorCodes::BadValue, reason, location); - } - - Status _checkV1RolesArray(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 || element.valueStringData().empty()) { - return _badValue("Roles must be non-empty strings.", 0); - } + for (BSONObjIterator iter(rolesElement.embeddedObject()); iter.more(); iter.next()) { + BSONElement element = *iter; + if (element.type() != String || element.valueStringData().empty()) { + return _badValue("Roles must be non-empty strings.", 0); } - return Status::OK(); } + return Status::OK(); +} } // namespace - std::string V1UserDocumentParser::extractUserNameFromUserDocument( - const BSONObj& doc) const { - return doc[AuthorizationManager::V1_USER_NAME_FIELD_NAME].str(); - } - - Status V1UserDocumentParser::initializeUserCredentialsFromUserDocument( - 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::V1_USER_SOURCE_FIELD_NAME)) { - std::string userSource = privDoc[AuthorizationManager::V1_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 { +std::string V1UserDocumentParser::extractUserNameFromUserDocument(const BSONObj& doc) const { + return doc[AuthorizationManager::V1_USER_NAME_FIELD_NAME].str(); +} + +Status V1UserDocumentParser::initializeUserCredentialsFromUserDocument( + 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::V1_USER_SOURCE_FIELD_NAME)) { + std::string userSource = privDoc[AuthorizationManager::V1_USER_SOURCE_FIELD_NAME].String(); + if (userSource != "$external") { return Status(ErrorCodes::UnsupportedFormat, - "Invalid user document: must have one of \"pwd\" and \"userSource\""); + "Cannot extract credentials from user documents without a password " + "and with userSource != \"$external\""); + } else { + credentials.isExternal = true; } - - user->setCredentials(credentials); - return Status::OK(); + } else { + return Status(ErrorCodes::UnsupportedFormat, + "Invalid user document: must have one of \"pwd\" and \"userSource\""); } - static void _initializeUserRolesFromV0UserDocument( - User* user, const BSONObj& privDoc, StringData dbname) { - bool readOnly = privDoc["readOnly"].trueValue(); - if (dbname == "admin") { - if (readOnly) { - user->addRole(RoleName(RoleGraph::BUILTIN_ROLE_V0_ADMIN_READ, "admin")); - } else { - user->addRole(RoleName(RoleGraph::BUILTIN_ROLE_V0_ADMIN_READ_WRITE, "admin")); - } + user->setCredentials(credentials); + return Status::OK(); +} + +static void _initializeUserRolesFromV0UserDocument(User* user, + const BSONObj& privDoc, + StringData dbname) { + bool readOnly = privDoc["readOnly"].trueValue(); + if (dbname == "admin") { + if (readOnly) { + user->addRole(RoleName(RoleGraph::BUILTIN_ROLE_V0_ADMIN_READ, "admin")); } else { - if (readOnly) { - user->addRole(RoleName(RoleGraph::BUILTIN_ROLE_V0_READ, dbname)); - } else { - user->addRole(RoleName(RoleGraph::BUILTIN_ROLE_V0_READ_WRITE, dbname)); - } + user->addRole(RoleName(RoleGraph::BUILTIN_ROLE_V0_ADMIN_READ_WRITE, "admin")); + } + } else { + if (readOnly) { + user->addRole(RoleName(RoleGraph::BUILTIN_ROLE_V0_READ, dbname)); + } else { + user->addRole(RoleName(RoleGraph::BUILTIN_ROLE_V0_READ_WRITE, dbname)); } } +} - Status _initializeUserRolesFromV1RolesArray(User* user, - const BSONElement& rolesElement, - StringData dbname) { - static const char privilegesTypeMismatchMessage[] = - "Roles in V1 user documents must be enumerated in an array of strings."; +Status _initializeUserRolesFromV1RolesArray(User* user, + const BSONElement& rolesElement, + StringData dbname) { + static const char privilegesTypeMismatchMessage[] = + "Roles in V1 user documents must be enumerated in an array of strings."; - if (rolesElement.type() != Array) - return Status(ErrorCodes::TypeMismatch, privilegesTypeMismatchMessage); + 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); + 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(); + user->addRole(RoleName(roleElement.String(), dbname)); + } + return Status::OK(); +} + +static Status _initializeUserRolesFromV1UserDocument(User* user, + const BSONObj& privDoc, + StringData dbname) { + if (!privDoc[READONLY_FIELD_NAME].eoo()) { + return Status(ErrorCodes::UnsupportedFormat, + "User documents may not contain both \"readonly\" and " + "\"roles\" fields"); } - static Status _initializeUserRolesFromV1UserDocument( - User* user, const BSONObj& privDoc, StringData dbname) { - - if (!privDoc[READONLY_FIELD_NAME].eoo()) { - return Status(ErrorCodes::UnsupportedFormat, - "User documents may not contain both \"readonly\" and " - "\"roles\" fields"); - } - - Status status = _initializeUserRolesFromV1RolesArray(user, - privDoc[ROLES_FIELD_NAME], - dbname); - if (!status.isOK()) { - return status; - } + 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()) { + // 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()) { - + for (BSONObjIterator iter(otherDbPrivileges.embeddedObject()); iter.more(); + iter.next()) { BSONElement rolesElement = *iter; - status = _initializeUserRolesFromV1RolesArray(user, - rolesElement, - rolesElement.fieldName()); + status = _initializeUserRolesFromV1RolesArray( + user, rolesElement, rolesElement.fieldName()); if (!status.isOK()) return status; } @@ -188,359 +181,337 @@ namespace { 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\""); } + } else if (!otherDbPrivileges.eoo()) { + return Status(ErrorCodes::UnsupportedFormat, + "Only the admin database may contain a field called \"otherDBRoles\""); + } - return Status::OK(); + return Status::OK(); +} + +Status V1UserDocumentParser::initializeUserRolesFromUserDocument(User* user, + const BSONObj& privDoc, + StringData dbname) const { + if (!privDoc.hasField("roles")) { + _initializeUserRolesFromV0UserDocument(user, privDoc, dbname); + } else { + return _initializeUserRolesFromV1UserDocument(user, privDoc, dbname); } + return Status::OK(); +} - Status V1UserDocumentParser::initializeUserRolesFromUserDocument( - User* user, const BSONObj& privDoc, StringData dbname) const { - if (!privDoc.hasField("roles")) { - _initializeUserRolesFromV0UserDocument(user, privDoc, dbname); - } else { - return _initializeUserRolesFromV1UserDocument(user, privDoc, dbname); + +Status _checkV2RolesArray(const BSONElement& rolesElement) { + if (rolesElement.eoo()) { + return _badValue("User document needs 'roles' field to be provided", 0); + } + if (rolesElement.type() != Array) { + return _badValue("'roles' field must be an array", 0); + } + for (BSONObjIterator iter(rolesElement.embeddedObject()); iter.more(); iter.next()) { + if ((*iter).type() != Object) { + return _badValue("Elements in 'roles' array must objects", 0); } - return Status::OK(); + Status status = V2UserDocumentParser::checkValidRoleObject((*iter).Obj()); + if (!status.isOK()) + return status; + } + return Status::OK(); +} + +Status V2UserDocumentParser::checkValidUserDocument(const BSONObj& doc) const { + BSONElement userElement = doc[AuthorizationManager::USER_NAME_FIELD_NAME]; + BSONElement userDBElement = doc[AuthorizationManager::USER_DB_FIELD_NAME]; + BSONElement credentialsElement = doc[CREDENTIALS_FIELD_NAME]; + BSONElement rolesElement = doc[ROLES_FIELD_NAME]; + + // Validate the "user" element. + if (userElement.type() != String) + return _badValue("User document needs 'user' field to be a string", 0); + if (userElement.valueStringData().empty()) + return _badValue("User document needs 'user' field to be non-empty", 0); + + // Validate the "db" element + if (userDBElement.type() != String || userDBElement.valueStringData().empty()) { + return _badValue("User document needs 'db' field to be a non-empty string", 0); + } + StringData userDBStr = userDBElement.valueStringData(); + if (!NamespaceString::validDBName(userDBStr) && userDBStr != "$external") { + return _badValue(mongoutils::str::stream() << "'" << userDBStr + << "' is not a valid value for the db field.", + 0); } + // Validate the "credentials" element + if (credentialsElement.eoo()) { + return _badValue("User document needs 'credentials' object", 0); + } + if (credentialsElement.type() != Object) { + return _badValue("User document needs 'credentials' field to be an object", 0); + } - Status _checkV2RolesArray(const BSONElement& rolesElement) { - if (rolesElement.eoo()) { - return _badValue("User document needs 'roles' field to be provided", 0); - } - if (rolesElement.type() != Array) { - return _badValue("'roles' field must be an array", 0); + BSONObj credentialsObj = credentialsElement.Obj(); + if (credentialsObj.isEmpty()) { + return _badValue("User document needs 'credentials' field to be a non-empty object", 0); + } + if (userDBStr == "$external") { + BSONElement externalElement = credentialsObj[MONGODB_EXTERNAL_CREDENTIAL_FIELD_NAME]; + if (externalElement.eoo() || externalElement.type() != Bool || !externalElement.Bool()) { + return _badValue( + "User documents for users defined on '$external' must have " + "'credentials' field set to {external: true}", + 0); } - for (BSONObjIterator iter(rolesElement.embeddedObject()); iter.more(); iter.next()) { - if ((*iter).type() != Object) { - return _badValue("Elements in 'roles' array must objects", 0); + } else { + BSONElement scramElement = credentialsObj[SCRAM_CREDENTIAL_FIELD_NAME]; + BSONElement mongoCRElement = credentialsObj[MONGODB_CR_CREDENTIAL_FIELD_NAME]; + + if (!mongoCRElement.eoo()) { + if (mongoCRElement.type() != String || mongoCRElement.valueStringData().empty()) { + return _badValue( + "MONGODB-CR credential must to be a non-empty string" + ", if present", + 0); + } + } else if (!scramElement.eoo()) { + if (scramElement.type() != Object) { + return _badValue("SCRAM credential must be an object, if present", 0); } - Status status = V2UserDocumentParser::checkValidRoleObject((*iter).Obj()); - if (!status.isOK()) - return status; + } else { + return _badValue( + "User document must provide credentials for all " + "non-external users", + 0); } - return Status::OK(); } - Status V2UserDocumentParser::checkValidUserDocument(const BSONObj& doc) const { - BSONElement userElement = doc[AuthorizationManager::USER_NAME_FIELD_NAME]; - BSONElement userDBElement = doc[AuthorizationManager::USER_DB_FIELD_NAME]; - BSONElement credentialsElement = doc[CREDENTIALS_FIELD_NAME]; - BSONElement rolesElement = doc[ROLES_FIELD_NAME]; - - // Validate the "user" element. - if (userElement.type() != String) - return _badValue("User document needs 'user' field to be a string", 0); - if (userElement.valueStringData().empty()) - return _badValue("User document needs 'user' field to be non-empty", 0); - - // Validate the "db" element - if (userDBElement.type() != String || userDBElement.valueStringData().empty()) { - return _badValue("User document needs 'db' field to be a non-empty string", 0); - } - StringData userDBStr = userDBElement.valueStringData(); - if (!NamespaceString::validDBName(userDBStr) && userDBStr != "$external") { - return _badValue(mongoutils::str::stream() << "'" << userDBStr << - "' is not a valid value for the db field.", - 0); - } + // Validate the "roles" element. + Status status = _checkV2RolesArray(rolesElement); + if (!status.isOK()) + return status; - // Validate the "credentials" element - if (credentialsElement.eoo()) { - return _badValue("User document needs 'credentials' object", - 0); - } - if (credentialsElement.type() != Object) { - return _badValue("User document needs 'credentials' field to be an object", 0); - } + return Status::OK(); +} + +std::string V2UserDocumentParser::extractUserNameFromUserDocument(const BSONObj& doc) const { + return doc[AuthorizationManager::USER_NAME_FIELD_NAME].str(); +} - BSONObj credentialsObj = credentialsElement.Obj(); - if (credentialsObj.isEmpty()) { - return _badValue("User document needs 'credentials' field to be a non-empty object", - 0); +Status V2UserDocumentParser::initializeUserCredentialsFromUserDocument( + User* user, const BSONObj& privDoc) const { + User::CredentialData credentials; + std::string userDB = privDoc[AuthorizationManager::USER_DB_FIELD_NAME].String(); + BSONElement credentialsElement = privDoc[CREDENTIALS_FIELD_NAME]; + if (!credentialsElement.eoo()) { + if (credentialsElement.type() != Object) { + return Status(ErrorCodes::UnsupportedFormat, + "'credentials' field in user documents must be an object"); } - if (userDBStr == "$external") { - BSONElement externalElement = credentialsObj[MONGODB_EXTERNAL_CREDENTIAL_FIELD_NAME]; - if (externalElement.eoo() || externalElement.type() != Bool || - !externalElement.Bool()) { - return _badValue("User documents for users defined on '$external' must have " - "'credentials' field set to {external: true}", 0); - } - } - else { - BSONElement scramElement = credentialsObj[SCRAM_CREDENTIAL_FIELD_NAME]; - BSONElement mongoCRElement = credentialsObj[MONGODB_CR_CREDENTIAL_FIELD_NAME]; - - if (!mongoCRElement.eoo()) { - if (mongoCRElement.type() != String || mongoCRElement.valueStringData().empty()) { - return _badValue("MONGODB-CR credential must to be a non-empty string" - ", if present", 0); - } - } - else if (!scramElement.eoo()) { - if (scramElement.type() != Object) { - return _badValue("SCRAM credential must be an object, if present", 0); + if (userDB == "$external") { + BSONElement externalCredentialElement = + credentialsElement.Obj()[MONGODB_EXTERNAL_CREDENTIAL_FIELD_NAME]; + if (!externalCredentialElement.eoo()) { + if (externalCredentialElement.type() != Bool || !externalCredentialElement.Bool()) { + return Status(ErrorCodes::UnsupportedFormat, + "'external' field in credentials object must be set to true"); + } else { + credentials.isExternal = true; } + } else { + return Status(ErrorCodes::UnsupportedFormat, + "User documents defined on '$external' must provide set " + "credentials to {external:true}"); } - else { - return _badValue("User document must provide credentials for all " - "non-external users", 0); + } else { + BSONElement scramElement = credentialsElement.Obj()[SCRAM_CREDENTIAL_FIELD_NAME]; + BSONElement mongoCRCredentialElement = + credentialsElement.Obj()[MONGODB_CR_CREDENTIAL_FIELD_NAME]; + + if (scramElement.eoo() && mongoCRCredentialElement.eoo()) { + return Status(ErrorCodes::UnsupportedFormat, + "User documents must provide credentials for SCRAM-SHA-1 " + "or MONGODB-CR authentication"); } - } - // Validate the "roles" element. - Status status = _checkV2RolesArray(rolesElement); - if (!status.isOK()) - return status; + if (!scramElement.eoo()) { + // We are asserting rather then returning errors since these + // fields should have been prepopulated by the calling code. + credentials.scram.iterationCount = scramElement.Obj()["iterationCount"].numberInt(); + uassert(17501, + "Invalid or missing SCRAM iteration count", + credentials.scram.iterationCount > 0); - return Status::OK(); - } + credentials.scram.salt = scramElement.Obj()["salt"].str(); + uassert(17502, "Missing SCRAM salt", !credentials.scram.salt.empty()); - std::string V2UserDocumentParser::extractUserNameFromUserDocument( - const BSONObj& doc) const { - return doc[AuthorizationManager::USER_NAME_FIELD_NAME].str(); - } + credentials.scram.serverKey = scramElement["serverKey"].str(); + uassert(17503, "Missing SCRAM serverKey", !credentials.scram.serverKey.empty()); - Status V2UserDocumentParser::initializeUserCredentialsFromUserDocument( - User* user, const BSONObj& privDoc) const { - User::CredentialData credentials; - std::string userDB = privDoc[AuthorizationManager::USER_DB_FIELD_NAME].String(); - BSONElement credentialsElement = privDoc[CREDENTIALS_FIELD_NAME]; - if (!credentialsElement.eoo()) { - if (credentialsElement.type() != Object) { - return Status(ErrorCodes::UnsupportedFormat, - "'credentials' field in user documents must be an object"); + credentials.scram.storedKey = scramElement["storedKey"].str(); + uassert(17504, "Missing SCRAM storedKey", !credentials.scram.storedKey.empty()); } - if (userDB == "$external") { - BSONElement externalCredentialElement = - credentialsElement.Obj()[MONGODB_EXTERNAL_CREDENTIAL_FIELD_NAME]; - if (!externalCredentialElement.eoo()) { - if (externalCredentialElement.type() != Bool || - !externalCredentialElement.Bool()) { - return Status(ErrorCodes::UnsupportedFormat, - "'external' field in credentials object must be set to true"); - } else { - credentials.isExternal = true; - } - } else { - return Status(ErrorCodes::UnsupportedFormat, - "User documents defined on '$external' must provide set " - "credentials to {external:true}"); - } - } else { - - BSONElement scramElement = - credentialsElement.Obj()[SCRAM_CREDENTIAL_FIELD_NAME]; - BSONElement mongoCRCredentialElement = - credentialsElement.Obj()[MONGODB_CR_CREDENTIAL_FIELD_NAME]; - - if (scramElement.eoo() && mongoCRCredentialElement.eoo()) { - return Status(ErrorCodes::UnsupportedFormat, - "User documents must provide credentials for SCRAM-SHA-1 " - "or MONGODB-CR authentication"); - } - if (!scramElement.eoo()) { - // We are asserting rather then returning errors since these - // fields should have been prepopulated by the calling code. - credentials.scram.iterationCount = - scramElement.Obj()["iterationCount"].numberInt(); - uassert(17501, "Invalid or missing SCRAM iteration count", - credentials.scram.iterationCount > 0); - - credentials.scram.salt = - scramElement.Obj()["salt"].str(); - uassert(17502, "Missing SCRAM salt", - !credentials.scram.salt.empty()); - - credentials.scram.serverKey = - scramElement["serverKey"].str(); - uassert(17503, "Missing SCRAM serverKey", - !credentials.scram.serverKey.empty()); - - credentials.scram.storedKey = - scramElement["storedKey"].str(); - uassert(17504, "Missing SCRAM storedKey", - !credentials.scram.storedKey.empty()); - } - - if (!mongoCRCredentialElement.eoo()) { - if (mongoCRCredentialElement.type() != String || - mongoCRCredentialElement.valueStringData().empty()) { + if (!mongoCRCredentialElement.eoo()) { + if (mongoCRCredentialElement.type() != String || + mongoCRCredentialElement.valueStringData().empty()) { + return Status(ErrorCodes::UnsupportedFormat, + "MONGODB-CR credentials must be non-empty strings"); + } else { + credentials.password = mongoCRCredentialElement.String(); + if (credentials.password.empty()) { return Status(ErrorCodes::UnsupportedFormat, - "MONGODB-CR credentials must be non-empty strings"); - } else { - credentials.password = mongoCRCredentialElement.String(); - if (credentials.password.empty()) { - return Status(ErrorCodes::UnsupportedFormat, - "User documents must provide authentication credentials"); - } + "User documents must provide authentication credentials"); } } - credentials.isExternal = false; } - } else { - return Status(ErrorCodes::UnsupportedFormat, - "Cannot extract credentials from user documents without a " - "'credentials' field"); + credentials.isExternal = false; } - - user->setCredentials(credentials); - return Status::OK(); + } else { + return Status(ErrorCodes::UnsupportedFormat, + "Cannot extract credentials from user documents without a " + "'credentials' field"); } - static Status _extractRoleDocumentElements( - const BSONObj& roleObject, - BSONElement* roleNameElement, - BSONElement* roleSourceElement) { + user->setCredentials(credentials); + return Status::OK(); +} - *roleNameElement = roleObject[ROLE_NAME_FIELD_NAME]; - *roleSourceElement = roleObject[ROLE_DB_FIELD_NAME]; - - if (roleNameElement->type() != String || roleNameElement->valueStringData().empty()) { - return Status(ErrorCodes::UnsupportedFormat, - "Role names must be non-empty strings"); - } - if (roleSourceElement->type() != String || roleSourceElement->valueStringData().empty()) { - return Status(ErrorCodes::UnsupportedFormat, "Role db must be non-empty strings"); - } +static Status _extractRoleDocumentElements(const BSONObj& roleObject, + BSONElement* roleNameElement, + BSONElement* roleSourceElement) { + *roleNameElement = roleObject[ROLE_NAME_FIELD_NAME]; + *roleSourceElement = roleObject[ROLE_DB_FIELD_NAME]; - return Status::OK(); + if (roleNameElement->type() != String || roleNameElement->valueStringData().empty()) { + return Status(ErrorCodes::UnsupportedFormat, "Role names must be non-empty strings"); } - - Status V2UserDocumentParser::checkValidRoleObject(const BSONObj& roleObject) { - BSONElement roleNameElement; - BSONElement roleSourceElement; - return _extractRoleDocumentElements( - roleObject, - &roleNameElement, - &roleSourceElement); + if (roleSourceElement->type() != String || roleSourceElement->valueStringData().empty()) { + return Status(ErrorCodes::UnsupportedFormat, "Role db must be non-empty strings"); } - Status V2UserDocumentParser::parseRoleName(const BSONObj& roleObject, RoleName* result) { - BSONElement roleNameElement; - BSONElement roleSourceElement; - Status status = _extractRoleDocumentElements( - roleObject, - &roleNameElement, - &roleSourceElement); - if (!status.isOK()) - return status; - *result = RoleName(roleNameElement.str(), roleSourceElement.str()); - return status; - } + return Status::OK(); +} - Status V2UserDocumentParser::parseRoleVector(const BSONArray& rolesArray, - std::vector<RoleName>* result) { - std::vector<RoleName> roles; - for (BSONObjIterator it(rolesArray); it.more(); it.next()) { - if ((*it).type() != Object) { - return Status(ErrorCodes::TypeMismatch, "Roles must be objects."); - } - RoleName role; - Status status = parseRoleName((*it).Obj(), &role); - if (!status.isOK()) - return status; - roles.push_back(role); +Status V2UserDocumentParser::checkValidRoleObject(const BSONObj& roleObject) { + BSONElement roleNameElement; + BSONElement roleSourceElement; + return _extractRoleDocumentElements(roleObject, &roleNameElement, &roleSourceElement); +} + +Status V2UserDocumentParser::parseRoleName(const BSONObj& roleObject, RoleName* result) { + BSONElement roleNameElement; + BSONElement roleSourceElement; + Status status = _extractRoleDocumentElements(roleObject, &roleNameElement, &roleSourceElement); + if (!status.isOK()) + return status; + *result = RoleName(roleNameElement.str(), roleSourceElement.str()); + return status; +} + +Status V2UserDocumentParser::parseRoleVector(const BSONArray& rolesArray, + std::vector<RoleName>* result) { + std::vector<RoleName> roles; + for (BSONObjIterator it(rolesArray); it.more(); it.next()) { + if ((*it).type() != Object) { + return Status(ErrorCodes::TypeMismatch, "Roles must be objects."); } - std::swap(*result, roles); - return Status::OK(); + RoleName role; + Status status = parseRoleName((*it).Obj(), &role); + if (!status.isOK()) + return status; + roles.push_back(role); } + std::swap(*result, roles); + return Status::OK(); +} - Status V2UserDocumentParser::initializeUserRolesFromUserDocument( - const BSONObj& privDoc, User* user) const { +Status V2UserDocumentParser::initializeUserRolesFromUserDocument(const BSONObj& privDoc, + User* user) const { + BSONElement rolesElement = privDoc[ROLES_FIELD_NAME]; - BSONElement rolesElement = privDoc[ROLES_FIELD_NAME]; + if (rolesElement.type() != Array) { + return Status(ErrorCodes::UnsupportedFormat, + "User document needs 'roles' field to be an array"); + } - if (rolesElement.type() != Array) { + std::vector<RoleName> roles; + for (BSONObjIterator it(rolesElement.Obj()); it.more(); it.next()) { + if ((*it).type() != Object) { return Status(ErrorCodes::UnsupportedFormat, - "User document needs 'roles' field to be an array"); + "User document needs values in 'roles' array to be a sub-documents"); } + BSONObj roleObject = (*it).Obj(); - std::vector<RoleName> roles; - for (BSONObjIterator it(rolesElement.Obj()); it.more(); it.next()) { - if ((*it).type() != Object) { - return Status(ErrorCodes::UnsupportedFormat, - "User document needs values in 'roles' array to be a sub-documents"); - } - BSONObj roleObject = (*it).Obj(); - - RoleName role; - Status status = parseRoleName(roleObject, &role); - if (!status.isOK()) { - return status; - } - roles.push_back(role); + RoleName role; + Status status = parseRoleName(roleObject, &role); + if (!status.isOK()) { + return status; } - user->setRoles(makeRoleNameIteratorForContainer(roles)); - return Status::OK(); + roles.push_back(role); } + user->setRoles(makeRoleNameIteratorForContainer(roles)); + return Status::OK(); +} - Status V2UserDocumentParser::initializeUserIndirectRolesFromUserDocument( - const BSONObj& privDoc, User* user) const { +Status V2UserDocumentParser::initializeUserIndirectRolesFromUserDocument(const BSONObj& privDoc, + User* user) const { + BSONElement indirectRolesElement = privDoc[INHERITED_ROLES_FIELD_NAME]; - BSONElement indirectRolesElement = privDoc[INHERITED_ROLES_FIELD_NAME]; + if (indirectRolesElement.type() != Array) { + return Status(ErrorCodes::UnsupportedFormat, + "User document needs 'inheritedRoles' field to be an array"); + } - if (indirectRolesElement.type() != Array) { + std::vector<RoleName> indirectRoles; + for (BSONObjIterator it(indirectRolesElement.Obj()); it.more(); it.next()) { + if ((*it).type() != Object) { return Status(ErrorCodes::UnsupportedFormat, - "User document needs 'inheritedRoles' field to be an array"); + "User document needs values in 'inheritedRoles'" + " array to be a sub-documents"); } + BSONObj indirectRoleObject = (*it).Obj(); - std::vector<RoleName> indirectRoles; - for (BSONObjIterator it(indirectRolesElement.Obj()); it.more(); it.next()) { - if ((*it).type() != Object) { - return Status(ErrorCodes::UnsupportedFormat, - "User document needs values in 'inheritedRoles'" - " array to be a sub-documents"); - } - BSONObj indirectRoleObject = (*it).Obj(); - - RoleName indirectRole; - Status status = parseRoleName(indirectRoleObject, &indirectRole); - if (!status.isOK()) { - return status; - } - indirectRoles.push_back(indirectRole); + RoleName indirectRole; + Status status = parseRoleName(indirectRoleObject, &indirectRole); + if (!status.isOK()) { + return status; } - user->setIndirectRoles(makeRoleNameIteratorForContainer(indirectRoles)); + indirectRoles.push_back(indirectRole); + } + user->setIndirectRoles(makeRoleNameIteratorForContainer(indirectRoles)); + return Status::OK(); +} + +Status V2UserDocumentParser::initializeUserPrivilegesFromUserDocument(const BSONObj& doc, + User* user) const { + BSONElement privilegesElement = doc[PRIVILEGES_FIELD_NAME]; + if (privilegesElement.eoo()) return Status::OK(); + if (privilegesElement.type() != Array) { + return Status(ErrorCodes::UnsupportedFormat, + "User document 'inheritedPrivileges' element must be Array if present."); } - - Status V2UserDocumentParser::initializeUserPrivilegesFromUserDocument(const BSONObj& doc, - User* user) const { - BSONElement privilegesElement = doc[PRIVILEGES_FIELD_NAME]; - if (privilegesElement.eoo()) - return Status::OK(); - if (privilegesElement.type() != Array) { - return Status(ErrorCodes::UnsupportedFormat, - "User document 'inheritedPrivileges' element must be Array if present."); + PrivilegeVector privileges; + std::string errmsg; + for (BSONObjIterator it(privilegesElement.Obj()); it.more(); it.next()) { + if ((*it).type() != Object) { + warning() << "Wrong type of element in inheritedPrivileges array for " + << user->getName() << ": " << *it; + continue; } - PrivilegeVector privileges; - std::string errmsg; - for (BSONObjIterator it(privilegesElement.Obj()); it.more(); it.next()) { - if ((*it).type() != Object) { - warning() << "Wrong type of element in inheritedPrivileges array for " << - user->getName() << ": " << *it; - continue; - } - Privilege privilege; - ParsedPrivilege pp; - if (!pp.parseBSON((*it).Obj(), &errmsg) || - !ParsedPrivilege::parsedPrivilegeToPrivilege(pp, &privilege, &errmsg)) { - - warning() << "Could not parse privilege element in user document for " << - user->getName() << ": " << errmsg; - continue; - } - privileges.push_back(privilege); + Privilege privilege; + ParsedPrivilege pp; + if (!pp.parseBSON((*it).Obj(), &errmsg) || + !ParsedPrivilege::parsedPrivilegeToPrivilege(pp, &privilege, &errmsg)) { + warning() << "Could not parse privilege element in user document for " + << user->getName() << ": " << errmsg; + continue; } - user->setPrivileges(privileges); - return Status::OK(); + privileges.push_back(privilege); } + user->setPrivileges(privileges); + return Status::OK(); +} -} // namespace mongo +} // namespace mongo |