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();
    }
// static
StatusWith<RollbackFixUpInfo::IndexOpType> RollbackFixUpInfo::IndexDescription::parseOpType(
    const BSONObj& doc) {
    std::string opTypeStr;
    auto status = bsonExtractStringField(doc, "operationType"_sd, &opTypeStr);
    if (!status.isOK()) {
        return status;
    }
    if ("create" == opTypeStr) {
        return RollbackFixUpInfo::IndexOpType::kCreate;
    } else if ("drop" == opTypeStr) {
        return RollbackFixUpInfo::IndexOpType::kDrop;
    } else if ("updateTTL" == opTypeStr) {
        return RollbackFixUpInfo::IndexOpType::kUpdateTTL;
    }
    return Status(ErrorCodes::FailedToParse,
                  str::stream() << "Unrecognized RollbackFixUpInfo::IndexOpType: " << opTypeStr);
}
Status ReplSetHeartbeatArgs::initialize(const BSONObj& argsObj) {
    Status status =
        bsonCheckOnlyHasFields("ReplSetHeartbeatArgs", argsObj, kLegalHeartbeatFieldNames);
    if (!status.isOK())
        return status;

    status = bsonExtractBooleanFieldWithDefault(argsObj, kCheckEmptyFieldName, false, &_checkEmpty);
    if (!status.isOK())
        return status;
    _hasCheckEmpty = true;

    status = bsonExtractIntegerField(argsObj, kProtocolVersionFieldName, &_protocolVersion);
    if (!status.isOK())
        return status;
    _hasProtocolVersion = true;

    status = bsonExtractIntegerField(argsObj, kConfigVersionFieldName, &_configVersion);
    if (!status.isOK())
        return status;
    _hasConfigVersion = true;

    status = bsonExtractIntegerFieldWithDefault(argsObj, kSenderIdFieldName, -1, &_senderId);
    if (!status.isOK())
        return status;
    _hasSenderId = true;

    status = bsonExtractStringField(argsObj, kSetNameFieldName, &_setName);
    if (!status.isOK())
        return status;
    _hasSetName = true;

    std::string hostAndPortString;
    status =
        bsonExtractStringFieldWithDefault(argsObj, kSenderHostFieldName, "", &hostAndPortString);
    if (!status.isOK())
        return status;

    if (!hostAndPortString.empty()) {
        status = _senderHost.initialize(hostAndPortString);
        if (!status.isOK())
            return status;
        _hasSenderHost = true;
    }

    return Status::OK();
}
Ejemplo n.º 5
0
StatusWith<ChunkType> ChunkType::fromShardBSON(const BSONObj& source, const OID& epoch) {
    ChunkType chunk;

    {
        BSONElement minKey;
        Status minKeyStatus = extractObject(source, minShardID.name(), &minKey);
        if (!minKeyStatus.isOK()) {
            return minKeyStatus;
        }

        BSONElement maxKey;
        Status maxKeyStatus = extractObject(source, max.name(), &maxKey);
        if (!maxKeyStatus.isOK()) {
            return maxKeyStatus;
        }

        if (SimpleBSONObjComparator::kInstance.evaluate(minKey.Obj() >= maxKey.Obj())) {
            return {ErrorCodes::FailedToParse,
                    str::stream() << "min: " << minKey.Obj() << " should be less than max: "
                                  << maxKey.Obj()};
        }

        chunk._min = minKey.Obj().getOwned();
        chunk._max = maxKey.Obj().getOwned();
    }

    {
        std::string chunkShard;
        Status status = bsonExtractStringField(source, shard.name(), &chunkShard);
        if (!status.isOK())
            return status;
        chunk._shard = chunkShard;
    }

    {
        auto statusWithChunkVersion =
            ChunkVersion::parseFromBSONWithFieldAndSetEpoch(source, lastmod.name(), epoch);
        if (!statusWithChunkVersion.isOK()) {
            return statusWithChunkVersion.getStatus();
        }
        chunk._version = std::move(statusWithChunkVersion.getValue());
    }

    return chunk;
}
Ejemplo n.º 6
0
StatusWith<ReadPreferenceSetting> ReadPreferenceSetting::fromBSON(const BSONObj& readPrefObj) {
    std::string modeStr;
    auto modeExtractStatus = bsonExtractStringField(readPrefObj, kModeFieldName, &modeStr);
    if (!modeExtractStatus.isOK()) {
        return modeExtractStatus;
    }

    ReadPreference mode;
    auto swReadPrefMode = parseReadPreferenceMode(modeStr);
    if (!swReadPrefMode.isOK()) {
        return swReadPrefMode.getStatus();
    }
    mode = std::move(swReadPrefMode.getValue());

    TagSet tags;
    BSONElement tagsElem;
    auto tagExtractStatus =
        bsonExtractTypedField(readPrefObj, kTagsFieldName, mongo::Array, &tagsElem);
    if (tagExtractStatus.isOK()) {
        tags = TagSet{BSONArray(tagsElem.Obj().getOwned())};

        // In accordance with the read preference spec, passing the default wildcard tagset
        // '[{}]' is the same as not passing a TagSet at all. Furthermore, passing an empty
        // TagSet with a non-primary ReadPreference is equivalent to passing the wildcard
        // ReadPreference.
        if (tags == TagSet() || tags == TagSet::primaryOnly()) {
            tags = defaultTagSetForMode(mode);
        }

        // If we are using a user supplied TagSet, check that it is compatible with
        // the readPreference mode.
        else if (ReadPreference::PrimaryOnly == mode && (tags != TagSet::primaryOnly())) {
            return Status(ErrorCodes::BadValue,
                          "Only empty tags are allowed with primary read preference");
        }
    }

    else if (ErrorCodes::NoSuchKey == tagExtractStatus) {
        tags = defaultTagSetForMode(mode);
    } else {
        return tagExtractStatus;
    }

    return ReadPreferenceSetting(mode, tags);
}
Ejemplo n.º 7
0
Status ReadConcernArgs::initialize(const BSONElement& readConcernElem) {
    if (readConcernElem.eoo()) {
        return Status::OK();
    }

    dassert(readConcernElem.fieldNameStringData() == kReadConcernFieldName);

    if (!readConcernElem.isABSONObj()) {
        return Status(ErrorCodes::FailedToParse,
                      str::stream() << kReadConcernFieldName << " field should be an object");
    }

    BSONObj readConcernObj = readConcernElem.Obj();

    if (readConcernObj.hasField(kAfterOpTimeFieldName)) {
        OpTime opTime;
        auto opTimeStatus = bsonExtractOpTimeField(readConcernObj, kAfterOpTimeFieldName, &opTime);
        if (!opTimeStatus.isOK()) {
            return opTimeStatus;
        }
        _opTime = opTime;
    }

    std::string levelString;
    auto readCommittedStatus =
        bsonExtractStringField(readConcernObj, kLevelFieldName, &levelString);
    if (readCommittedStatus.isOK()) {
        if (levelString == kLocalReadConcernStr) {
            _level = ReadConcernLevel::kLocalReadConcern;
        } else if (levelString == kMajorityReadConcernStr) {
            _level = ReadConcernLevel::kMajorityReadConcern;
        } else {
            return Status(ErrorCodes::FailedToParse,
                          str::stream() << kReadConcernFieldName << '.' << kLevelFieldName
                                        << " must be either \"local\" or \"majority\"");
        }
    } else if (readCommittedStatus != ErrorCodes::NoSuchKey) {
        return readCommittedStatus;
    }

    return Status::OK();
}
    Status parseUserRoleManipulationCommand(const BSONObj& cmdObj,
                                            const StringData& cmdName,
                                            const std::string& dbname,
                                            AuthorizationManager* authzManager,
                                            UserName* parsedUserName,
                                            vector<RoleName>* parsedRoleNames,
                                            BSONObj* parsedWriteConcern) {
        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();
    }
