diff options
Diffstat (limited to 'src/mongo/db/auth/user_management_commands_parser.cpp')
-rw-r--r-- | src/mongo/db/auth/user_management_commands_parser.cpp | 1032 |
1 files changed, 500 insertions, 532 deletions
diff --git a/src/mongo/db/auth/user_management_commands_parser.cpp b/src/mongo/db/auth/user_management_commands_parser.cpp index eecef9d9301..82130e2a530 100644 --- a/src/mongo/db/auth/user_management_commands_parser.cpp +++ b/src/mongo/db/auth/user_management_commands_parser.cpp @@ -47,652 +47,620 @@ namespace mongo { namespace auth { - using std::vector; - - /** - * Writes into *writeConcern a BSONObj describing the parameters to getLastError to use for - * the write confirmation. - */ - Status _extractWriteConcern(const BSONObj& cmdObj, BSONObj* writeConcern) { - BSONElement writeConcernElement; - Status status = bsonExtractTypedField(cmdObj, "writeConcern", Object, &writeConcernElement); - if (!status.isOK()) { - if (status.code() == ErrorCodes::NoSuchKey) { - *writeConcern = BSONObj(); - return Status::OK(); - } - return status; - } - *writeConcern = writeConcernElement.Obj().getOwned();; - return Status::OK(); - } - - Status _checkNoExtraFields(const BSONObj& cmdObj, - StringData cmdName, - const unordered_set<std::string>& validFieldNames) { - // Iterate through all fields in command object and make sure there are no unexpected - // ones. - for (BSONObjIterator iter(cmdObj); iter.more(); iter.next()) { - StringData fieldName = (*iter).fieldNameStringData(); - if (!validFieldNames.count(fieldName.toString())) { - return Status(ErrorCodes::BadValue, - mongoutils::str::stream() << "\"" << fieldName << "\" is not " - "a valid argument to " << cmdName); - } - } - return Status::OK(); - } - - // Extracts a UserName or RoleName object from a BSONElement. - template <typename Name> - Status _parseNameFromBSONElement(const BSONElement& element, - StringData dbname, - StringData nameFieldName, - StringData sourceFieldName, - Name* parsedName) { - if (element.type() == String) { - *parsedName = Name(element.String(), dbname); - } - else if (element.type() == Object) { - BSONObj obj = element.Obj(); - - std::string name; - std::string source; - Status status = bsonExtractStringField(obj, nameFieldName, &name); - if (!status.isOK()) { - return status; - } - status = bsonExtractStringField(obj, sourceFieldName, &source); - if (!status.isOK()) { - return status; - } - - *parsedName = Name(name, source); - } - else { +using std::vector; + +/** + * Writes into *writeConcern a BSONObj describing the parameters to getLastError to use for + * the write confirmation. + */ +Status _extractWriteConcern(const BSONObj& cmdObj, BSONObj* writeConcern) { + BSONElement writeConcernElement; + Status status = bsonExtractTypedField(cmdObj, "writeConcern", Object, &writeConcernElement); + if (!status.isOK()) { + if (status.code() == ErrorCodes::NoSuchKey) { + *writeConcern = BSONObj(); + return Status::OK(); + } + return status; + } + *writeConcern = writeConcernElement.Obj().getOwned(); + ; + return Status::OK(); +} + +Status _checkNoExtraFields(const BSONObj& cmdObj, + StringData cmdName, + const unordered_set<std::string>& validFieldNames) { + // Iterate through all fields in command object and make sure there are no unexpected + // ones. + for (BSONObjIterator iter(cmdObj); iter.more(); iter.next()) { + StringData fieldName = (*iter).fieldNameStringData(); + if (!validFieldNames.count(fieldName.toString())) { return Status(ErrorCodes::BadValue, - "User and role names must be either strings or objects"); - } - return Status::OK(); - } - - // Extracts UserName or RoleName objects from a BSONArray of role/user names. - template <typename Name> - Status _parseNamesFromBSONArray(const BSONArray& array, - StringData dbname, - StringData nameFieldName, - StringData sourceFieldName, - std::vector<Name>* parsedNames) { - for (BSONObjIterator it(array); it.more(); it.next()) { - BSONElement element = *it; - Name name; - Status status = _parseNameFromBSONElement(element, - dbname, - nameFieldName, - sourceFieldName, - &name); - if (!status.isOK()) { - return status; - } - parsedNames->push_back(name); - } - return Status::OK(); - } - - Status parseUserNamesFromBSONArray(const BSONArray& usersArray, - StringData dbname, - std::vector<UserName>* parsedUserNames) { - return _parseNamesFromBSONArray(usersArray, - dbname, - AuthorizationManager::USER_NAME_FIELD_NAME, - AuthorizationManager::USER_DB_FIELD_NAME, - parsedUserNames); - } - - Status parseRoleNamesFromBSONArray(const BSONArray& rolesArray, - StringData dbname, - std::vector<RoleName>* parsedRoleNames) { - return _parseNamesFromBSONArray(rolesArray, - dbname, - AuthorizationManager::ROLE_NAME_FIELD_NAME, - AuthorizationManager::ROLE_DB_FIELD_NAME, - parsedRoleNames); - } - - Status parseRolePossessionManipulationCommands(const BSONObj& cmdObj, - StringData cmdName, - const std::string& dbname, - std::string* parsedName, - 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; + mongoutils::str::stream() << "\"" << fieldName << "\" is not " + "a valid argument to " + << cmdName); } + } + return Status::OK(); +} - status = _extractWriteConcern(cmdObj, parsedWriteConcern); - if (!status.isOK()) { - return status; - } +// Extracts a UserName or RoleName object from a BSONElement. +template <typename Name> +Status _parseNameFromBSONElement(const BSONElement& element, + StringData dbname, + StringData nameFieldName, + StringData sourceFieldName, + Name* parsedName) { + if (element.type() == String) { + *parsedName = Name(element.String(), dbname); + } else if (element.type() == Object) { + BSONObj obj = element.Obj(); - status = bsonExtractStringField(cmdObj, cmdName, parsedName); + std::string name; + std::string source; + Status status = bsonExtractStringField(obj, nameFieldName, &name); if (!status.isOK()) { return status; } - - BSONElement rolesElement; - status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); + status = bsonExtractStringField(obj, sourceFieldName, &source); if (!status.isOK()) { return status; } - status = parseRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), - dbname, - parsedRoleNames); - if (!status.isOK()) { - return status; - } + *parsedName = Name(name, source); + } else { + return Status(ErrorCodes::BadValue, + "User and role names must be either strings or objects"); + } + return Status::OK(); +} - if (!parsedRoleNames->size()) { - return Status(ErrorCodes::BadValue, - mongoutils::str::stream() << cmdName << " command requires a non-empty " - "\"roles\" array"); - } - return Status::OK(); - } - - Status parseCreateOrUpdateUserCommands(const BSONObj& cmdObj, - 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); +// Extracts UserName or RoleName objects from a BSONArray of role/user names. +template <typename Name> +Status _parseNamesFromBSONArray(const BSONArray& array, + StringData dbname, + StringData nameFieldName, + StringData sourceFieldName, + std::vector<Name>* parsedNames) { + for (BSONObjIterator it(array); it.more(); it.next()) { + BSONElement element = *it; + Name name; + Status status = + _parseNameFromBSONElement(element, dbname, nameFieldName, sourceFieldName, &name); if (!status.isOK()) { return status; } + parsedNames->push_back(name); + } + return Status::OK(); +} + +Status parseUserNamesFromBSONArray(const BSONArray& usersArray, + StringData dbname, + std::vector<UserName>* parsedUserNames) { + return _parseNamesFromBSONArray(usersArray, + dbname, + AuthorizationManager::USER_NAME_FIELD_NAME, + AuthorizationManager::USER_DB_FIELD_NAME, + parsedUserNames); +} + +Status parseRoleNamesFromBSONArray(const BSONArray& rolesArray, + StringData dbname, + std::vector<RoleName>* parsedRoleNames) { + return _parseNamesFromBSONArray(rolesArray, + dbname, + AuthorizationManager::ROLE_NAME_FIELD_NAME, + AuthorizationManager::ROLE_DB_FIELD_NAME, + parsedRoleNames); +} + +Status parseRolePossessionManipulationCommands(const BSONObj& cmdObj, + StringData cmdName, + const std::string& dbname, + std::string* parsedName, + 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, &parsedArgs->writeConcern); - if (!status.isOK()) { - return status; - } + status = _extractWriteConcern(cmdObj, parsedWriteConcern); + if (!status.isOK()) { + return status; + } - BSONObjBuilder userObjBuilder; + status = bsonExtractStringField(cmdObj, cmdName, parsedName); + if (!status.isOK()) { + return status; + } - // Parse user name - std::string userName; - status = bsonExtractStringField(cmdObj, cmdName, &userName); - if (!status.isOK()) { - return status; - } + BSONElement rolesElement; + status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); + 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 = mongo::createPasswordDigest( - userName, password); - } else { - parsedArgs->hashedPassword = password; - } - parsedArgs->hasHashedPassword = true; - } + status = parseRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), dbname, parsedRoleNames); + if (!status.isOK()) { + return status; + } - // 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; - } + if (!parsedRoleNames->size()) { + return Status(ErrorCodes::BadValue, + mongoutils::str::stream() << cmdName << " command requires a non-empty " + "\"roles\" array"); + } + return Status::OK(); +} + +Status parseCreateOrUpdateUserCommands(const BSONObj& cmdObj, + 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; + } - // 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; - } + status = _extractWriteConcern(cmdObj, &parsedArgs->writeConcern); + if (!status.isOK()) { + return status; + } + + BSONObjBuilder userObjBuilder; - return Status::OK(); + // Parse user name + std::string userName; + status = bsonExtractStringField(cmdObj, cmdName, &userName); + if (!status.isOK()) { + return status; } - Status parseAndValidateDropUserCommand(const BSONObj& cmdObj, - const std::string& dbname, - UserName* parsedUserName, - BSONObj* parsedWriteConcern) { - unordered_set<std::string> validFieldNames; - validFieldNames.insert("dropUser"); - validFieldNames.insert("writeConcern"); + parsedArgs->userName = UserName(userName, dbname); - Status status = _checkNoExtraFields(cmdObj, "dropUser", validFieldNames); + // 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"); + } - std::string user; - status = bsonExtractStringField(cmdObj, "dropUser", &user); + bool digestPassword; // True if the server should digest the password + status = + bsonExtractBooleanFieldWithDefault(cmdObj, "digestPassword", true, &digestPassword); if (!status.isOK()) { return status; } - status = _extractWriteConcern(cmdObj, parsedWriteConcern); + if (digestPassword) { + parsedArgs->hashedPassword = mongo::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; } - - *parsedUserName = UserName(user, dbname); - return Status::OK(); + parsedArgs->customData = element.Obj(); + parsedArgs->hasCustomData = true; } - Status parseFromDatabaseCommand(const BSONObj& cmdObj, - const std::string& dbname, - BSONObj* parsedWriteConcern, - std::string command) { - unordered_set<std::string> validFieldNames; - validFieldNames.insert(command); - validFieldNames.insert("writeConcern"); - - Status status = _checkNoExtraFields(cmdObj, command, validFieldNames); + // Parse roles + if (cmdObj.hasField("roles")) { + BSONElement rolesElement; + status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } - - status = _extractWriteConcern(cmdObj, parsedWriteConcern); + status = + parseRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), dbname, &parsedArgs->roles); if (!status.isOK()) { return status; } + parsedArgs->hasRoles = true; + } + + return Status::OK(); +} + +Status parseAndValidateDropUserCommand(const BSONObj& cmdObj, + const std::string& dbname, + UserName* parsedUserName, + BSONObj* parsedWriteConcern) { + unordered_set<std::string> validFieldNames; + validFieldNames.insert("dropUser"); + validFieldNames.insert("writeConcern"); - return Status::OK(); + Status status = _checkNoExtraFields(cmdObj, "dropUser", validFieldNames); + if (!status.isOK()) { + return status; } - Status parseAndValidateDropAllUsersFromDatabaseCommand(const BSONObj& cmdObj, - const std::string& dbname, - BSONObj* parsedWriteConcern) { - return parseFromDatabaseCommand(cmdObj, dbname, parsedWriteConcern, "dropAllUsersFromDatabase"); + + std::string user; + status = bsonExtractStringField(cmdObj, "dropUser", &user); + if (!status.isOK()) { + return status; } - Status parseUsersInfoCommand(const BSONObj& cmdObj, - StringData dbname, - UsersInfoArgs* parsedArgs) { - unordered_set<std::string> validFieldNames; - validFieldNames.insert("usersInfo"); - validFieldNames.insert("showPrivileges"); - validFieldNames.insert("showCredentials"); + status = _extractWriteConcern(cmdObj, parsedWriteConcern); + if (!status.isOK()) { + return status; + } - Status status = _checkNoExtraFields(cmdObj, "usersInfo", validFieldNames); - if (!status.isOK()) { - return status; - } + *parsedUserName = UserName(user, dbname); + return Status::OK(); +} - if (cmdObj["usersInfo"].numberInt() == 1) { - parsedArgs->allForDB = true; - } else if (cmdObj["usersInfo"].type() == Array) { - status = parseUserNamesFromBSONArray(BSONArray(cmdObj["usersInfo"].Obj()), - dbname, - &parsedArgs->userNames); - if (!status.isOK()) { - return status; - } - } else { - UserName name; - status = _parseNameFromBSONElement(cmdObj["usersInfo"], - dbname, - AuthorizationManager::USER_NAME_FIELD_NAME, - AuthorizationManager::USER_DB_FIELD_NAME, - &name); - if (!status.isOK()) { - return status; - } - parsedArgs->userNames.push_back(name); - } +Status parseFromDatabaseCommand(const BSONObj& cmdObj, + const std::string& dbname, + BSONObj* parsedWriteConcern, + std::string command) { + unordered_set<std::string> validFieldNames; + validFieldNames.insert(command); + validFieldNames.insert("writeConcern"); + + Status status = _checkNoExtraFields(cmdObj, command, validFieldNames); + if (!status.isOK()) { + return status; + } - status = bsonExtractBooleanFieldWithDefault(cmdObj, - "showPrivileges", - false, - &parsedArgs->showPrivileges); + status = _extractWriteConcern(cmdObj, parsedWriteConcern); + if (!status.isOK()) { + return status; + } + + return Status::OK(); +} +Status parseAndValidateDropAllUsersFromDatabaseCommand(const BSONObj& cmdObj, + const std::string& dbname, + BSONObj* parsedWriteConcern) { + return parseFromDatabaseCommand(cmdObj, dbname, parsedWriteConcern, "dropAllUsersFromDatabase"); +} + +Status parseUsersInfoCommand(const BSONObj& cmdObj, StringData dbname, UsersInfoArgs* parsedArgs) { + unordered_set<std::string> validFieldNames; + validFieldNames.insert("usersInfo"); + validFieldNames.insert("showPrivileges"); + validFieldNames.insert("showCredentials"); + + Status status = _checkNoExtraFields(cmdObj, "usersInfo", validFieldNames); + if (!status.isOK()) { + return status; + } + + if (cmdObj["usersInfo"].numberInt() == 1) { + parsedArgs->allForDB = true; + } else if (cmdObj["usersInfo"].type() == Array) { + status = parseUserNamesFromBSONArray( + BSONArray(cmdObj["usersInfo"].Obj()), dbname, &parsedArgs->userNames); if (!status.isOK()) { return status; } - status = bsonExtractBooleanFieldWithDefault(cmdObj, - "showCredentials", - false, - &parsedArgs->showCredentials); + } else { + UserName name; + status = _parseNameFromBSONElement(cmdObj["usersInfo"], + dbname, + AuthorizationManager::USER_NAME_FIELD_NAME, + AuthorizationManager::USER_DB_FIELD_NAME, + &name); if (!status.isOK()) { return status; } + parsedArgs->userNames.push_back(name); + } - return Status::OK(); + status = bsonExtractBooleanFieldWithDefault( + cmdObj, "showPrivileges", false, &parsedArgs->showPrivileges); + if (!status.isOK()) { + return status; + } + status = bsonExtractBooleanFieldWithDefault( + cmdObj, "showCredentials", false, &parsedArgs->showCredentials); + if (!status.isOK()) { + return status; } - Status parseRolesInfoCommand(const BSONObj& cmdObj, - StringData dbname, - RolesInfoArgs* parsedArgs) { - unordered_set<std::string> validFieldNames; - validFieldNames.insert("rolesInfo"); - validFieldNames.insert("showPrivileges"); - validFieldNames.insert("showBuiltinRoles"); + return Status::OK(); +} - Status status = _checkNoExtraFields(cmdObj, "rolesInfo", validFieldNames); - if (!status.isOK()) { - return status; - } +Status parseRolesInfoCommand(const BSONObj& cmdObj, StringData dbname, RolesInfoArgs* parsedArgs) { + unordered_set<std::string> validFieldNames; + validFieldNames.insert("rolesInfo"); + validFieldNames.insert("showPrivileges"); + validFieldNames.insert("showBuiltinRoles"); - 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_DB_FIELD_NAME, - &name); - if (!status.isOK()) { - return status; - } - parsedArgs->roleNames.push_back(name); - } + Status status = _checkNoExtraFields(cmdObj, "rolesInfo", validFieldNames); + if (!status.isOK()) { + return status; + } - status = bsonExtractBooleanFieldWithDefault(cmdObj, - "showPrivileges", - false, - &parsedArgs->showPrivileges); + 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; } - - status = bsonExtractBooleanFieldWithDefault(cmdObj, - "showBuiltinRoles", - false, - &parsedArgs->showBuiltinRoles); + } else { + RoleName name; + status = _parseNameFromBSONElement(cmdObj["rolesInfo"], + dbname, + AuthorizationManager::ROLE_NAME_FIELD_NAME, + AuthorizationManager::ROLE_DB_FIELD_NAME, + &name); if (!status.isOK()) { return status; } + parsedArgs->roleNames.push_back(name); + } - return Status::OK(); - } - - /* - * Validates that the given privilege BSONArray is valid. - * If parsedPrivileges is not NULL, adds to it the privileges parsed out of the input BSONArray. - */ - Status parseAndValidatePrivilegeArray(const BSONArray& privileges, - PrivilegeVector* parsedPrivileges) { - for (BSONObjIterator it(privileges); it.more(); it.next()) { - BSONElement element = *it; - if (element.type() != Object) { - return Status(ErrorCodes::FailedToParse, - "Elements in privilege arrays must be objects"); - } - - ParsedPrivilege parsedPrivilege; - std::string errmsg; - if (!parsedPrivilege.parseBSON(element.Obj(), &errmsg)) { - return Status(ErrorCodes::FailedToParse, errmsg); - } - if (!parsedPrivilege.isValid(&errmsg)) { - return Status(ErrorCodes::FailedToParse, errmsg); - } - - Privilege privilege; - if (!ParsedPrivilege::parsedPrivilegeToPrivilege(parsedPrivilege, &privilege, &errmsg)) { - return Status(ErrorCodes::FailedToParse, errmsg); - } - - parsedPrivileges->push_back(privilege); - } - return Status::OK(); + status = bsonExtractBooleanFieldWithDefault( + cmdObj, "showPrivileges", false, &parsedArgs->showPrivileges); + if (!status.isOK()) { + return status; } - Status parseCreateOrUpdateRoleCommands(const BSONObj& cmdObj, - 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 = bsonExtractBooleanFieldWithDefault( + cmdObj, "showBuiltinRoles", false, &parsedArgs->showBuiltinRoles); + if (!status.isOK()) { + return status; + } - Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); - if (!status.isOK()) { - return status; - } + return Status::OK(); +} - status = _extractWriteConcern(cmdObj, &parsedArgs->writeConcern); - if (!status.isOK()) { - return status; +/* + * Validates that the given privilege BSONArray is valid. + * If parsedPrivileges is not NULL, adds to it the privileges parsed out of the input BSONArray. + */ +Status parseAndValidatePrivilegeArray(const BSONArray& privileges, + PrivilegeVector* parsedPrivileges) { + for (BSONObjIterator it(privileges); it.more(); it.next()) { + BSONElement element = *it; + if (element.type() != Object) { + return Status(ErrorCodes::FailedToParse, + "Elements in privilege arrays must be objects"); } - std::string roleName; - status = bsonExtractStringField(cmdObj, cmdName, &roleName); - if (!status.isOK()) { - return status; + ParsedPrivilege parsedPrivilege; + std::string errmsg; + if (!parsedPrivilege.parseBSON(element.Obj(), &errmsg)) { + return Status(ErrorCodes::FailedToParse, errmsg); } - 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; + if (!parsedPrivilege.isValid(&errmsg)) { + return Status(ErrorCodes::FailedToParse, errmsg); } - // 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; + Privilege privilege; + if (!ParsedPrivilege::parsedPrivilegeToPrivilege(parsedPrivilege, &privilege, &errmsg)) { + return Status(ErrorCodes::FailedToParse, errmsg); } - return Status::OK(); - } - - Status parseAndValidateRolePrivilegeManipulationCommands(const BSONObj& cmdObj, - 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; - } + parsedPrivileges->push_back(privilege); + } + return Status::OK(); +} + +Status parseCreateOrUpdateRoleCommands(const BSONObj& cmdObj, + 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; + } - BSONObjBuilder roleObjBuilder; + status = _extractWriteConcern(cmdObj, &parsedArgs->writeConcern); + if (!status.isOK()) { + return status; + } - // Parse role name - std::string roleName; - status = bsonExtractStringField(cmdObj, cmdName, &roleName); - if (!status.isOK()) { - return status; - } - *parsedRoleName = RoleName(roleName, dbname); + std::string roleName; + status = bsonExtractStringField(cmdObj, cmdName, &roleName); + if (!status.isOK()) { + return status; + } + parsedArgs->roleName = RoleName(roleName, dbname); - // Parse privileges + // Parse privileges + if (cmdObj.hasField("privileges")) { BSONElement privilegesElement; status = bsonExtractTypedField(cmdObj, "privileges", Array, &privilegesElement); if (!status.isOK()) { return status; } status = parseAndValidatePrivilegeArray(BSONArray(privilegesElement.Obj()), - parsedPrivileges); + &parsedArgs->privileges); 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(); + parsedArgs->hasPrivileges = true; } - Status parseDropRoleCommand(const BSONObj& cmdObj, - const std::string& dbname, - RoleName* parsedRoleName, - BSONObj* parsedWriteConcern) { - unordered_set<std::string> validFieldNames; - validFieldNames.insert("dropRole"); - validFieldNames.insert("writeConcern"); - - Status status = _checkNoExtraFields(cmdObj, "dropRole", validFieldNames); + // Parse roles + if (cmdObj.hasField("roles")) { + BSONElement rolesElement; + status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } - - std::string user; - status = bsonExtractStringField(cmdObj, "dropRole", &user); + status = + parseRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), dbname, &parsedArgs->roles); if (!status.isOK()) { return status; } + parsedArgs->hasRoles = true; + } + return Status::OK(); +} + +Status parseAndValidateRolePrivilegeManipulationCommands(const BSONObj& cmdObj, + 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; - } + status = _extractWriteConcern(cmdObj, parsedWriteConcern); + if (!status.isOK()) { + return status; + } + + BSONObjBuilder roleObjBuilder; - *parsedRoleName = RoleName(user, dbname); - return Status::OK(); + // Parse role name + std::string roleName; + status = bsonExtractStringField(cmdObj, cmdName, &roleName); + if (!status.isOK()) { + return status; } + *parsedRoleName = RoleName(roleName, dbname); - Status parseDropAllRolesFromDatabaseCommand(const BSONObj& cmdObj, - const std::string& dbname, - BSONObj* parsedWriteConcern) { - return parseFromDatabaseCommand(cmdObj, dbname, parsedWriteConcern, "dropAllRolesFromDatabase"); + // 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"); } - Status parseMergeAuthzCollectionsCommand(const BSONObj& cmdObj, - MergeAuthzCollectionsArgs* parsedArgs) { - unordered_set<std::string> validFieldNames; - validFieldNames.insert("_mergeAuthzCollections"); - validFieldNames.insert("tempUsersCollection"); - validFieldNames.insert("tempRolesCollection"); - validFieldNames.insert("db"); - validFieldNames.insert("drop"); - validFieldNames.insert("writeConcern"); + return Status::OK(); +} - Status status = _checkNoExtraFields(cmdObj, "_mergeAuthzCollections", validFieldNames); - if (!status.isOK()) { - return status; - } +Status parseDropRoleCommand(const BSONObj& cmdObj, + const std::string& dbname, + RoleName* parsedRoleName, + BSONObj* parsedWriteConcern) { + unordered_set<std::string> validFieldNames; + validFieldNames.insert("dropRole"); + validFieldNames.insert("writeConcern"); - status = _extractWriteConcern(cmdObj, &parsedArgs->writeConcern); - if (!status.isOK()) { - return status; - } + Status status = _checkNoExtraFields(cmdObj, "dropRole", validFieldNames); + if (!status.isOK()) { + return status; + } - status = bsonExtractStringFieldWithDefault(cmdObj, - "tempUsersCollection", - "", - &parsedArgs->usersCollName); - if (!status.isOK()) { - return status; - } + std::string user; + status = bsonExtractStringField(cmdObj, "dropRole", &user); + if (!status.isOK()) { + return status; + } - status = bsonExtractStringFieldWithDefault(cmdObj, - "tempRolesCollection", - "", - &parsedArgs->rolesCollName); - if (!status.isOK()) { - return status; - } + status = _extractWriteConcern(cmdObj, parsedWriteConcern); + if (!status.isOK()) { + return status; + } - status = bsonExtractStringField(cmdObj, "db", &parsedArgs->db); - if (!status.isOK()) { - if (status == ErrorCodes::NoSuchKey) { - return Status(ErrorCodes::OutdatedClient, - "Missing \"db\" field for _mergeAuthzCollections command. This is " - "most likely due to running an outdated (pre-2.6.4) version of " - "mongorestore."); - } - return status; - } + *parsedRoleName = RoleName(user, dbname); + return Status::OK(); +} + +Status parseDropAllRolesFromDatabaseCommand(const BSONObj& cmdObj, + const std::string& dbname, + BSONObj* parsedWriteConcern) { + return parseFromDatabaseCommand(cmdObj, dbname, parsedWriteConcern, "dropAllRolesFromDatabase"); +} + +Status parseMergeAuthzCollectionsCommand(const BSONObj& cmdObj, + MergeAuthzCollectionsArgs* parsedArgs) { + unordered_set<std::string> validFieldNames; + validFieldNames.insert("_mergeAuthzCollections"); + validFieldNames.insert("tempUsersCollection"); + validFieldNames.insert("tempRolesCollection"); + validFieldNames.insert("db"); + validFieldNames.insert("drop"); + validFieldNames.insert("writeConcern"); + + Status status = _checkNoExtraFields(cmdObj, "_mergeAuthzCollections", validFieldNames); + if (!status.isOK()) { + return status; + } - status = bsonExtractBooleanFieldWithDefault(cmdObj, - "drop", - false, - &parsedArgs->drop); - if (!status.isOK()) { - return status; + status = _extractWriteConcern(cmdObj, &parsedArgs->writeConcern); + if (!status.isOK()) { + return status; + } + + status = bsonExtractStringFieldWithDefault( + cmdObj, "tempUsersCollection", "", &parsedArgs->usersCollName); + if (!status.isOK()) { + return status; + } + + status = bsonExtractStringFieldWithDefault( + cmdObj, "tempRolesCollection", "", &parsedArgs->rolesCollName); + if (!status.isOK()) { + return status; + } + + status = bsonExtractStringField(cmdObj, "db", &parsedArgs->db); + if (!status.isOK()) { + if (status == ErrorCodes::NoSuchKey) { + return Status(ErrorCodes::OutdatedClient, + "Missing \"db\" field for _mergeAuthzCollections command. This is " + "most likely due to running an outdated (pre-2.6.4) version of " + "mongorestore."); } + return status; + } - return Status::OK(); + status = bsonExtractBooleanFieldWithDefault(cmdObj, "drop", false, &parsedArgs->drop); + if (!status.isOK()) { + return status; } -} // namespace auth -} // namespace mongo + return Status::OK(); +} + +} // namespace auth +} // namespace mongo |