示例#1
0
    void Pipeline::addRequiredPrivileges(Command* commandTemplate,
                                         const string& db,
                                         BSONObj cmdObj,
                                         vector<Privilege>* out) {
        ResourcePattern inputResource(commandTemplate->parseResourcePattern(db, cmdObj));
        uassert(17138,
                mongoutils::str::stream() << "Invalid input resource, " << inputResource.toString(),
                inputResource.isExactNamespacePattern());

        out->push_back(Privilege(inputResource, ActionType::find));

        BSONObj pipeline = cmdObj.getObjectField("pipeline");
        BSONForEach(stageElem, pipeline) {
            BSONObj stage = stageElem.embeddedObjectUserCheck();
            if (str::equals(stage.firstElementFieldName(), "$out")) {
                NamespaceString outputNs(db, stage.firstElement().str());
                uassert(17139,
                        mongoutils::str::stream() << "Invalid $out target namespace, " <<
                        outputNs.ns(),
                        outputNs.isValid());

                ActionSet actions;
                actions.addAction(ActionType::remove);
                actions.addAction(ActionType::insert);
                if (shouldBypassDocumentValidationForCommand(cmdObj)) {
                    actions.addAction(ActionType::bypassDocumentValidation);
                }

                out->push_back(Privilege(ResourcePattern::forExactNamespace(outputNs), actions));
            }
        }
示例#2
0
Status checkAuthForCopydbCommand(ClientBasic* client,
                                 const std::string& dbname,
                                 const BSONObj& cmdObj) {
    bool fromSelf = StringData(cmdObj.getStringField("fromhost")).empty();
    StringData fromdb = cmdObj.getStringField("fromdb");
    StringData todb = cmdObj.getStringField("todb");

    // get system collections
    std::vector<std::string> legalClientSystemCollections;
    legalClientSystemCollections.push_back("system.js");
    if (fromdb == "admin") {
        legalClientSystemCollections.push_back("system.users");
        legalClientSystemCollections.push_back("system.roles");
        legalClientSystemCollections.push_back("system.version");
    } else if (fromdb == "local") {  // TODO(spencer): shouldn't be possible. See SERVER-11383
        legalClientSystemCollections.push_back("system.replset");
    }

    // Check authorization on destination db
    ActionSet actions;
    actions.addAction(ActionType::insert);
    actions.addAction(ActionType::createIndex);
    if (shouldBypassDocumentValidationForCommand(cmdObj)) {
        actions.addAction(ActionType::bypassDocumentValidation);
    }

    if (!AuthorizationSession::get(client)
             ->isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(todb), actions)) {
        return Status(ErrorCodes::Unauthorized, "Unauthorized");
    }

    actions.removeAllActions();
    actions.addAction(ActionType::insert);
    for (size_t i = 0; i < legalClientSystemCollections.size(); ++i) {
        if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnNamespace(
                NamespaceString(todb, legalClientSystemCollections[i]), actions)) {
            return Status(ErrorCodes::Unauthorized, "Unauthorized");
        }
    }

    if (fromSelf) {
        // If copying from self, also require privileges on source db
        actions.removeAllActions();
        actions.addAction(ActionType::find);
        if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource(
                ResourcePattern::forDatabaseName(fromdb), actions)) {
            return Status(ErrorCodes::Unauthorized, "Unauthorized");
        }
        for (size_t i = 0; i < legalClientSystemCollections.size(); ++i) {
            if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnNamespace(
                    NamespaceString(fromdb, legalClientSystemCollections[i]), actions)) {
                return Status(ErrorCodes::Unauthorized, "Unauthorized");
            }
        }
    }
    return Status::OK();
}
示例#3
0
Status Pipeline::checkAuthForCommand(ClientBasic* client,
                                     const std::string& db,
                                     const BSONObj& cmdObj) {
    NamespaceString inputNs(db, cmdObj.firstElement().str());
    auto inputResource = ResourcePattern::forExactNamespace(inputNs);
    uassert(17138,
            mongoutils::str::stream() << "Invalid input namespace, " << inputNs.ns(),
            inputNs.isValid());

    std::vector<Privilege> privileges;

    if (dps::extractElementAtPath(cmdObj, "pipeline.0.$indexStats")) {
        Privilege::addPrivilegeToPrivilegeVector(
            &privileges,
            Privilege(ResourcePattern::forAnyNormalResource(), ActionType::indexStats));
    } else if (dps::extractElementAtPath(cmdObj, "pipeline.0.$collStats")) {
        Privilege::addPrivilegeToPrivilegeVector(&privileges,
                Privilege(inputResource, ActionType::collStats));
    } else {
        // If no source requiring an alternative permission scheme is specified then default to
        // requiring find() privileges on the given namespace.
        Privilege::addPrivilegeToPrivilegeVector(&privileges,
                Privilege(inputResource, ActionType::find));
    }

    BSONObj pipeline = cmdObj.getObjectField("pipeline");
    BSONForEach(stageElem, pipeline) {
        BSONObj stage = stageElem.embeddedObjectUserCheck();
        StringData stageName = stage.firstElementFieldName();
        if (stageName == "$out" && stage.firstElementType() == String) {
            NamespaceString outputNs(db, stage.firstElement().str());
            uassert(17139,
                    mongoutils::str::stream() << "Invalid $out target namespace, " << outputNs.ns(),
                    outputNs.isValid());

            ActionSet actions;
            actions.addAction(ActionType::remove);
            actions.addAction(ActionType::insert);
            if (shouldBypassDocumentValidationForCommand(cmdObj)) {
                actions.addAction(ActionType::bypassDocumentValidation);
            }
            Privilege::addPrivilegeToPrivilegeVector(
                &privileges, Privilege(ResourcePattern::forExactNamespace(outputNs), actions));
        } else if (stageName == "$lookup" && stage.firstElementType() == Object) {
            NamespaceString fromNs(db, stage.firstElement()["from"].str());
            Privilege::addPrivilegeToPrivilegeVector(
                &privileges,
                Privilege(ResourcePattern::forExactNamespace(fromNs), ActionType::find));
        } else if (stageName == "$graphLookup" && stage.firstElementType() == Object) {
            NamespaceString fromNs(db, stage.firstElement()["from"].str());
            Privilege::addPrivilegeToPrivilegeVector(
                &privileges,
                Privilege(ResourcePattern::forExactNamespace(fromNs), ActionType::find));
        }
    }
示例#4
0
Status checkAuthForWriteCommand(AuthorizationSession* authzSession,
                                BatchedCommandRequest::BatchType cmdType,
                                const OpMsgRequest& request) {
    std::vector<Privilege> privileges;
    ActionSet actionsOnCommandNSS;

    if (shouldBypassDocumentValidationForCommand(request.body)) {
        actionsOnCommandNSS.addAction(ActionType::bypassDocumentValidation);
    }

    NamespaceString cmdNSS;
    if (cmdType == BatchedCommandRequest::BatchType_Insert) {
        auto op = Insert::parse(IDLParserErrorContext("insert"), request);
        cmdNSS = op.getNamespace();
        if (!op.getNamespace().isSystemDotIndexes()) {
            actionsOnCommandNSS.addAction(ActionType::insert);
        } else {
            // Special-case indexes until we have a command
            const auto swNssToIndex = getIndexedNss(op.getDocuments());
            if (!swNssToIndex.isOK()) {
                return swNssToIndex.getStatus();
            }

            const auto& nssToIndex = swNssToIndex.getValue();
            privileges.push_back(
                Privilege(ResourcePattern::forExactNamespace(nssToIndex), ActionType::createIndex));
        }
    } else if (cmdType == BatchedCommandRequest::BatchType_Update) {
        auto op = Update::parse(IDLParserErrorContext("update"), request);
        cmdNSS = op.getNamespace();
        actionsOnCommandNSS.addAction(ActionType::update);

        // Upsert also requires insert privs
        if (containsUpserts(op.getUpdates())) {
            actionsOnCommandNSS.addAction(ActionType::insert);
        }
    } else {
        fassert(17251, cmdType == BatchedCommandRequest::BatchType_Delete);
        auto op = Delete::parse(IDLParserErrorContext("delete"), request);
        cmdNSS = op.getNamespace();
        actionsOnCommandNSS.addAction(ActionType::remove);
    }

    if (!actionsOnCommandNSS.empty()) {
        privileges.emplace_back(ResourcePattern::forExactNamespace(cmdNSS), actionsOnCommandNSS);
    }

    if (authzSession->isAuthorizedForPrivileges(privileges))
        return Status::OK();

    return Status(ErrorCodes::Unauthorized, "unauthorized");
}
示例#5
0
Status checkAuthForApplyOpsCommand(OperationContext* txn,
                                   const std::string& dbname,
                                   const BSONObj& cmdObj) {
    AuthorizationSession* authSession = AuthorizationSession::get(txn->getClient());

    ApplyOpsValidity validity = validateApplyOpsCommand(cmdObj);
    if (validity == ApplyOpsValidity::kNeedsSuperuser) {
        std::vector<Privilege> universalPrivileges;
        RoleGraph::generateUniversalPrivileges(&universalPrivileges);
        if (!authSession->isAuthorizedForPrivileges(universalPrivileges)) {
            return Status(ErrorCodes::Unauthorized, "Unauthorized");
        }
        return Status::OK();
    }
    fassert(40314, validity == ApplyOpsValidity::kOk);

    boost::optional<DisableDocumentValidation> maybeDisableValidation;
    if (shouldBypassDocumentValidationForCommand(cmdObj))
        maybeDisableValidation.emplace(txn);


    const bool alwaysUpsert =
        cmdObj.hasField("alwaysUpsert") ? cmdObj["alwaysUpsert"].trueValue() : true;

    checkBSONType(BSONType::Array, cmdObj.firstElement());
    for (const BSONElement& e : cmdObj.firstElement().Array()) {
        checkBSONType(BSONType::Object, e);
        Status status = checkOperationAuthorization(txn, dbname, e.Obj(), alwaysUpsert);
        if (!status.isOK()) {
            return status;
        }
    }

    BSONElement preconditions = cmdObj["preCondition"];
    if (!preconditions.eoo()) {
        for (const BSONElement& precondition : preconditions.Array()) {
            checkBSONType(BSONType::Object, precondition);
            BSONElement nsElem = precondition.Obj()["ns"];
            checkBSONType(BSONType::String, nsElem);
            NamespaceString nss(nsElem.checkAndGetStringData());

            if (!authSession->isAuthorizedForActionsOnResource(
                    ResourcePattern::forExactNamespace(nss), ActionType::find)) {
                return Status(ErrorCodes::Unauthorized, "Unauthorized to check precondition");
            }
        }
    }

    return Status::OK();
}
示例#6
0
void addPrivilegesRequiredForMapReduce(Command* commandTemplate,
                                       const std::string& dbname,
                                       const BSONObj& cmdObj,
                                       std::vector<Privilege>* out) {
    Config::OutputOptions outputOptions = Config::parseOutputOptions(dbname, cmdObj);

    ResourcePattern inputResource(commandTemplate->parseResourcePattern(dbname, cmdObj));
    uassert(17142,
            mongolutils::str::stream() << "Invalid input resource " << inputResource.toString(),
            inputResource.isExactNamespacePattern());
    out->push_back(Privilege(inputResource, ActionType::find));

    if (outputOptions.outType != Config::INMEMORY) {
        ActionSet outputActions;
        outputActions.addAction(ActionType::insert);
        if (outputOptions.outType == Config::REPLACE) {
            outputActions.addAction(ActionType::remove);
        } else {
            outputActions.addAction(ActionType::update);
        }

        if (shouldBypassDocumentValidationForCommand(cmdObj)) {
            outputActions.addAction(ActionType::bypassDocumentValidation);
        }

        ResourcePattern outputResource(
            ResourcePattern::forExactNamespace(NamespaceString(outputOptions.finalNamespace)));
        uassert(17143,
                mongolutils::str::stream() << "Invalid target namespace "
                                          << outputResource.ns().ns(),
                outputResource.ns().isValid());

        // TODO: check if outputNs exists and add createCollection privilege if not
        out->push_back(Privilege(outputResource, outputActions));
    }
}