StatusWith<ControlBalancerRequest> ControlBalancerRequest::_parse(const BSONObj& obj,
                                                                  StringData commandString) {
    if (obj.firstElementFieldName() != commandString) {
        return {ErrorCodes::InternalError,
                str::stream() << "Expected to find a " << commandString << " command, but found "
                              << obj};
    }

    std::string actionString;
    Status status = bsonExtractStringField(obj, commandString, &actionString);
    if (!status.isOK()) {
        return status;
    }

    if (actionString == kStartAction)
        return ControlBalancerRequest(kStart);
    if (actionString == kStopAction)
        return ControlBalancerRequest(kStop);

    return {ErrorCodes::IllegalOperation,
            str::stream() << actionString << " is not a valid balancer control action"};
}
Ejemplo n.º 10
0
    Status ReplSetRequestVotesArgs::initialize(const BSONObj& argsObj) {
        Status status = bsonCheckOnlyHasFields("ReplSetRequestVotes",
                                               argsObj,
                                               kLegalArgsFieldNames);
        if (!status.isOK())
            return status;

        status = bsonExtractIntegerField(argsObj, kTermFieldName, &_term);
        if (!status.isOK())
            return status;

        status = bsonExtractIntegerField(argsObj, kCandidateIdFieldName, &_candidateId);
        if (!status.isOK())
            return status;

        status = bsonExtractIntegerField(argsObj, kConfigVersionFieldName, &_cfgver);
        if (!status.isOK())
            return status;

        status = bsonExtractStringField(argsObj, kSetNameFieldName, &_setName);
        if (!status.isOK())
            return status;

        // extracting the lastCommittedOp is a bit of a process
        BSONObj lastCommittedOp = argsObj[kLastCommittedOpFieldName].Obj();
        Timestamp ts;
        status = bsonExtractTimestampField(lastCommittedOp, kOpTimeFieldName, &ts);
        if (!status.isOK())
            return status;
        long long term;
        status = bsonExtractIntegerField(lastCommittedOp, kTermFieldName, &term);
        if (!status.isOK())
            return status;
        _lastCommittedOp = OpTime(lastCommittedOp[kOpTimeFieldName].timestamp(),
                                  lastCommittedOp[kTermFieldName].Long());

        return Status::OK();
    }
Status ReplSetRequestVotesResponse::initialize(const BSONObj& argsObj) {
    Status status =
        bsonCheckOnlyHasFields("ReplSetRequestVotes", argsObj, kLegalResponseFieldNames);
    if (!status.isOK())
        return status;

    status = bsonExtractIntegerField(argsObj, kTermFieldName, &_term);
    if (!status.isOK())
        return status;

    status = bsonExtractBooleanField(argsObj, kVoteGrantedFieldName, &_voteGranted);
    if (!status.isOK())
        return status;

    status = bsonExtractStringField(argsObj, kReasonFieldName, &_reason);
    if (!status.isOK())
        return status;

    status = bsonExtractBooleanField(argsObj, kOkFieldName, &_ok);
    if (!status.isOK())
        return status;

    return Status::OK();
}
    /**
     * Validates that the roles array described by rolesElement is valid.
     * Also returns a new roles array (via the modifiedRolesArray output param) where any roles
     * from the input array that were listed as strings have been expanded to a full role document.
     * If includePossessionBools is true then the expanded roles documents will have "hasRole"
     * and "canDelegate" boolean fields (in addition to the "name" and "source" fields which are
     * there either way).
     */
    Status _validateAndModifyRolesArray(const BSONElement& rolesElement,
                                        const std::string& dbname,
                                        AuthorizationManager* authzManager,
                                        bool includePossessionBools,
                                        BSONArray* modifiedRolesArray) {
        BSONArrayBuilder rolesBuilder;

        for (BSONObjIterator it(rolesElement.Obj()); it.more(); it.next()) {
            BSONElement element = *it;
            if (element.type() == String) {
                RoleName roleName(element.String(), dbname);
                if (!authzManager->roleExists(roleName)) {
                    return Status(ErrorCodes::RoleNotFound,
                                  mongoutils::str::stream() << roleName.toString() <<
                                  " does not name an existing role");
                }

                if (includePossessionBools) {
                    rolesBuilder.append(BSON("name" << element.String() <<
                                             "source" << dbname <<
                                             "hasRole" << true <<
                                             "canDelegate" << false));
                } else {
                    rolesBuilder.append(BSON("name" << element.String() <<
                                             "source" << dbname));
                }
            } else if (element.type() == Object) {
                // Check that the role object is valid
                V2UserDocumentParser parser;
                BSONObj roleObj = element.Obj();
                Status status = parser.checkValidRoleObject(roleObj, includePossessionBools);
                if (!status.isOK()) {
                    return status;
                }

                // Check that the role actually exists
                std::string roleNameString;
                std::string roleSource;
                status = bsonExtractStringField(roleObj, "name", &roleNameString);
                if (!status.isOK()) {
                    return status;
                }
                status = bsonExtractStringField(roleObj, "source", &roleSource);
                if (!status.isOK()) {
                    return status;
                }

                RoleName roleName(roleNameString, roleSource);
                if (!authzManager->roleExists(roleName)) {
                    return Status(ErrorCodes::RoleNotFound,
                                  mongoutils::str::stream() << roleName.toString() <<
                                  " does not name an existing role");
                }

                rolesBuilder.append(element);
            } else {
                return Status(ErrorCodes::UnsupportedFormat,
                              "Values in 'roles' array must be sub-documents or strings");
            }
        }

        *modifiedRolesArray = rolesBuilder.arr();
        return Status::OK();
    }
