Status V2PrivilegeDocumentParser::checkValidPrivilegeDocument(const BSONObj& doc) const { BSONElement userElement = doc[AuthorizationManager::USER_NAME_FIELD_NAME]; BSONElement userSourceElement = doc[AuthorizationManager::USER_SOURCE_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 (makeStringDataFromBSONElement(userElement).empty()) return _badValue("User document needs 'user' field to be non-empty", 0); // Validate the "userSource" element if (userSourceElement.type() != String || makeStringDataFromBSONElement(userSourceElement).empty()) { return _badValue("User document needs 'userSource' field to be a non-empty string", 0); } StringData userSourceStr = makeStringDataFromBSONElement(userSourceElement); if (!NamespaceString::validDBName(userSourceStr) && userSourceStr != "$external") { return _badValue(mongoutils::str::stream() << "'" << userSourceStr << "' is not a valid value for the userSource field.", 0); } // Validate the "credentials" element if (credentialsElement.eoo() && userSourceStr != "$external") { return _badValue("User document needs 'credentials' field unless userSource is " "'$external'", 0); } if (!credentialsElement.eoo()) { if (credentialsElement.type() != Object) { return _badValue("User document needs 'credentials' field to be an object", 0); } BSONObj credentialsObj = credentialsElement.Obj(); if (credentialsObj.isEmpty()) { return _badValue("User document needs 'credentials' field to be a non-empty object", 0); } BSONElement MongoCRElement = credentialsObj[MONGODB_CR_CREDENTIAL_FIELD_NAME]; if (!MongoCRElement.eoo() && (MongoCRElement.type() != String || makeStringDataFromBSONElement(MongoCRElement).empty())) { return _badValue("MONGODB-CR credential must to be a non-empty string, if present", 0); } } // Validate the "roles" element. Status status = _checkV2RolesArray(rolesElement); if (!status.isOK()) return status; return Status::OK(); }
Status V2UserDocumentParser::checkValidUserDocument(const BSONObj& doc) const { auto userIdElement = doc[AuthorizationManager::USERID_FIELD_NAME]; auto userElement = doc[AuthorizationManager::USER_NAME_FIELD_NAME]; auto userDBElement = doc[AuthorizationManager::USER_DB_FIELD_NAME]; auto credentialsElement = doc[CREDENTIALS_FIELD_NAME]; auto rolesElement = doc[ROLES_FIELD_NAME]; // Validate the "userId" element. if (!userIdElement.eoo()) { if (!userIdElement.isBinData(BinDataType::newUUID)) { return _badValue("User document needs 'userId' field to be a UUID"); } } // Validate the "user" element. if (userElement.type() != String) return _badValue("User document needs 'user' field to be a string"); if (userElement.valueStringData().empty()) return _badValue("User document needs 'user' field to be non-empty"); // Validate the "db" element if (userDBElement.type() != String || userDBElement.valueStringData().empty()) { return _badValue("User document needs 'db' field to be a non-empty string"); } StringData userDBStr = userDBElement.valueStringData(); if (!NamespaceString::validDBName(userDBStr, NamespaceString::DollarInDbNameBehavior::Allow) && userDBStr != "$external") { return _badValue(mongoutils::str::stream() << "'" << userDBStr << "' is not a valid value for the db field."); } // Validate the "credentials" element if (credentialsElement.eoo()) { return _badValue("User document needs 'credentials' object"); } if (credentialsElement.type() != Object) { return _badValue("User document needs 'credentials' field to be an object"); } BSONObj credentialsObj = credentialsElement.Obj(); if (credentialsObj.isEmpty()) { return _badValue("User document needs 'credentials' field to be a non-empty 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}"); } } else { const auto validateScram = [&credentialsObj](const auto& fieldName) { auto scramElement = credentialsObj[fieldName]; if (scramElement.eoo()) { return Status(ErrorCodes::NoSuchKey, str::stream() << fieldName << " does not exist"); } if (scramElement.type() != Object) { return _badValue(str::stream() << fieldName << " credential must be an object, if present"); } return Status::OK(); }; const auto sha1status = validateScram(SCRAMSHA1_CREDENTIAL_FIELD_NAME); if (!sha1status.isOK() && (sha1status.code() != ErrorCodes::NoSuchKey)) { return sha1status; } const auto sha256status = validateScram(SCRAMSHA256_CREDENTIAL_FIELD_NAME); if (!sha256status.isOK() && (sha256status.code() != ErrorCodes::NoSuchKey)) { return sha256status; } if (!sha1status.isOK() && !sha256status.isOK()) { return _badValue( "User document must provide credentials for all " "non-external users"); } } // Validate the "roles" element. Status status = _checkV2RolesArray(rolesElement); if (!status.isOK()) return status; // Validate the "authenticationRestrictions" element. status = initializeAuthenticationRestrictionsFromUserDocument(doc, nullptr); 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); } 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); } } 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); } } else { return _badValue("User document must provide credentials for all " "non-external users", 0); } } // Validate the "roles" element. Status status = _checkV2RolesArray(rolesElement); if (!status.isOK()) return status; return Status::OK(); }