Status parseRolesInfoCommand(const BSONObj& cmdObj, const StringData& dbname, std::vector<RoleName>* parsedRoleNames) { unordered_set<std::string> validFieldNames; validFieldNames.insert("rolesInfo"); Status status = _checkNoExtraFields(cmdObj, "rolesInfo", validFieldNames); if (!status.isOK()) { return status; } if (cmdObj["rolesInfo"].type() == Array) { status = parseRoleNamesFromBSONArray(BSONArray(cmdObj["rolesInfo"].Obj()), dbname, parsedRoleNames); if (!status.isOK()) { return status; } } else { RoleName name; status = _parseNameFromBSONElement(cmdObj["rolesInfo"], dbname, AuthorizationManager::ROLE_NAME_FIELD_NAME, AuthorizationManager::ROLE_SOURCE_FIELD_NAME, &name); if (!status.isOK()) { return status; } parsedRoleNames->push_back(name); } return Status::OK(); }
Status parseCreateOrUpdateRoleCommands(const BSONObj& cmdObj, const StringData& cmdName, const std::string& dbname, CreateOrUpdateRoleArgs* parsedArgs) { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert("privileges"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, &parsedArgs->writeConcern); if (!status.isOK()) { return status; } std::string roleName; status = bsonExtractStringField(cmdObj, "createRole", &roleName); if (!status.isOK()) { return status; } parsedArgs->roleName = RoleName(roleName, dbname); // Parse privileges if (cmdObj.hasField("privileges")) { BSONElement privilegesElement; status = bsonExtractTypedField(cmdObj, "privileges", Array, &privilegesElement); if (!status.isOK()) { return status; } status = parseAndValidatePrivilegeArray(BSONArray(privilegesElement.Obj()), &parsedArgs->privileges); if (!status.isOK()) { return status; } parsedArgs->hasPrivileges = true; } // Parse roles if (cmdObj.hasField("roles")) { BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } status = parseRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), dbname, "roles", &parsedArgs->roles); if (!status.isOK()) { return status; } parsedArgs->hasRoles = true; } return Status::OK(); }
Status parseAndValidateRemoveUserCommand(const BSONObj& cmdObj, const std::string& dbname, UserName* parsedUserName, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert("removeUser"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "removeUser", validFieldNames); if (!status.isOK()) { return status; } std::string user; status = bsonExtractStringField(cmdObj, "removeUser", &user); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } *parsedUserName = UserName(user, dbname); return Status::OK(); }
Status parseRolesInfoCommand(const BSONObj& cmdObj, const StringData& dbname, RolesInfoArgs* parsedArgs) { unordered_set<std::string> validFieldNames; validFieldNames.insert("rolesInfo"); validFieldNames.insert("showPrivileges"); validFieldNames.insert("showBuiltinRoles"); Status status = _checkNoExtraFields(cmdObj, "rolesInfo", validFieldNames); if (!status.isOK()) { return status; } if (cmdObj["rolesInfo"].numberInt() == 1) { parsedArgs->allForDB = true; } else if (cmdObj["rolesInfo"].type() == Array) { status = parseRoleNamesFromBSONArray(BSONArray(cmdObj["rolesInfo"].Obj()), dbname, &parsedArgs->roleNames); if (!status.isOK()) { return status; } } else { RoleName name; status = _parseNameFromBSONElement(cmdObj["rolesInfo"], dbname, AuthorizationManager::ROLE_NAME_FIELD_NAME, AuthorizationManager::ROLE_SOURCE_FIELD_NAME, &name); if (!status.isOK()) { return status; } parsedArgs->roleNames.push_back(name); } status = bsonExtractBooleanFieldWithDefault(cmdObj, "showPrivileges", false, &parsedArgs->showPrivileges); if (!status.isOK()) { return status; } status = bsonExtractBooleanFieldWithDefault(cmdObj, "showBuiltinRoles", false, &parsedArgs->showBuiltinRoles); if (!status.isOK()) { return status; } return Status::OK(); }
Status parseUserRoleManipulationCommand(const BSONObj& cmdObj, const StringData& cmdName, const std::string& dbname, AuthorizationManager* authzManager, UserName* parsedUserName, vector<RoleName>* parsedRoleNames, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } std::string userNameStr; status = bsonExtractStringField(cmdObj, cmdName, &userNameStr); if (!status.isOK()) { return status; } *parsedUserName = UserName(userNameStr, dbname); BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } status = _extractRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), dbname, authzManager, parsedRoleNames); if (!status.isOK()) { return status; } if (!parsedRoleNames->size()) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << cmdName << " command requires a non-empty" << " roles array"); } return Status::OK(); }
Status parseAndValidateRolePrivilegeManipulationCommands(const BSONObj& cmdObj, const StringData& cmdName, const std::string& dbname, RoleName* parsedRoleName, PrivilegeVector* parsedPrivileges, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert("privileges"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } BSONObjBuilder roleObjBuilder; // Parse role name std::string roleName; status = bsonExtractStringField(cmdObj, cmdName, &roleName); if (!status.isOK()) { return status; } *parsedRoleName = RoleName(roleName, dbname); // Parse privileges BSONElement privilegesElement; status = bsonExtractTypedField(cmdObj, "privileges", Array, &privilegesElement); if (!status.isOK()) { return status; } status = parseAndValidatePrivilegeArray(BSONArray(privilegesElement.Obj()), parsedPrivileges); if (!status.isOK()) { return status; } if (!parsedPrivileges->size()) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << cmdName << " command requires a non-empty " "\"privileges\" array"); } return Status::OK(); }
Status parseRolePossessionManipulationCommands(const BSONObj& cmdObj, const StringData& cmdName, const StringData& rolesFieldName, const std::string& dbname, std::string* parsedName, vector<RoleName>* parsedRoleNames, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert(rolesFieldName.toString()); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } status = bsonExtractStringField(cmdObj, cmdName, parsedName); if (!status.isOK()) { return status; } BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, rolesFieldName, Array, &rolesElement); if (!status.isOK()) { return status; } status = parseRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), dbname, rolesFieldName, parsedRoleNames); if (!status.isOK()) { return status; } if (!parsedRoleNames->size()) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << cmdName << " command requires a non-empty \"" << rolesFieldName << "\" array"); } return Status::OK(); }
Status parseAndValidateRemoveUsersFromDatabaseCommand(const BSONObj& cmdObj, const std::string& dbname, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert("removeUsersFromDatabase"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "removeUsersFromDatabase", validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } return Status::OK(); }
Status parseAuthSchemaUpgradeStepCommand(const BSONObj& cmdObj, const std::string& dbname, int* maxSteps, bool* shouldUpgradeShards, BSONObj* parsedWriteConcern) { static const int minUpgradeSteps = 1; static const int maxUpgradeSteps = 2; unordered_set<std::string> validFieldNames; validFieldNames.insert("authSchemaUpgrade"); validFieldNames.insert("maxSteps"); validFieldNames.insert("upgradeShards"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "authSchemaUpgrade", validFieldNames); if (!status.isOK()) { return status; } status = bsonExtractBooleanFieldWithDefault( cmdObj, "upgradeShards", true, shouldUpgradeShards); if (!status.isOK()) { return status; } long long steps; status = bsonExtractIntegerFieldWithDefault(cmdObj, "maxSteps", maxUpgradeSteps, &steps); if (!status.isOK()) return status; if (steps < minUpgradeSteps || steps > maxUpgradeSteps) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Legal values for \"maxSteps\" are at least " << minUpgradeSteps << " and no more than " << maxUpgradeSteps << "; found " << steps); } *maxSteps = static_cast<int>(steps); status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } return Status::OK(); }
Status parseAuthSchemaUpgradeStepCommand(const BSONObj& cmdObj, const std::string& dbname, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert("authSchemaUpgradeStep"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "authSchemaUpgradeStep", validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } return Status::OK(); }
Status parseAndValidateInfoCommands(const BSONObj& cmdObj, const StringData& cmdName, const std::string& dbname, bool* parsedAnyDB, BSONElement* parsedNameFilter) { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert("anyDB"); validFieldNames.insert("writeConcern"); validFieldNames.insert("details"); Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); if (!status.isOK()) { return status; } if (cmdObj[cmdName].type() != String && cmdObj[cmdName].type() != RegEx) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Argument to \"" << cmdName << "\"command must be either a string or a regex"); } *parsedNameFilter = cmdObj[cmdName]; bool anyDB = false; if (cmdObj.hasField("anyDB")) { if (dbname == "admin") { Status status = bsonExtractBooleanField(cmdObj, "anyDB", &anyDB); if (!status.isOK()) { return status; } } else { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "\"anyDB\" argument to \"" << cmdName << "\"command is only valid when run on the \"admin\" database"); } } *parsedAnyDB = anyDB; return Status::OK(); }
Status parseAndValidateUsersInfoCommand(const BSONObj& cmdObj, const std::string& dbname, bool* parsedAnyDB, BSONElement* parsedUsersFilter) { unordered_set<std::string> validFieldNames; validFieldNames.insert("usersInfo"); validFieldNames.insert("anyDB"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "usersInfo", validFieldNames); if (!status.isOK()) { return status; } if (cmdObj["usersInfo"].type() != String && cmdObj["usersInfo"].type() != RegEx) { return Status(ErrorCodes::BadValue, "Argument to userInfo command must be either a string or a regex"); } *parsedUsersFilter = cmdObj["usersInfo"]; bool anyDB = false; if (cmdObj.hasField("anyDB")) { if (dbname == "admin") { Status status = bsonExtractBooleanField(cmdObj, "anyDB", &anyDB); if (!status.isOK()) { return status; } } else { return Status(ErrorCodes::BadValue, "\"anyDB\" argument to usersInfo command is only valid when " "run on the \"admin\" database"); } } *parsedAnyDB = anyDB; return Status::OK(); }
Status parseAndValidateCreateRoleCommand(const BSONObj& cmdObj, const std::string& dbname, AuthorizationManager* authzManager, BSONObj* parsedRoleObj, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert("createRole"); validFieldNames.insert("privileges"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "createRole", validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } BSONObjBuilder roleObjBuilder; // Parse role name std::string roleName; status = bsonExtractStringField(cmdObj, "createRole", &roleName); if (!status.isOK()) { return status; } // Prevent creating roles in the local database if (dbname == "local") { return Status(ErrorCodes::BadValue, "Cannot create roles in the local database"); } roleObjBuilder.append("_id", dbname + "." + roleName); roleObjBuilder.append(AuthorizationManager::ROLE_NAME_FIELD_NAME, roleName); roleObjBuilder.append(AuthorizationManager::ROLE_SOURCE_FIELD_NAME, dbname); // Parse privileges BSONElement privilegesElement; status = bsonExtractTypedField(cmdObj, "privileges", Array, &privilegesElement); if (!status.isOK()) { return status; } status = _parseAndValidatePrivilegeArray(BSONArray(privilegesElement.Obj()), NULL); if (!status.isOK()) { return status; } roleObjBuilder.append(privilegesElement); // Parse roles BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } BSONArray modifiedRolesArray; status = _validateAndModifyRolesArray(rolesElement, dbname, authzManager, false, &modifiedRolesArray); if (!status.isOK()) { return status; } roleObjBuilder.append("roles", modifiedRolesArray); *parsedRoleObj = roleObjBuilder.obj(); return Status::OK(); }
Status parseAndValidateUpdateUserCommand(const BSONObj& cmdObj, const std::string& dbname, AuthorizationManager* authzManager, BSONObj* parsedUpdateObj, UserName* parsedUserName, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert("updateUser"); validFieldNames.insert("customData"); validFieldNames.insert("pwd"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "updateUser", validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } BSONObjBuilder updateSetBuilder; // Parse user name std::string userName; status = bsonExtractStringField(cmdObj, "updateUser", &userName); if (!status.isOK()) { return status; } *parsedUserName = UserName(userName, dbname); // Parse password if (cmdObj.hasField("pwd")) { std::string clearTextPassword; status = bsonExtractStringField(cmdObj, "pwd", &clearTextPassword); if (!status.isOK()) { return status; } std::string password = auth::createPasswordDigest(userName, clearTextPassword); updateSetBuilder.append("credentials.MONGODB-CR", password); } // Parse custom data if (cmdObj.hasField("customData")) { BSONElement element; status = bsonExtractTypedField(cmdObj, "customData", Object, &element); if (!status.isOK()) { return status; } updateSetBuilder.append("customData", element.Obj()); } // Parse roles if (cmdObj.hasField("roles")) { BSONElement rolesElement; Status status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } BSONArray modifiedRolesObj; status = _validateAndModifyRolesArray(rolesElement, dbname, authzManager, true, &modifiedRolesObj); if (!status.isOK()) { return status; } updateSetBuilder.append("roles", modifiedRolesObj); } BSONObj updateSet = updateSetBuilder.obj(); if (updateSet.isEmpty()) { return Status(ErrorCodes::UserModificationFailed, "Must specify at least one field to update in updateUser"); } *parsedUpdateObj = BSON("$set" << updateSet); return Status::OK(); }
Status parseAndValidateCreateUserCommand(const BSONObj& cmdObj, const std::string& dbname, AuthorizationManager* authzManager, BSONObj* parsedUserObj, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert("createUser"); validFieldNames.insert("customData"); validFieldNames.insert("pwd"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "createUser", validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } BSONObjBuilder userObjBuilder; // Parse user name std::string userName; status = bsonExtractStringField(cmdObj, "createUser", &userName); if (!status.isOK()) { return status; } // Prevent creating users in the local database if (dbname == "local") { return Status(ErrorCodes::BadValue, "Cannot create users in the local database"); } userObjBuilder.append("_id", dbname + "." + userName); userObjBuilder.append(AuthorizationManager::USER_NAME_FIELD_NAME, userName); userObjBuilder.append(AuthorizationManager::USER_SOURCE_FIELD_NAME, dbname); // Parse password if (cmdObj.hasField("pwd")) { std::string clearTextPassword; status = bsonExtractStringField(cmdObj, "pwd", &clearTextPassword); if (!status.isOK()) { return status; } std::string password = auth::createPasswordDigest(userName, clearTextPassword); userObjBuilder.append("credentials", BSON("MONGODB-CR" << password)); } else { if (dbname != "$external") { return Status(ErrorCodes::BadValue, "Must provide a 'pwd' field for all user documents, except those" " with '$external' as the user's source"); } } // Parse custom data if (cmdObj.hasField("customData")) { BSONElement element; status = bsonExtractTypedField(cmdObj, "customData", Object, &element); if (!status.isOK()) { return status; } userObjBuilder.append("customData", element.Obj()); } // Parse roles if (cmdObj.hasField("roles")) { BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } BSONArray modifiedRolesArray; status = _validateAndModifyRolesArray(rolesElement, dbname, authzManager, true, &modifiedRolesArray); if (!status.isOK()) { return status; } userObjBuilder.append("roles", modifiedRolesArray); } *parsedUserObj = userObjBuilder.obj(); // Make sure document to insert is valid V2UserDocumentParser parser; status = parser.checkValidUserDocument(*parsedUserObj); if (!status.isOK()) { return status; } return Status::OK(); }
Status parseCreateOrUpdateUserCommands(const BSONObj& cmdObj, const StringData& cmdName, const std::string& dbname, CreateOrUpdateUserArgs* parsedArgs) { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert("customData"); validFieldNames.insert("pwd"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, &parsedArgs->writeConcern); if (!status.isOK()) { return status; } BSONObjBuilder userObjBuilder; // Parse user name std::string userName; status = bsonExtractStringField(cmdObj, cmdName, &userName); if (!status.isOK()) { return status; } parsedArgs->userName = UserName(userName, dbname); // Parse password if (cmdObj.hasField("pwd")) { std::string clearTextPassword; status = bsonExtractStringField(cmdObj, "pwd", &clearTextPassword); if (!status.isOK()) { return status; } parsedArgs->hashedPassword = auth::createPasswordDigest(userName, clearTextPassword); parsedArgs->hasHashedPassword = true; } // Parse custom data if (cmdObj.hasField("customData")) { BSONElement element; status = bsonExtractTypedField(cmdObj, "customData", Object, &element); if (!status.isOK()) { return status; } parsedArgs->customData = element.Obj(); parsedArgs->hasCustomData = true; } // Parse roles if (cmdObj.hasField("roles")) { BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } status = _extractRoleDataFromBSONArray(rolesElement, dbname, &parsedArgs->roles); if (!status.isOK()) { return status; } parsedArgs->hasRoles = true; } return Status::OK(); }
Status parseCreateOrUpdateUserCommands(const BSONObj& cmdObj, const StringData& cmdName, const std::string& dbname, CreateOrUpdateUserArgs* parsedArgs) { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert("customData"); validFieldNames.insert("digestPassword"); validFieldNames.insert("pwd"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, &parsedArgs->writeConcern); if (!status.isOK()) { return status; } BSONObjBuilder userObjBuilder; // Parse user name std::string userName; status = bsonExtractStringField(cmdObj, cmdName, &userName); if (!status.isOK()) { return status; } parsedArgs->userName = UserName(userName, dbname); // Parse password if (cmdObj.hasField("pwd")) { std::string password; status = bsonExtractStringField(cmdObj, "pwd", &password); if (!status.isOK()) { return status; } if (password.empty()) { return Status(ErrorCodes::BadValue, "User passwords must not be empty"); } bool digestPassword; // True if the server should digest the password status = bsonExtractBooleanFieldWithDefault(cmdObj, "digestPassword", true, &digestPassword); if (!status.isOK()) { return status; } if (digestPassword) { parsedArgs->hashedPassword = auth::createPasswordDigest(userName, password); } else { parsedArgs->hashedPassword = password; } parsedArgs->hasHashedPassword = true; } // Parse custom data if (cmdObj.hasField("customData")) { BSONElement element; status = bsonExtractTypedField(cmdObj, "customData", Object, &element); if (!status.isOK()) { return status; } parsedArgs->customData = element.Obj(); parsedArgs->hasCustomData = true; } // Parse roles if (cmdObj.hasField("roles")) { BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } status = parseRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), dbname, &parsedArgs->roles); if (!status.isOK()) { return status; } parsedArgs->hasRoles = true; } return Status::OK(); }