Ejemplo n.º 13
0
StatusWith<ChangeLogType> ChangeLogType::fromBSON(const BSONObj& source) {
    ChangeLogType changeLog;

    {
        std::string changeLogId;
        Status status = bsonExtractStringField(source, changeId.name(), &changeLogId);
        if (!status.isOK())
            return status;
        changeLog._changeId = changeLogId;
    }

    {
        std::string changeLogServer;
        Status status = bsonExtractStringField(source, server.name(), &changeLogServer);
        if (!status.isOK())
            return status;
        changeLog._server = changeLogServer;
    }

    {
        std::string changeLogShard;
        Status status =
            bsonExtractStringFieldWithDefault(source, shard.name(), "", &changeLogShard);
        if (!status.isOK())
            return status;
        changeLog._shard = changeLogShard;
    }

    {
        std::string changeLogClientAddr;
        Status status = bsonExtractStringField(source, clientAddr.name(), &changeLogClientAddr);
        if (!status.isOK())
            return status;
        changeLog._clientAddr = changeLogClientAddr;
    }

    {
        BSONElement changeLogTimeElem;
        Status status = bsonExtractTypedField(source, time.name(), Date, &changeLogTimeElem);
        if (!status.isOK())
            return status;
        changeLog._time = changeLogTimeElem.date();
    }

    {
        std::string changeLogWhat;
        Status status = bsonExtractStringField(source, what.name(), &changeLogWhat);
        if (!status.isOK())
            return status;
        changeLog._what = changeLogWhat;
    }

    {
        std::string changeLogNs;
        Status status = bsonExtractStringFieldWithDefault(source, ns.name(), "", &changeLogNs);
        if (!status.isOK())
            return status;
        changeLog._ns = changeLogNs;
    }

    {
        BSONElement changeLogDetailsElem;
        Status status =
            bsonExtractTypedField(source, details.name(), Object, &changeLogDetailsElem);
        if (!status.isOK())
            return status;
        changeLog._details = changeLogDetailsElem.Obj().getOwned();
    }

    return changeLog;
}
Ejemplo n.º 14
0
        Status _parseAndValidateInput(BSONObj cmdObj, CreateUserArgs* parsedArgs) const {
            unordered_set<std::string> validFieldNames;
            validFieldNames.insert("createUser");
            validFieldNames.insert("user");
            validFieldNames.insert("pwd");
            validFieldNames.insert("userSource");
            validFieldNames.insert("roles");
            validFieldNames.insert("readOnly");
            validFieldNames.insert("otherDBRoles");


            // 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 createUser");
                }
            }

            Status status = bsonExtractStringField(cmdObj, "user", &parsedArgs->userName);
            if (!status.isOK()) {
                return status;
            }

            if (cmdObj.hasField("pwd")) {
                parsedArgs->hasPassword = true;
                status = bsonExtractStringField(cmdObj, "pwd", &parsedArgs->clearTextPassword);
                if (!status.isOK()) {
                    return status;
                }
            }


            if (cmdObj.hasField("userSource")) {
                parsedArgs->hasUserSource = true;
                status = bsonExtractStringField(cmdObj, "userSource", &parsedArgs->userSource);
                if (!status.isOK()) {
                    return status;
                }
            }

            if (cmdObj.hasField("readOnly")) {
                parsedArgs->hasReadOnly = true;
                status = bsonExtractBooleanField(cmdObj, "readOnly", &parsedArgs->readOnly);
                if (!status.isOK()) {
                    return status;
                }
            }

            if (cmdObj.hasField("extraData")) {
                parsedArgs->hasExtraData = true;
                BSONElement element;
                status = bsonExtractTypedField(cmdObj, "extraData", Object, &element);
                if (!status.isOK()) {
                    return status;
                }
                parsedArgs->extraData = element.Obj();
            }

            if (cmdObj.hasField("roles")) {
                parsedArgs->hasRoles = true;
                BSONElement element;
                status = bsonExtractTypedField(cmdObj, "roles", Array, &element);
                if (!status.isOK()) {
                    return status;
                }
                parsedArgs->roles = BSONArray(element.Obj());
            }

            if (cmdObj.hasField("otherDBRoles")) {
                parsedArgs->hasOtherDBRoles = true;
                BSONElement element;
                status = bsonExtractTypedField(cmdObj, "otherDBRoles", Object, &element);
                if (!status.isOK()) {
                    return status;
                }
                parsedArgs->otherDBRoles = element.Obj();
            }

            if (parsedArgs->hasPassword && parsedArgs->hasUserSource) {
                return Status(ErrorCodes::BadValue,
                              "User objects can't have both 'pwd' and 'userSource'");
            }
            if (!parsedArgs->hasPassword && !parsedArgs->hasUserSource) {
                return Status(ErrorCodes::BadValue,
                              "User objects must have one of 'pwd' and 'userSource'");
            }
            if (parsedArgs->hasRoles && parsedArgs->hasReadOnly) {
                return Status(ErrorCodes::BadValue,
                              "User objects can't have both 'roles' and 'readOnly'");
            }

            return Status::OK();
        }
Ejemplo n.º 15
0
StatusWith<TextMatchExpressionBase::TextParams>
ExtensionsCallback::extractTextMatchExpressionParams(BSONElement text) {
    TextMatchExpressionBase::TextParams params;
    if (text.type() != Object) {
        return {ErrorCodes::BadValue, "$text expects an object"};
    }
    BSONObj queryObj = text.Obj();

    //
    // Parse required fields.
    //

    Status queryStatus = bsonExtractStringField(queryObj, "$search", &params.query);
    if (!queryStatus.isOK()) {
        return queryStatus;
    }

    //
    // Parse optional fields.
    //

    int expectedFieldCount = 1;

    Status languageStatus = bsonExtractStringField(queryObj, "$language", &params.language);
    if (languageStatus == ErrorCodes::TypeMismatch) {
        return languageStatus;
    } else if (languageStatus == ErrorCodes::NoSuchKey) {
        params.language = std::string();
    } else {
        invariantOK(languageStatus);
        expectedFieldCount++;
    }

    Status caseSensitiveStatus =
        bsonExtractBooleanField(queryObj, "$caseSensitive", &params.caseSensitive);
    if (caseSensitiveStatus == ErrorCodes::TypeMismatch) {
        return caseSensitiveStatus;
    } else if (caseSensitiveStatus == ErrorCodes::NoSuchKey) {
        params.caseSensitive = TextMatchExpressionBase::kCaseSensitiveDefault;
    } else {
        invariantOK(caseSensitiveStatus);
        expectedFieldCount++;
    }

    Status diacriticSensitiveStatus =
        bsonExtractBooleanField(queryObj, "$diacriticSensitive", &params.diacriticSensitive);
    if (diacriticSensitiveStatus == ErrorCodes::TypeMismatch) {
        return diacriticSensitiveStatus;
    } else if (diacriticSensitiveStatus == ErrorCodes::NoSuchKey) {
        params.diacriticSensitive = TextMatchExpressionBase::kDiacriticSensitiveDefault;
    } else {
        invariantOK(diacriticSensitiveStatus);
        expectedFieldCount++;
    }

    if (queryObj.nFields() != expectedFieldCount) {
        return {ErrorCodes::BadValue, "extra fields in $text"};
    }

    return {std::move(params)};
}
Ejemplo n.º 16
0
StatusWith<ReadPreferenceSetting> ReadPreferenceSetting::fromInnerBSON(const BSONObj& readPrefObj) {
    std::string modeStr;
    auto modeExtractStatus = bsonExtractStringField(readPrefObj, kModeFieldName, &modeStr);
    if (!modeExtractStatus.isOK()) {
        return modeExtractStatus;
    }

    ReadPreference mode;
    auto swReadPrefMode = parseReadPreferenceMode(modeStr);
    if (!swReadPrefMode.isOK()) {
        return swReadPrefMode.getStatus();
    }
    mode = std::move(swReadPrefMode.getValue());

    TagSet tags;
    BSONElement tagsElem;
    auto tagExtractStatus =
        bsonExtractTypedField(readPrefObj, kTagsFieldName, mongo::Array, &tagsElem);
    if (tagExtractStatus.isOK()) {
        tags = TagSet{BSONArray(tagsElem.Obj().getOwned())};

        // In accordance with the read preference spec, passing the default wildcard tagset
        // '[{}]' is the same as not passing a TagSet at all. Furthermore, passing an empty
        // TagSet with a non-primary ReadPreference is equivalent to passing the wildcard
        // ReadPreference.
        if (tags == TagSet() || tags == TagSet::primaryOnly()) {
            tags = defaultTagSetForMode(mode);
        }

        // If we are using a user supplied TagSet, check that it is compatible with
        // the readPreference mode.
        else if (ReadPreference::PrimaryOnly == mode && (tags != TagSet::primaryOnly())) {
            return Status(ErrorCodes::BadValue,
                          "Only empty tags are allowed with primary read preference");
        }
    }

    else if (ErrorCodes::NoSuchKey == tagExtractStatus) {
        tags = defaultTagSetForMode(mode);
    } else {
        return tagExtractStatus;
    }

    long long maxStalenessSecondsValue;
    auto maxStalenessSecondsExtractStatus = bsonExtractIntegerFieldWithDefault(
        readPrefObj, kMaxStalenessSecondsFieldName, 0, &maxStalenessSecondsValue);

    if (!maxStalenessSecondsExtractStatus.isOK()) {
        return maxStalenessSecondsExtractStatus;
    }

    if (maxStalenessSecondsValue && maxStalenessSecondsValue < 0) {
        return Status(ErrorCodes::BadValue,
                      str::stream() << kMaxStalenessSecondsFieldName
                                    << " must be a non-negative integer");
    }

    if (maxStalenessSecondsValue && maxStalenessSecondsValue >= Seconds::max().count()) {
        return Status(ErrorCodes::BadValue,
                      str::stream() << kMaxStalenessSecondsFieldName << " value can not exceed "
                                    << Seconds::max().count());
    }

    if (maxStalenessSecondsValue && maxStalenessSecondsValue < kMinimalMaxStalenessValue.count()) {
        return Status(ErrorCodes::MaxStalenessOutOfRange,
                      str::stream() << kMaxStalenessSecondsFieldName
                                    << " value can not be less than "
                                    << kMinimalMaxStalenessValue.count());
    }

    if ((mode == ReadPreference::PrimaryOnly) && maxStalenessSecondsValue) {
        return Status(ErrorCodes::BadValue,
                      str::stream() << kMaxStalenessSecondsFieldName
                                    << " can not be set for the primary mode");
    }

    return ReadPreferenceSetting(mode, tags, Seconds(maxStalenessSecondsValue));
}
Ejemplo n.º 17
0
 Status extractMechanism(const BSONObj& cmdObj, std::string* mechanism) {
     return bsonExtractStringField(cmdObj, saslCommandMechanismFieldName, mechanism);
 }
