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. 2
0
Status V2UserDocumentParser::checkValidUserDocument(const BSONObj& doc) const {
    auto userIdElement = doc[AuthorizationManager::USERID_FIELD_NAME];
    auto userElement = doc[AuthorizationManager::USER_NAME_FIELD_NAME];
    auto userDBElement = doc[AuthorizationManager::USER_DB_FIELD_NAME];
    auto credentialsElement = doc[CREDENTIALS_FIELD_NAME];
    auto rolesElement = doc[ROLES_FIELD_NAME];

    // Validate the "userId" element.
    if (!userIdElement.eoo()) {
        if (!userIdElement.isBinData(BinDataType::newUUID)) {
            return _badValue("User document needs 'userId' field to be a UUID");
        }
    }

    // Validate the "user" element.
    if (userElement.type() != String)
        return _badValue("User document needs 'user' field to be a string");
    if (userElement.valueStringData().empty())
        return _badValue("User document needs 'user' field to be non-empty");

    // Validate the "db" element
    if (userDBElement.type() != String || userDBElement.valueStringData().empty()) {
        return _badValue("User document needs 'db' field to be a non-empty string");
    }
    StringData userDBStr = userDBElement.valueStringData();
    if (!NamespaceString::validDBName(userDBStr, NamespaceString::DollarInDbNameBehavior::Allow) &&
        userDBStr != "$external") {
        return _badValue(mongoutils::str::stream() << "'" << userDBStr
                                                   << "' is not a valid value for the db field.");
    }

    // Validate the "credentials" element
    if (credentialsElement.eoo()) {
        return _badValue("User document needs 'credentials' object");
    }
    if (credentialsElement.type() != Object) {
        return _badValue("User document needs 'credentials' field to be an object");
    }

    BSONObj credentialsObj = credentialsElement.Obj();
    if (credentialsObj.isEmpty()) {
        return _badValue("User document needs 'credentials' field to be a non-empty object");
    }
    if (userDBStr == "$external") {
        BSONElement externalElement = credentialsObj[MONGODB_EXTERNAL_CREDENTIAL_FIELD_NAME];
        if (externalElement.eoo() || externalElement.type() != Bool || !externalElement.Bool()) {
            return _badValue(
                "User documents for users defined on '$external' must have "
                "'credentials' field set to {external: true}");
        }
    } else {
        const auto validateScram = [&credentialsObj](const auto& fieldName) {
            auto scramElement = credentialsObj[fieldName];

            if (scramElement.eoo()) {
                return Status(ErrorCodes::NoSuchKey,
                              str::stream() << fieldName << " does not exist");
            }
            if (scramElement.type() != Object) {
                return _badValue(str::stream() << fieldName
                                               << " credential must be an object, if present");
            }
            return Status::OK();
        };

        const auto sha1status = validateScram(SCRAMSHA1_CREDENTIAL_FIELD_NAME);
        if (!sha1status.isOK() && (sha1status.code() != ErrorCodes::NoSuchKey)) {
            return sha1status;
        }
        const auto sha256status = validateScram(SCRAMSHA256_CREDENTIAL_FIELD_NAME);
        if (!sha256status.isOK() && (sha256status.code() != ErrorCodes::NoSuchKey)) {
            return sha256status;
        }

        if (!sha1status.isOK() && !sha256status.isOK()) {
            return _badValue(
                "User document must provide credentials for all "
                "non-external users");
        }
    }

    // Validate the "roles" element.
    Status status = _checkV2RolesArray(rolesElement);
    if (!status.isOK())
        return status;

    // Validate the "authenticationRestrictions" element.
    status = initializeAuthenticationRestrictionsFromUserDocument(doc, nullptr);
    if (!status.isOK()) {
        return status;
    }

    return Status::OK();
}
Esempio n. 3
0
    Status V2UserDocumentParser::checkValidUserDocument(const BSONObj& doc) const {
        BSONElement userElement = doc[AuthorizationManager::USER_NAME_FIELD_NAME];
        BSONElement userDBElement = doc[AuthorizationManager::USER_DB_FIELD_NAME];
        BSONElement credentialsElement = doc[CREDENTIALS_FIELD_NAME];
        BSONElement rolesElement = doc[ROLES_FIELD_NAME];

        // Validate the "user" element.
        if (userElement.type() != String)
            return _badValue("User document needs 'user' field to be a string", 0);
        if (userElement.valueStringData().empty())
            return _badValue("User document needs 'user' field to be non-empty", 0);

        // Validate the "db" element
        if (userDBElement.type() != String || userDBElement.valueStringData().empty()) {
            return _badValue("User document needs 'db' field to be a non-empty string", 0);
        }
        StringData userDBStr = userDBElement.valueStringData();
        if (!NamespaceString::validDBName(userDBStr) && userDBStr != "$external") {
            return _badValue(mongoutils::str::stream() << "'" << userDBStr <<
                                     "' is not a valid value for the db field.",
                             0);
        }

        // Validate the "credentials" element
        if (credentialsElement.eoo()) {
            return _badValue("User document needs 'credentials' object",
                    0);
        }
        if (credentialsElement.type() != Object) {
            return _badValue("User document needs 'credentials' field to be an object", 0);
        }

        BSONObj credentialsObj = credentialsElement.Obj();
        if (credentialsObj.isEmpty()) {
            return _badValue("User document needs 'credentials' field to be a non-empty object",
                             0);
        }
        if (userDBStr == "$external") {
            BSONElement externalElement = credentialsObj[MONGODB_EXTERNAL_CREDENTIAL_FIELD_NAME];
            if (externalElement.eoo() || externalElement.type() != Bool ||
                    !externalElement.Bool()) {
                return _badValue("User documents for users defined on '$external' must have "
                        "'credentials' field set to {external: true}", 0);
            }
        } 
        else {
            BSONElement scramElement = credentialsObj[SCRAM_CREDENTIAL_FIELD_NAME];
            BSONElement mongoCRElement = credentialsObj[MONGODB_CR_CREDENTIAL_FIELD_NAME];
            
            if (!mongoCRElement.eoo()) {
                if (mongoCRElement.type() != String || mongoCRElement.valueStringData().empty()) {
                    return _badValue("MONGODB-CR credential must to be a non-empty string"
                                     ", if present", 0);
                }
            }
            else if (!scramElement.eoo()) {
                if (scramElement.type() != Object) {
                    return _badValue("SCRAM credential must be an object, if present", 0);
                }
            }
            else {
                return _badValue("User document must provide credentials for all "
                        "non-external users", 0);
            }
        }

        // Validate the "roles" element.
        Status status = _checkV2RolesArray(rolesElement);
        if (!status.isOK())
            return status;

        return Status::OK();
    }