static Status _extractRoleDocumentElements( const BSONObj& roleObject, BSONElement* roleNameElement, BSONElement* roleSourceElement, BSONElement* canDelegateElement, BSONElement* hasRoleElement) { *roleNameElement = roleObject[ROLE_NAME_FIELD_NAME]; *roleSourceElement = roleObject[ROLE_SOURCE_FIELD_NAME]; *canDelegateElement = roleObject[ROLE_CAN_DELEGATE_FIELD_NAME]; *hasRoleElement = roleObject[ROLE_HAS_ROLE_FIELD_NAME]; if (roleNameElement->type() != String || makeStringDataFromBSONElement(*roleNameElement).empty()) { return Status(ErrorCodes::UnsupportedFormat, "Role names must be non-empty strings"); } if (roleSourceElement->type() != String || makeStringDataFromBSONElement(*roleSourceElement).empty()) { return Status(ErrorCodes::UnsupportedFormat, "Role db must be non-empty strings"); } if (!canDelegateElement->eoo() && canDelegateElement->type() != Bool) { return Status(ErrorCodes::UnsupportedFormat, "'canDelegate' field must be a boolean if provided"); } if (!hasRoleElement->eoo() && hasRoleElement->type() != Bool) { return Status(ErrorCodes::UnsupportedFormat, "'hasRole' field must be a boolean if provided"); } return Status::OK(); }
Status V2PrivilegeDocumentParser::initializeUserRolesFromPrivilegeDocument( User* user, const BSONObj& privDoc, const StringData&) const { BSONElement rolesElement = privDoc[ROLES_FIELD_NAME]; if (rolesElement.type() != Array) { return Status(ErrorCodes::UnsupportedFormat, "User document needs 'roles' field to be an array"); } 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(); BSONElement roleNameElement = roleObject[ROLE_NAME_FIELD_NAME]; BSONElement roleSourceElement = roleObject[ROLE_SOURCE_FIELD_NAME]; if (roleNameElement.type() != String || makeStringDataFromBSONElement(roleNameElement).empty()) { return Status(ErrorCodes::UnsupportedFormat, "Role names must be non-empty strings"); } if (roleSourceElement.type() != String || makeStringDataFromBSONElement(roleSourceElement).empty()) { return Status(ErrorCodes::UnsupportedFormat, "Role source must be non-empty strings"); } user->addRole(RoleName(roleNameElement.String(), roleSourceElement.String())); } return Status::OK(); }
Status V2PrivilegeDocumentParser::checkValidRoleObject( const BSONObj& roleObject) const { BSONElement roleNameElement = roleObject[ROLE_NAME_FIELD_NAME]; BSONElement roleSourceElement = roleObject[ROLE_SOURCE_FIELD_NAME]; BSONElement canDelegateElement = roleObject[ROLE_CAN_DELEGATE_FIELD_NAME]; BSONElement hasRoleElement = roleObject[ROLE_HAS_ROLE_FIELD_NAME]; if (roleNameElement.type() != String || makeStringDataFromBSONElement(roleNameElement).empty()) { return Status(ErrorCodes::UnsupportedFormat, "Role names must be non-empty strings"); } if (roleSourceElement.type() != String || makeStringDataFromBSONElement(roleSourceElement).empty()) { return Status(ErrorCodes::UnsupportedFormat, "Role source must be non-empty strings"); } if (canDelegateElement.type() != Bool) { return Status(ErrorCodes::UnsupportedFormat, "Entries in 'roles' array need a 'canDelegate' boolean field"); } if (hasRoleElement.type() != Bool) { return Status(ErrorCodes::UnsupportedFormat, "Entries in 'roles' array need a 'hasRole' boolean field"); } if (!hasRoleElement.Bool() && !canDelegateElement.Bool()) { return Status(ErrorCodes::UnsupportedFormat, "At least one of 'canDelegate' and 'hasRole' must be true for " "every role in the 'roles' array"); } return Status::OK(); }
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(); }
static Status _extractRoleDocumentElements( const BSONObj& roleObject, bool hasPossessionBools, BSONElement* roleNameElement, BSONElement* roleSourceElement, BSONElement* canDelegateElement, BSONElement* hasRoleElement) { *roleNameElement = roleObject[ROLE_NAME_FIELD_NAME]; *roleSourceElement = roleObject[ROLE_SOURCE_FIELD_NAME]; *canDelegateElement = roleObject[ROLE_CAN_DELEGATE_FIELD_NAME]; *hasRoleElement = roleObject[ROLE_HAS_ROLE_FIELD_NAME]; if (roleNameElement->type() != String || makeStringDataFromBSONElement(*roleNameElement).empty()) { return Status(ErrorCodes::UnsupportedFormat, "Role names must be non-empty strings"); } if (roleSourceElement->type() != String || makeStringDataFromBSONElement(*roleSourceElement).empty()) { return Status(ErrorCodes::UnsupportedFormat, "Role db must be non-empty strings"); } if (hasPossessionBools) { if (canDelegateElement->type() != Bool) { return Status(ErrorCodes::UnsupportedFormat, "Entries in 'roles' array need a 'canDelegate' boolean field"); } if (hasRoleElement->type() != Bool) { return Status(ErrorCodes::UnsupportedFormat, "Entries in 'roles' array need a 'hasRole' boolean field"); } if (!hasRoleElement->Bool() && !canDelegateElement->Bool()) { return Status(ErrorCodes::UnsupportedFormat, "At least one of 'canDelegate' and 'hasRole' must be true for " "every role in the 'roles' array"); } } else { if (canDelegateElement->type() != EOO) { return Status(ErrorCodes::UnsupportedFormat, "Invalid field 'canDelegate' found in role object"); } if (hasRoleElement->type() != EOO) { return Status(ErrorCodes::UnsupportedFormat, "Invalid field 'hasRole' found in role object"); } } return Status::OK(); }
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); } BSONObj roleObj = (*iter).Obj(); BSONElement nameElement = roleObj[ROLE_NAME_FIELD_NAME]; BSONElement sourceElement = roleObj[ROLE_SOURCE_FIELD_NAME]; BSONElement canDelegateElement = roleObj[ROLE_CAN_DELEGATE_FIELD_NAME]; BSONElement hasRoleElement = roleObj[ROLE_HAS_ROLE_FIELD_NAME]; if (nameElement.type() != String || makeStringDataFromBSONElement(nameElement).empty()) { return _badValue("Entries in 'roles' array need 'name' field to be a non-empty " "string", 0); } if (sourceElement.type() != String || makeStringDataFromBSONElement(sourceElement).empty()) { return _badValue("Entries in 'roles' array need 'source' field to be a non-empty " "string", 0); } if (canDelegateElement.type() != Bool) { return _badValue("Entries in 'roles' array need a 'canDelegate' boolean field", 0); } if (hasRoleElement.type() != Bool) { return _badValue("Entries in 'roles' array need a 'canDelegate' boolean field", 0); } if (!canDelegateElement.Bool() && !hasRoleElement.Bool()) { return _badValue("At least one of 'canDelegate' and 'hasRole' must be true for " "every role in the 'roles' array", 0); } } return Status::OK(); }
static Status _checkRolesArray(const BSONElement& rolesElement) { if (rolesElement.type() != Array) { return _badValue("Role fields must be an array when present in system.users entries", 0); } for (BSONObjIterator iter(rolesElement.embeddedObject()); iter.more(); iter.next()) { BSONElement element = *iter; if (element.type() != String || makeStringDataFromBSONElement(element).empty()) { return _badValue("Roles must be non-empty strings.", 0); } } return Status::OK(); }
Status _checkV2RolesArray(const BSONElement& rolesElement) { StringData fieldName = rolesElement.fieldNameStringData(); if (rolesElement.eoo()) { return _badValue(mongoutils::str::stream() << "User document needs '" << fieldName << "' field to be provided", 0); } if (rolesElement.type() != Array) { return _badValue(mongoutils::str::stream() << fieldName << " field must be an array", 0); } for (BSONObjIterator iter(rolesElement.embeddedObject()); iter.more(); iter.next()) { if ((*iter).type() != Object) { return _badValue(mongoutils::str::stream() << "Elements in '" << fieldName << "' array must objects.", 0); } BSONObj roleObj = (*iter).Obj(); BSONElement nameElement = roleObj[ROLE_NAME_FIELD_NAME]; BSONElement sourceElement = roleObj[ROLE_SOURCE_FIELD_NAME]; if (nameElement.type() != String || makeStringDataFromBSONElement(nameElement).empty()) { return _badValue(mongoutils::str::stream() << "Entries in '" << fieldName << "' array need 'name' field to be a non-empty string", 0); } if (sourceElement.type() != String || makeStringDataFromBSONElement(sourceElement).empty()) { return _badValue(mongoutils::str::stream() << "Entries in '" << fieldName << "' array need 'source' field to be a non-empty string", 0); } } return Status::OK(); }
Status V2UserDocumentParser::initializeUserCredentialsFromUserDocument( User* user, const BSONObj& privDoc) const { User::CredentialData credentials; std::string userSource = privDoc[AuthorizationManager::USER_SOURCE_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"); } BSONElement mongoCRCredentialElement = credentialsElement.Obj()[MONGODB_CR_CREDENTIAL_FIELD_NAME]; if (!mongoCRCredentialElement.eoo()) { if (mongoCRCredentialElement.type() != String || makeStringDataFromBSONElement(mongoCRCredentialElement).empty()) { return Status(ErrorCodes::UnsupportedFormat, "MONGODB-CR credentials must be non-empty strings"); } else { credentials.isExternal = false; credentials.password = mongoCRCredentialElement.String(); } } else { return Status(ErrorCodes::UnsupportedFormat, "User documents must provide credentials for MONGODB-CR" " authentication"); } } else if (userSource == "$external") { credentials.isExternal = true; } else { return Status(ErrorCodes::UnsupportedFormat, "Cannot extract credentials from user documents without a " "'credentials' field and with 'db' != \"$external\""); } user->setCredentials(credentials); return Status::OK(); }
Status AuthorizationManager::checkValidPrivilegeDocument(const StringData& dbname, const BSONObj& doc) { BSONElement userElement = doc[USER_NAME_FIELD_NAME]; BSONElement userSourceElement = doc[USER_SOURCE_FIELD_NAME]; BSONElement passwordElement = doc[PASSWORD_FIELD_NAME]; BSONElement rolesElement = doc[ROLES_FIELD_NAME]; BSONElement otherDBRolesElement = doc[OTHER_DB_ROLES_FIELD_NAME]; BSONElement readOnlyElement = doc[READONLY_FIELD_NAME]; // Validate the "user" element. if (userElement.type() != String) return _badValue("system.users entry needs 'user' field to be a string", 14051); if (makeStringDataFromBSONElement(userElement).empty()) return _badValue("system.users entry needs 'user' field to be non-empty", 14053); // Must set exactly one of "userSource" and "pwd" fields. if (userSourceElement.eoo() == passwordElement.eoo()) { return _badValue("system.users entry must have either a 'pwd' field or a 'userSource' " "field, but not both", 0); } if (!_doesSupportOldStylePrivileges && rolesElement.eoo()) { return _oldPrivilegeFormatNotSupported(); } // Cannot have both "roles" and "readOnly" elements. if (!rolesElement.eoo() && !readOnlyElement.eoo()) { return _badValue("system.users entry must not have both 'roles' and 'readOnly' fields", 0); } // Validate the "pwd" element, if present. if (!passwordElement.eoo()) { if (passwordElement.type() != String) return _badValue("system.users entry needs 'pwd' field to be a string", 14052); if (makeStringDataFromBSONElement(passwordElement).empty()) return _badValue("system.users entry needs 'pwd' field to be non-empty", 14054); } // Validate the "userSource" element, if present. if (!userSourceElement.eoo()) { if (userSourceElement.type() != String || makeStringDataFromBSONElement(userSourceElement).empty()) { return _badValue("system.users entry needs 'userSource' field to be a non-empty " "string, if present", 0); } if (userSourceElement.str() == dbname) { return _badValue(mongoutils::str::stream() << "'" << dbname << "' is not a valid value for the userSource field in " << dbname << ".system.users entries", 0); } if (rolesElement.eoo()) { return _badValue("system.users entry needs 'roles' field if 'userSource' field " "is present.", 0); } } // Validate the "roles" element. if (!rolesElement.eoo()) { Status status = _checkRolesArray(rolesElement); if (!status.isOK()) return status; } if (!otherDBRolesElement.eoo()) { if (dbname != ADMIN_DBNAME) { return _badValue("Only admin.system.users entries may contain 'otherDBRoles' " "fields", 0); } if (rolesElement.eoo()) { return _badValue("system.users entries with 'otherDBRoles' fields must contain " "'roles' fields", 0); } if (otherDBRolesElement.type() != Object) { return _badValue("'otherDBRoles' field must be an object when present in " "system.users entries", 0); } for (BSONObjIterator iter(otherDBRolesElement.embeddedObject()); iter.more(); iter.next()) { Status status = _checkRolesArray(*iter); if (!status.isOK()) return status; } } return Status::OK(); }