StatusWith<MoveChunkRequest> MoveChunkRequest::createFromCommand(NamespaceString nss,
                                                                 const BSONObj& obj) {
    auto secondaryThrottleStatus = MigrationSecondaryThrottleOptions::createFromCommand(obj);
    if (!secondaryThrottleStatus.isOK()) {
        return secondaryThrottleStatus.getStatus();
    }

    auto rangeStatus = ChunkRange::fromBSON(obj);
    if (!rangeStatus.isOK()) {
        return rangeStatus.getStatus();
    }

    MoveChunkRequest request(std::move(nss),
                             std::move(rangeStatus.getValue()),
                             std::move(secondaryThrottleStatus.getValue()));

    {
        std::string shardStr;
        Status status = bsonExtractStringField(obj, kFromShardId, &shardStr);
        request._fromShardId = shardStr;
        if (!status.isOK()) {
            return status;
        }
    }

    {
        std::string shardStr;
        Status status = bsonExtractStringField(obj, kToShardId, &shardStr);
        request._toShardId = shardStr;
        if (!status.isOK()) {
            return status;
        }
    }

    {
        BSONElement epochElem;
        Status status = bsonExtractTypedField(obj, kEpoch, BSONType::jstOID, &epochElem);
        if (!status.isOK())
            return status;
        request._versionEpoch = epochElem.OID();
    }

    {
        Status status =
            bsonExtractBooleanFieldWithDefault(obj, kWaitForDelete, false, &request._waitForDelete);
        if (!status.isOK()) {
            return status;
        }
    }

    // Check for the deprecated name '_waitForDelete' if 'waitForDelete' was false.
    if (!request._waitForDelete) {
        Status status = bsonExtractBooleanFieldWithDefault(
            obj, kWaitForDeleteDeprecated, false, &request._waitForDelete);
        if (!status.isOK()) {
            return status;
        }
    }

    {
        long long maxChunkSizeBytes;
        Status status = bsonExtractIntegerField(obj, kMaxChunkSizeBytes, &maxChunkSizeBytes);
        if (!status.isOK()) {
            return status;
        }

        request._maxChunkSizeBytes = static_cast<int64_t>(maxChunkSizeBytes);
    }

    {  // TODO: delete this block in 3.8
        bool takeDistLock = false;
        Status status = bsonExtractBooleanField(obj, kTakeDistLock, &takeDistLock);
        if (status.isOK() && takeDistLock) {
            return Status{ErrorCodes::IncompatibleShardingConfigVersion,
                          str::stream()
                              << "Request received from an older, incompatible mongodb version"};
        }
    }

    return request;
}
Ejemplo n.º 19
0
StatusWith<MoveChunkRequest> MoveChunkRequest::createFromCommand(NamespaceString nss,
                                                                 const BSONObj& obj) {
    auto secondaryThrottleStatus = MigrationSecondaryThrottleOptions::createFromCommand(obj);
    if (!secondaryThrottleStatus.isOK()) {
        return secondaryThrottleStatus.getStatus();
    }

    auto rangeStatus = ChunkRange::fromBSON(obj);
    if (!rangeStatus.isOK()) {
        return rangeStatus.getStatus();
    }

    MoveChunkRequest request(std::move(nss),
                             std::move(rangeStatus.getValue()),
                             std::move(secondaryThrottleStatus.getValue()));

    {
        std::string configServerConnectionString;
        Status status = bsonExtractStringField(
            obj, kConfigServerConnectionString, &configServerConnectionString);
        if (!status.isOK()) {
            return status;
        }

        auto statusConfigServerCS = ConnectionString::parse(configServerConnectionString);
        if (!statusConfigServerCS.isOK()) {
            return statusConfigServerCS.getStatus();
        }

        request._configServerCS = std::move(statusConfigServerCS.getValue());
    }

    {
        std::string shardStr;
        Status status = bsonExtractStringField(obj, kFromShardId, &shardStr);
        request._fromShardId = shardStr;
        if (!status.isOK()) {
            return status;
        }
    }

    {
        std::string shardStr;
        Status status = bsonExtractStringField(obj, kToShardId, &shardStr);
        request._toShardId = shardStr;
        if (!status.isOK()) {
            return status;
        }
    }

    {
        Status status =
            bsonExtractBooleanFieldWithDefault(obj, kWaitForDelete, false, &request._waitForDelete);
        if (!status.isOK()) {
            return status;
        }
    }

    {
        long long maxChunkSizeBytes;
        Status status = bsonExtractIntegerField(obj, kMaxChunkSizeBytes, &maxChunkSizeBytes);
        if (!status.isOK()) {
            return status;
        }

        request._maxChunkSizeBytes = static_cast<int64_t>(maxChunkSizeBytes);
    }

    {
        Status status =
            bsonExtractBooleanFieldWithDefault(obj, kTakeDistLock, true, &request._takeDistLock);
        if (!status.isOK()) {
            return status;
        }
    }

    return request;
}
Ejemplo n.º 20
0
        // TODO: The bulk of the implementation of this will need to change once we're using the
        // new v2 authorization storage format.
        bool run(const string& dbname,
                 BSONObj& cmdObj,
                 int options,
                 string& errmsg,
                 BSONObjBuilder& result,
                 bool fromRepl) {
            std::string userName;
            std::string password;
            std::string userSource; // TODO: remove this.
            bool readOnly; // TODO: remove this.
            BSONElement extraData;
            BSONElement roles;

            if (cmdObj.hasField("pwd") && cmdObj.hasField("userSource")) {
                errmsg = "User objects can't have both 'pwd' and 'userSource'";
                return false;
            }

            if (!cmdObj.hasField("pwd") && !cmdObj.hasField("userSource")) {
                errmsg = "User objects must have one of 'pwd' and 'userSource'";
                return false;
            }

            if (cmdObj.hasField("roles") && cmdObj.hasField("readOnly")) {
                errmsg = "User objects can't have both 'roles' and 'readOnly'";
                return false;
            }

            Status status = bsonExtractStringField(cmdObj, "user", &userName);
            if (!status.isOK()) {
                addStatus(Status(ErrorCodes::UserModificationFailed,
                                 "\"user\" string not specified"),
                          result);
                return false;
            }

            status = bsonExtractStringFieldWithDefault(cmdObj, "pwd", "", &password);
            if (!status.isOK()) {
                addStatus(Status(ErrorCodes::UserModificationFailed,
                                 "Invalid \"pwd\" string"),
                          result);
                return false;
            }

            status = bsonExtractStringFieldWithDefault(cmdObj, "userSource", "", &userSource);
            if (!status.isOK()) {
                addStatus(Status(ErrorCodes::UserModificationFailed,
                                 "Invalid \"userSource\" string"),
                          result);
                return false;
            }

            status = bsonExtractBooleanFieldWithDefault(cmdObj, "readOnly", false, &readOnly);
            if (!status.isOK()) {
                addStatus(Status(ErrorCodes::UserModificationFailed,
                                 "Invalid \"readOnly\" boolean"),
                          result);
                return false;
            }

            if (cmdObj.hasField("extraData")) {
                status = bsonExtractField(cmdObj, "extraData", &extraData);
                if (!status.isOK()) {
                    addStatus(Status(ErrorCodes::UserModificationFailed,
                                     "Invalid \"extraData\" object"),
                              result);
                    return false;
                }
            }

            if (cmdObj.hasField("roles")) {
                status = bsonExtractField(cmdObj, "roles", &roles);
                if (!status.isOK()) {
                    addStatus(Status(ErrorCodes::UserModificationFailed,
                                     "Invalid \"roles\" array"),
                              result);
                    return false;
                }
            }

            BSONObjBuilder userObjBuilder;
            userObjBuilder.append("user", userName);
            if (cmdObj.hasField("pwd")) {
                // TODO: hash password once we're receiving plaintext passwords here.
                userObjBuilder.append("pwd", password);
            }

            if (cmdObj.hasField("userSource")) {
                userObjBuilder.append("userSource", userSource);
            }

            if (cmdObj.hasField("readOnly")) {
                userObjBuilder.append("readOnly", readOnly);
            }

            if (cmdObj.hasField("extraData")) {
                userObjBuilder.append("extraData", extraData);
            }

            if (cmdObj.hasField("roles")) {
                userObjBuilder.append(roles);
            }

            status = getGlobalAuthorizationManager()->insertPrivilegeDocument(dbname,
                                                                              userObjBuilder.obj());
            if (!status.isOK()) {
                addStatus(status, result);
                return false;
            }

            return true;
        }
