Esempio n. 1
0
    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();
    }
Esempio n. 2
0
    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();
    }
Esempio n. 5
0
    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();
    }
Esempio n. 7
0
 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();
 }
Esempio n. 8
0
    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();
    }
Esempio n. 9
0
    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();
    }
Esempio n. 10
0
    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();
    }