Ejemplo n.º 21
0
Status ReadConcernArgs::initialize(const BSONElement& readConcernElem) {
    invariant(isEmpty());  // only legal to call on uninitialized object.

    if (readConcernElem.eoo()) {
        return Status::OK();
    }

    dassert(readConcernElem.fieldNameStringData() == kReadConcernFieldName);

    if (readConcernElem.type() != Object) {
        return Status(ErrorCodes::FailedToParse,
                      str::stream() << kReadConcernFieldName << " field should be an object");
    }

    BSONObj readConcernObj = readConcernElem.Obj();
    for (auto&& field : readConcernObj) {
        auto fieldName = field.fieldNameStringData();
        if (fieldName == kAfterOpTimeFieldName) {
            OpTime opTime;
            // TODO pass field in rather than scanning again.
            auto opTimeStatus =
                bsonExtractOpTimeField(readConcernObj, kAfterOpTimeFieldName, &opTime);
            if (!opTimeStatus.isOK()) {
                return opTimeStatus;
            }
            _opTime = opTime;
        } else if (fieldName == kAfterClusterTimeFieldName) {
            Timestamp afterClusterTime;
            auto afterClusterTimeStatus = bsonExtractTimestampField(
                readConcernObj, kAfterClusterTimeFieldName, &afterClusterTime);
            if (!afterClusterTimeStatus.isOK()) {
                return afterClusterTimeStatus;
            }
            _afterClusterTime = LogicalTime(afterClusterTime);
        } else if (fieldName == kAtClusterTimeFieldName) {
            Timestamp atClusterTime;
            auto atClusterTimeStatus =
                bsonExtractTimestampField(readConcernObj, kAtClusterTimeFieldName, &atClusterTime);
            if (!atClusterTimeStatus.isOK()) {
                return atClusterTimeStatus;
            }
            _atClusterTime = LogicalTime(atClusterTime);
        } else if (fieldName == kLevelFieldName) {
            std::string levelString;
            // TODO pass field in rather than scanning again.
            auto readCommittedStatus =
                bsonExtractStringField(readConcernObj, kLevelFieldName, &levelString);

            if (!readCommittedStatus.isOK()) {
                return readCommittedStatus;
            }

            if (levelString == kLocalReadConcernStr) {
                _level = ReadConcernLevel::kLocalReadConcern;
            } else if (levelString == kMajorityReadConcernStr) {
                _level = ReadConcernLevel::kMajorityReadConcern;
            } else if (levelString == kLinearizableReadConcernStr) {
                _level = ReadConcernLevel::kLinearizableReadConcern;
            } else if (levelString == kAvailableReadConcernStr) {
                _level = ReadConcernLevel::kAvailableReadConcern;
            } else if (levelString == kSnapshotReadConcernStr) {
                _level = ReadConcernLevel::kSnapshotReadConcern;
            } else {
                return Status(ErrorCodes::FailedToParse,
                              str::stream() << kReadConcernFieldName << '.' << kLevelFieldName
                                            << " must be either 'local', 'majority', "
                                               "'linearizable', 'available', or 'snapshot'");
            }
            _originalLevel = _level;
        } else {
            return Status(ErrorCodes::InvalidOptions,
                          str::stream() << "Unrecognized option in " << kReadConcernFieldName
                                        << ": "
                                        << fieldName);
        }
    }

    if (_afterClusterTime && _opTime) {
        return Status(ErrorCodes::InvalidOptions,
                      str::stream() << "Can not specify both " << kAfterClusterTimeFieldName
                                    << " and "
                                    << kAfterOpTimeFieldName);
    }

    if (_afterClusterTime && _atClusterTime) {
        return Status(ErrorCodes::InvalidOptions,
                      str::stream() << "Can not specify both " << kAfterClusterTimeFieldName
                                    << " and "
                                    << kAtClusterTimeFieldName);
    }

    // Note: 'available' should not be used with after cluster time, as cluster time can wait for
    // replication whereas the premise of 'available' is to avoid waiting. 'linearizable' should not
    // be used with after cluster time, since linearizable reads are inherently causally consistent.
    if (_afterClusterTime && getLevel() != ReadConcernLevel::kMajorityReadConcern &&
        getLevel() != ReadConcernLevel::kLocalReadConcern &&
        getLevel() != ReadConcernLevel::kSnapshotReadConcern) {
        return Status(ErrorCodes::InvalidOptions,
                      str::stream() << kAfterClusterTimeFieldName << " field can be set only if "
                                    << kLevelFieldName
                                    << " is equal to "
                                    << kMajorityReadConcernStr
                                    << ", "
                                    << kLocalReadConcernStr
                                    << ", or "
                                    << kSnapshotReadConcernStr);
    }

    if (_opTime && getLevel() == ReadConcernLevel::kSnapshotReadConcern) {
        return Status(ErrorCodes::InvalidOptions,
                      str::stream() << kAfterOpTimeFieldName << " field cannot be set if "
                                    << kLevelFieldName
                                    << " is equal to "
                                    << kSnapshotReadConcernStr);
    }

    if (_atClusterTime && getLevel() != ReadConcernLevel::kSnapshotReadConcern) {
        return Status(ErrorCodes::InvalidOptions,
                      str::stream() << kAtClusterTimeFieldName << " field can be set only if "
                                    << kLevelFieldName
                                    << " is equal to "
                                    << kSnapshotReadConcernStr);
    }

    if (_afterClusterTime && _afterClusterTime == LogicalTime::kUninitialized) {
        return Status(ErrorCodes::InvalidOptions,
                      str::stream() << kAfterClusterTimeFieldName << " cannot be a null timestamp");
    }

    if (_atClusterTime && _atClusterTime == LogicalTime::kUninitialized) {
        return Status(ErrorCodes::InvalidOptions,
                      str::stream() << kAtClusterTimeFieldName << " cannot be a null timestamp");
    }

    return Status::OK();
}
Ejemplo n.º 22
0
StatusWith<MoveChunkRequest> MoveChunkRequest::createFromCommand(NamespaceString nss,
                                                                 const BSONObj& obj) {
    auto secondaryThrottleStatus = MigrationSecondaryThrottleOptions::createFromCommand(obj);
    if (!secondaryThrottleStatus.isOK()) {
        return secondaryThrottleStatus.getStatus();
    }

    MoveChunkRequest request(std::move(nss), std::move(secondaryThrottleStatus.getValue()));

    {
        std::string configServerConnectionString;
        Status status = bsonExtractStringField(
            obj, kConfigServerConnectionString, &configServerConnectionString);
        if (!status.isOK()) {
            return status;
        }

        auto statusConfigServerCS = ConnectionString::parse(configServerConnectionString);
        if (!statusConfigServerCS.isOK()) {
            return statusConfigServerCS.getStatus();
        }

        request._configServerCS = std::move(statusConfigServerCS.getValue());
    }

    {
        Status status = bsonExtractStringField(obj, kFromShardId, &request._fromShardId);
        if (!status.isOK()) {
            return status;
        }
    }

    {
        Status status = bsonExtractStringField(obj, kToShardId, &request._toShardId);
        if (!status.isOK()) {
            return status;
        }
    }

    {
        BSONElement elem;
        Status status = bsonExtractTypedField(obj, kChunkMinKey, BSONType::Object, &elem);
        if (!status.isOK()) {
            return status;
        }

        request._minKey = elem.Obj().getOwned();

        if (request._minKey.isEmpty()) {
            return Status(ErrorCodes::UnsupportedFormat, "The chunk min key cannot be empty");
        }
    }

    {
        BSONElement elem;
        Status status = bsonExtractTypedField(obj, kChunkMaxKey, BSONType::Object, &elem);
        if (!status.isOK()) {
            return status;
        }

        request._maxKey = elem.Obj().getOwned();

        if (request._maxKey.isEmpty()) {
            return Status(ErrorCodes::UnsupportedFormat, "The chunk max key cannot be empty");
        }
    }

    {
        Status status =
            bsonExtractBooleanFieldWithDefault(obj, kWaitForDelete, false, &request._waitForDelete);
        if (!status.isOK()) {
            return status;
        }
    }

    {
        long long maxChunkSizeBytes;
        Status status = bsonExtractIntegerField(obj, kMaxChunkSizeBytes, &maxChunkSizeBytes);
        if (!status.isOK()) {
            return status;
        }

        request._maxChunkSizeBytes = static_cast<int64_t>(maxChunkSizeBytes);
    }

    return request;
}
    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();
    }
Ejemplo n.º 24
0
StatusWith<SetShardVersionRequest> SetShardVersionRequest::parseFromBSON(const BSONObj& cmdObj) {
    SetShardVersionRequest request;

    {
        std::string configServer;
        Status status = bsonExtractStringField(cmdObj, kConfigServer, &configServer);
        if (!status.isOK())
            return status;

        auto configServerStatus = ConnectionString::parse(configServer);
        if (!configServerStatus.isOK())
            return configServerStatus.getStatus();

        request._configServer = std::move(configServerStatus.getValue());
    }

    {
        Status status = bsonExtractStringField(cmdObj, kShardName, &request._shardName);
        if (!status.isOK())
            return status;
    }

    {
        std::string shardCS;
        Status status = bsonExtractStringField(cmdObj, kShardConnectionString, &shardCS);
        if (!status.isOK())
            return status;

        auto shardCSStatus = ConnectionString::parse(shardCS);
        if (!shardCSStatus.isOK())
            return shardCSStatus.getStatus();

        request._shardCS = std::move(shardCSStatus.getValue());
    }

    {
        Status status = bsonExtractBooleanFieldWithDefault(cmdObj, kInit, false, &request._init);
        if (!status.isOK())
            return status;
    }

    {
        Status status = bsonExtractBooleanFieldWithDefault(
            cmdObj, kAuthoritative, false, &request._isAuthoritative);
        if (!status.isOK())
            return status;
    }

    {
        Status status = bsonExtractBooleanFieldWithDefault(
            cmdObj, kNoConnectionVersioning, false, &request._noConnectionVersioning);
        if (!status.isOK())
            return status;
    }

    if (request.isInit()) {
        return request;
    }

    // Only initialize the version information if this is not an "init" request

    {
        std::string ns;
        Status status = bsonExtractStringField(cmdObj, kCmdName, &ns);
        if (!status.isOK())
            return status;

        NamespaceString nss(ns);

        if (!nss.isValid()) {
            return {ErrorCodes::InvalidNamespace,
                    str::stream() << ns << " is not a valid namespace"};
        }

        request._nss = std::move(nss);
    }

    {
        auto versionStatus = ChunkVersionAndOpTime::parseFromBSONForSetShardVersion(cmdObj);
        if (!versionStatus.isOK())
            return versionStatus.getStatus();

        request._version = versionStatus.getValue();
    }

    return request;
}
    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();
    }
Ejemplo n.º 26
0
    Status MemberConfig::initialize(const BSONObj& mcfg, ReplicaSetTagConfig* tagConfig) {
        Status status = bsonCheckOnlyHasFields(
            "replica set member configuration", mcfg, kLegalMemberConfigFieldNames);
        if (!status.isOK())
            return status;

        //
        // Parse _id field.
        //
        BSONElement idElement = mcfg[kIdFieldName];
        if (idElement.eoo()) {
            return Status(ErrorCodes::NoSuchKey, str::stream() << kIdFieldName <<
                          " field is missing");
        }
        if (!idElement.isNumber()) {
            return Status(ErrorCodes::TypeMismatch, str::stream() << kIdFieldName <<
                          " field has non-numeric type " << typeName(idElement.type()));
        }
        _id = idElement.numberInt();

        //
        // Parse h field.
        //
        std::string hostAndPortString;
        status = bsonExtractStringField(mcfg, kHostFieldName, &hostAndPortString);
        if (!status.isOK())
            return status;
        boost::trim(hostAndPortString);
        status = _host.initialize(hostAndPortString);
        if (!status.isOK())
            return status;
        if (!_host.hasPort()) {
            // make port explicit even if default.
            _host = HostAndPort(_host.host(), _host.port());
        }

        //
        // Parse votes field.
        //
        BSONElement votesElement = mcfg[kVotesFieldName];
        int votes;
        if (votesElement.eoo()) {
            votes = kVotesFieldDefault;
        }
        else if (votesElement.isNumber()) {
            votes = votesElement.numberInt();
        }
        else {
            return Status(ErrorCodes::TypeMismatch, str::stream() << kVotesFieldName <<
                          " field value has non-numeric type " <<
                          typeName(votesElement.type()));
        }
        if (votes != 0 && votes != 1) {
            return Status(ErrorCodes::BadValue, str::stream() << kVotesFieldName <<
                          " field value is " << votesElement.numberInt() << " but must be 0 or 1");
        }
        _isVoter = bool(votes);

        //
        // Parse priority field.
        //
        BSONElement priorityElement = mcfg[kPriorityFieldName];
        if (priorityElement.eoo()) {
            _priority = kPriorityFieldDefault;
        }
        else if (priorityElement.isNumber()) {
            _priority = priorityElement.numberDouble();
        }
        else {
            return Status(ErrorCodes::TypeMismatch, str::stream() << kPriorityFieldName <<
                          " field has non-numeric type " << typeName(priorityElement.type()));
        }

        //
        // Parse arbiterOnly field.
        //
        status = bsonExtractBooleanFieldWithDefault(mcfg,
                                                    kArbiterOnlyFieldName,
                                                    kArbiterOnlyFieldDefault,
                                                    &_arbiterOnly);
        if (!status.isOK())
            return status;

        //
        // Parse slaveDelay field.
        //
        BSONElement slaveDelayElement = mcfg[kSlaveDelayFieldName];
        if (slaveDelayElement.eoo()) {
            _slaveDelay = kSlaveDelayFieldDefault;
        }
        else if (slaveDelayElement.isNumber()) {
            _slaveDelay = Seconds(slaveDelayElement.numberInt());
        }
        else {
            return Status(ErrorCodes::TypeMismatch, str::stream() << kSlaveDelayFieldName <<
                          " field value has non-numeric type " <<
                          typeName(slaveDelayElement.type()));
        }

        //
        // Parse hidden field.
        //
        status = bsonExtractBooleanFieldWithDefault(mcfg,
                                                    kHiddenFieldName,
                                                    kHiddenFieldDefault,
                                                    &_hidden);
        if (!status.isOK())
            return status;

        //
        // Parse buildIndexes field.
        //
        status = bsonExtractBooleanFieldWithDefault(mcfg,
                                                    kBuildIndexesFieldName,
                                                    kBuildIndexesFieldDefault,
                                                    &_buildIndexes);
        if (!status.isOK())
            return status;

        //
        // Parse "tags" field.
        //
        _tags.clear();
        BSONElement tagsElement;
        status = bsonExtractTypedField(mcfg, kTagsFieldName, Object, &tagsElement);
        if (status.isOK()) {
            for (BSONObj::iterator tagIter(tagsElement.Obj()); tagIter.more();) {
                const BSONElement& tag = tagIter.next();
                if (tag.type() != String) {
                    return Status(ErrorCodes::TypeMismatch, str::stream() << "tags." <<
                                  tag.fieldName() << " field has non-string value of type " <<
                                  typeName(tag.type()));
                }
                _tags.push_back(tagConfig->makeTag(tag.fieldNameStringData(),
                                                   tag.valueStringData()));
            }
        }
        else if (ErrorCodes::NoSuchKey != status) {
            return status;
        }

        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();
    }
Ejemplo n.º 28
0
StatusWith<StartChunkCloneRequest> StartChunkCloneRequest::createFromCommand(NamespaceString nss,
                                                                             const BSONObj& obj) {
    auto secondaryThrottleStatus = MigrationSecondaryThrottleOptions::createFromCommand(obj);
    if (!secondaryThrottleStatus.isOK()) {
        return secondaryThrottleStatus.getStatus();
    }

    auto sessionIdStatus = MigrationSessionId::extractFromBSON(obj);
    if (!sessionIdStatus.isOK()) {
        return sessionIdStatus.getStatus();
    }

    StartChunkCloneRequest request(std::move(nss),
                                   std::move(sessionIdStatus.getValue()),
                                   std::move(secondaryThrottleStatus.getValue()));

    {
        std::string configServerConnectionString;
        Status status = bsonExtractStringField(
            obj, kConfigServerConnectionString, &configServerConnectionString);
        if (!status.isOK()) {
            return status;
        }

        auto statusConfigServerCS = ConnectionString::parse(configServerConnectionString);
        if (!statusConfigServerCS.isOK()) {
            return statusConfigServerCS.getStatus();
        }

        request._configServerCS = std::move(statusConfigServerCS.getValue());
    }

    {
        std::string fromShardConnectionString;
        Status status =
            bsonExtractStringField(obj, kFromShardConnectionString, &fromShardConnectionString);
        if (!status.isOK()) {
            return status;
        }

        auto fromShardConnectionStringStatus = ConnectionString::parse(fromShardConnectionString);
        if (!fromShardConnectionStringStatus.isOK()) {
            return fromShardConnectionStringStatus.getStatus();
        }

        request._fromShardCS = std::move(fromShardConnectionStringStatus.getValue());
    }

    {
        std::string fromShard;
        Status status = bsonExtractStringField(obj, kFromShardId, &fromShard);
        request._fromShardId = fromShard;
        if (!status.isOK()) {
            return status;
        }
    }

    {
        std::string toShard;
        Status status = bsonExtractStringField(obj, kToShardId, &toShard);
        request._toShardId = toShard;
        if (!status.isOK()) {
            return status;
        }
    }

    {
        BSONElement elem;
        Status status = bsonExtractTypedField(obj, kChunkMinKey, BSONType::Object, &elem);
        if (!status.isOK()) {
            return status;
        }

        request._minKey = elem.Obj().getOwned();

        if (request._minKey.isEmpty()) {
            return Status(ErrorCodes::UnsupportedFormat, "The chunk min key cannot be empty");
        }
    }

    {
        BSONElement elem;
        Status status = bsonExtractTypedField(obj, kChunkMaxKey, BSONType::Object, &elem);
        if (!status.isOK()) {
            return status;
        }

        request._maxKey = elem.Obj().getOwned();

        if (request._maxKey.isEmpty()) {
            return Status(ErrorCodes::UnsupportedFormat, "The chunk max key cannot be empty");
        }
    }

    {
        BSONElement elem;
        Status status = bsonExtractTypedField(obj, kShardKeyPattern, BSONType::Object, &elem);
        if (!status.isOK()) {
            return status;
        }

        request._shardKeyPattern = elem.Obj().getOwned();

        if (request._shardKeyPattern.isEmpty()) {
            return Status(ErrorCodes::UnsupportedFormat, "The shard key pattern cannot be empty");
        }
    }

    return request;
}
Ejemplo n.º 29
0
StatusWith<ShardType> ShardType::fromBSON(const BSONObj& source) {
    ShardType shard;

    {
        std::string shardName;
        Status status = bsonExtractStringField(source, name.name(), &shardName);
        if (!status.isOK())
            return status;
        shard._name = shardName;
    }

    {
        std::string shardHost;
        Status status = bsonExtractStringField(source, host.name(), &shardHost);
        if (!status.isOK())
            return status;
        shard._host = shardHost;
    }

    {
        bool isShardDraining;
        Status status = bsonExtractBooleanField(source, draining.name(), &isShardDraining);
        if (status.isOK()) {
            shard._draining = isShardDraining;
        } else if (status == ErrorCodes::NoSuchKey) {
            // draining field can be mssing in which case it is presumed false
        } else {
            return status;
        }
    }

    {
        long long shardMaxSizeMB;
        // maxSizeMB == 0 means there's no limitation to space usage.
        Status status = bsonExtractIntegerField(source, maxSizeMB.name(), &shardMaxSizeMB);
        if (status.isOK()) {
            shard._maxSizeMB = shardMaxSizeMB;
        } else if (status == ErrorCodes::NoSuchKey) {
            // maxSizeMB field can be missing in which case it is presumed false
        } else {
            return status;
        }
    }

    if (source.hasField(tags.name())) {
        shard._tags = std::vector<std::string>();
        BSONElement tagsElement;
        Status status = bsonExtractTypedField(source, tags.name(), Array, &tagsElement);
        if (!status.isOK())
            return status;

        BSONObjIterator it(tagsElement.Obj());
        while (it.more()) {
            BSONElement tagElement = it.next();
            if (tagElement.type() != String) {
                return Status(ErrorCodes::TypeMismatch,
                              str::stream() << "Elements in \"" << tags.name()
                                            << "\" array must be strings but found "
                                            << typeName(tagElement.type()));
            }
            shard._tags->push_back(tagElement.String());
        }
    }

    return shard;
}
Ejemplo n.º 30
0
Status IsMasterResponse::initialize(const BSONObj& doc) {
    Status status = bsonExtractBooleanField(doc, kIsMasterFieldName, &_isMaster);
    if (!status.isOK()) {
        return status;
    }
    _isMasterSet = true;
    status = bsonExtractBooleanField(doc, kSecondaryFieldName, &_secondary);
    if (!status.isOK()) {
        return status;
    }
    _isSecondarySet = true;
    if (doc.hasField(kInfoFieldName)) {
        if (_isMaster || _secondary || !doc.hasField(kIsReplicaSetFieldName) ||
            !doc[kIsReplicaSetFieldName].booleanSafe()) {
            return Status(ErrorCodes::FailedToParse,
                          str::stream() << "Expected presence of \"" << kInfoFieldName
                                        << "\" field to indicate no valid config loaded, but other "
                                           "fields weren't as we expected");
        }
        _configSet = false;
        return Status::OK();
    } else {
        if (doc.hasField(kIsReplicaSetFieldName)) {
            return Status(ErrorCodes::FailedToParse,
                          str::stream() << "Found \"" << kIsReplicaSetFieldName
                                        << "\" field which should indicate that no valid config "
                                           "is loaded, but we didn't also have an \""
                                        << kInfoFieldName << "\" field as we expected");
        }
    }

    status = bsonExtractStringField(doc, kSetNameFieldName, &_setName);
    if (!status.isOK()) {
        return status;
    }
    _setNameSet = true;
    status = bsonExtractIntegerField(doc, kSetVersionFieldName, &_setVersion);
    if (!status.isOK()) {
        return status;
    }
    _setVersionSet = true;

    if (doc.hasField(kHostsFieldName)) {
        BSONElement hostsElement;
        status = bsonExtractTypedField(doc, kHostsFieldName, Array, &hostsElement);
        if (!status.isOK()) {
            return status;
        }
        for (BSONObjIterator it(hostsElement.Obj()); it.more();) {
            BSONElement hostElement = it.next();
            if (hostElement.type() != String) {
                return Status(ErrorCodes::TypeMismatch,
                              str::stream() << "Elements in \"" << kHostsFieldName
                                            << "\" array of isMaster response must be of type "
                                            << typeName(String) << " but found type "
                                            << typeName(hostElement.type()));
            }
            _hosts.push_back(HostAndPort(hostElement.String()));
        }
        _hostsSet = true;
    }

    if (doc.hasField(kPassivesFieldName)) {
        BSONElement passivesElement;
        status = bsonExtractTypedField(doc, kPassivesFieldName, Array, &passivesElement);
        if (!status.isOK()) {
            return status;
        }
        for (BSONObjIterator it(passivesElement.Obj()); it.more();) {
            BSONElement passiveElement = it.next();
            if (passiveElement.type() != String) {
                return Status(ErrorCodes::TypeMismatch,
                              str::stream() << "Elements in \"" << kPassivesFieldName
                                            << "\" array of isMaster response must be of type "
                                            << typeName(String) << " but found type "
                                            << typeName(passiveElement.type()));
            }
            _passives.push_back(HostAndPort(passiveElement.String()));
        }
        _passivesSet = true;
    }

    if (doc.hasField(kArbitersFieldName)) {
        BSONElement arbitersElement;
        status = bsonExtractTypedField(doc, kArbitersFieldName, Array, &arbitersElement);
        if (!status.isOK()) {
            return status;
        }
        for (BSONObjIterator it(arbitersElement.Obj()); it.more();) {
            BSONElement arbiterElement = it.next();
            if (arbiterElement.type() != String) {
                return Status(ErrorCodes::TypeMismatch,
                              str::stream() << "Elements in \"" << kArbitersFieldName
                                            << "\" array of isMaster response must be of type "
                                            << typeName(String) << " but found type "
                                            << typeName(arbiterElement.type()));
            }
            _arbiters.push_back(HostAndPort(arbiterElement.String()));
        }
        _arbitersSet = true;
    }

    if (doc.hasField(kPrimaryFieldName)) {
        std::string primaryString;
        status = bsonExtractStringField(doc, kPrimaryFieldName, &primaryString);
        if (!status.isOK()) {
            return status;
        }
        _primary = HostAndPort(primaryString);
        _primarySet = true;
    }

    if (doc.hasField(kArbiterOnlyFieldName)) {
        status = bsonExtractBooleanField(doc, kArbiterOnlyFieldName, &_arbiterOnly);
        if (!status.isOK()) {
            return status;
        }
        _arbiterOnlySet = true;
    }

    if (doc.hasField(kPassiveFieldName)) {
        status = bsonExtractBooleanField(doc, kPassiveFieldName, &_passive);
        if (!status.isOK()) {
            return status;
        }
        _passiveSet = true;
    }

    if (doc.hasField(kHiddenFieldName)) {
        status = bsonExtractBooleanField(doc, kHiddenFieldName, &_hidden);
        if (!status.isOK()) {
            return status;
        }
        _hiddenSet = true;
    }

    if (doc.hasField(kBuildIndexesFieldName)) {
        status = bsonExtractBooleanField(doc, kBuildIndexesFieldName, &_buildIndexes);
        if (!status.isOK()) {
            return status;
        }
        _buildIndexesSet = true;
    }

    if (doc.hasField(kSlaveDelayFieldName)) {
        long long slaveDelaySecs;
        status = bsonExtractIntegerField(doc, kSlaveDelayFieldName, &slaveDelaySecs);
        if (!status.isOK()) {
            return status;
        }
        _slaveDelaySet = true;
        _slaveDelay = Seconds(slaveDelaySecs);
    }

    if (doc.hasField(kTagsFieldName)) {
        BSONElement tagsElement;
        status = bsonExtractTypedField(doc, kTagsFieldName, Object, &tagsElement);
        if (!status.isOK()) {
            return status;
        }
        for (BSONObjIterator it(tagsElement.Obj()); it.more();) {
            BSONElement tagElement = it.next();
            if (tagElement.type() != String) {
                return Status(ErrorCodes::TypeMismatch,
                              str::stream() << "Elements in \"" << kTagsFieldName
                                            << "\" obj "
                                               "of isMaster response must be of type "
                                            << typeName(String) << " but found type "
                                            << typeName(tagsElement.type()));
            }
            _tags[tagElement.fieldNameStringData().toString()] = tagElement.String();
        }
        _tagsSet = true;
    }

    if (doc.hasField(kElectionIdFieldName)) {
        BSONElement electionIdElem;
        status = bsonExtractTypedField(doc, kElectionIdFieldName, jstOID, &electionIdElem);
        if (!status.isOK()) {
            return status;
        }
        _electionId = electionIdElem.OID();
    }

    std::string meString;
    status = bsonExtractStringField(doc, kMeFieldName, &meString);
    if (!status.isOK()) {
        return status;
    }
    _me = HostAndPort(meString);
    _meSet = true;

    return Status::OK();
}