void SASLServerMechanismRegistry::advertiseMechanismNamesForUser(OperationContext* opCtx,
                                                                 const BSONObj& isMasterCmd,
                                                                 BSONObjBuilder* builder) {
    BSONElement saslSupportedMechs = isMasterCmd["saslSupportedMechs"];
    if (saslSupportedMechs.type() == BSONType::String) {

        UserName userName = uassertStatusOK(UserName::parse(saslSupportedMechs.String()));


        // Authenticating the __system@local user to the admin database on mongos is required
        // by the auth passthrough test suite.
        if (getTestCommandsEnabled() &&
            userName.getUser() == internalSecurity.user->getName().getUser() &&
            userName.getDB() == "admin") {
            userName = internalSecurity.user->getName();
        }

        AuthorizationManager* authManager = AuthorizationManager::get(opCtx->getServiceContext());

        UserHandle user;
        const auto swUser = authManager->acquireUser(opCtx, userName);
        if (!swUser.isOK()) {
            auto& status = swUser.getStatus();
            if (status.code() == ErrorCodes::UserNotFound) {
                log() << "Supported SASL mechanisms requested for unknown user '" << userName
                      << "'";
                return;
            }
            uassertStatusOK(status);
        }

        user = std::move(swUser.getValue());
        BSONArrayBuilder mechanismsBuilder;
        const auto& mechList = _getMapRef(userName.getDB());

        for (const auto& factoryIt : mechList) {
            SecurityPropertySet properties = factoryIt->properties();
            if (!properties.hasAllProperties(SecurityPropertySet{SecurityProperty::kNoPlainText,
                                                                 SecurityProperty::kMutualAuth}) &&
                userName.getDB() != "$external") {
                continue;
            }

            auto mechanismEnabled = _mechanismSupportedByConfig(factoryIt->mechanismName());
            if (!mechanismEnabled && userName == internalSecurity.user->getName()) {
                mechanismEnabled = factoryIt->isInternalAuthMech();
            }

            if (mechanismEnabled && factoryIt->canMakeMechanismForUser(user.get())) {
                mechanismsBuilder << factoryIt->mechanismName();
            }
        }

        builder->appendArray("saslSupportedMechs", mechanismsBuilder.arr());
    }
}
示例#2
0
void NoopWriter::_writeNoop(OperationContext* opCtx) {
    // Use GlobalLock + lockMMAPV1Flush instead of DBLock to allow return when the lock is not
    // available. It may happen when the primary steps down and a shared global lock is acquired.
    Lock::GlobalLock lock(
        opCtx, MODE_IX, Date_t::now() + Milliseconds(1), Lock::InterruptBehavior::kLeaveUnlocked);
    if (!lock.isLocked()) {
        LOG(1) << "Global lock is not available skipping noopWrite";
        return;
    }
    opCtx->lockState()->lockMMAPV1Flush();

    auto replCoord = ReplicationCoordinator::get(opCtx);
    // Its a proxy for being a primary
    if (!replCoord->canAcceptWritesForDatabase(opCtx, "admin")) {
        LOG(1) << "Not a primary, skipping the noop write";
        return;
    }

    auto lastAppliedOpTime = replCoord->getMyLastAppliedOpTime();

    // _lastKnownOpTime is not protected by lock as its used only by one thread.
    if (lastAppliedOpTime != _lastKnownOpTime) {
        LOG(1) << "Not scheduling a noop write. Last known OpTime: " << _lastKnownOpTime
               << " != last primary OpTime: " << lastAppliedOpTime;
    } else {
        if (writePeriodicNoops.load()) {
            const auto logLevel = getTestCommandsEnabled() ? 0 : 1;
            LOG(logLevel)
                << "Writing noop to oplog as there has been no writes to this replica set in over "
                << _writeInterval;
            writeConflictRetry(
                opCtx, "writeNoop", NamespaceString::kRsOplogNamespace.ns(), [&opCtx] {
                    WriteUnitOfWork uow(opCtx);
                    opCtx->getClient()->getServiceContext()->getOpObserver()->onOpMessage(opCtx,
                                                                                          kMsgObj);
                    uow.commit();
                });
        }
    }

    _lastKnownOpTime = replCoord->getMyLastAppliedOpTime();
    LOG(1) << "Set last known op time to " << _lastKnownOpTime;
}
示例#3
0
bool CurrentOpCommandBase::run(OperationContext* opCtx,
                               const std::string& dbName,
                               const BSONObj& cmdObj,
                               BSONObjBuilder& result) {
    // Convert the currentOp command spec into an equivalent aggregation command. This will be
    // of the form {aggregate:1, pipeline: [{$currentOp: {idleConnections: $all, allUsers:
    // !$ownOps, truncateOps: true}}, {$match: {<filter>}}, {$group: {_id: null, inprog: {$push:
    // "$$ROOT"}}}], cursor:{}}
    std::vector<BSONObj> pipeline;

    // {$currentOp: {idleConnections: $all, allUsers: !$ownOps, truncateOps: true}}
    BSONObjBuilder currentOpBuilder;
    BSONObjBuilder currentOpSpecBuilder(currentOpBuilder.subobjStart("$currentOp"));

    // If test commands are enabled, then we allow the currentOp commands to specify whether or not
    // to truncate long operations via the '$truncateOps' parameter. Otherwise, we always truncate
    // operations to match the behaviour of the legacy currentOp command.
    const bool truncateOps =
        !getTestCommandsEnabled() || !cmdObj[kTruncateOps] || cmdObj[kTruncateOps].trueValue();

    currentOpSpecBuilder.append("idleConnections", cmdObj[kAll].trueValue());
    currentOpSpecBuilder.append("allUsers", !cmdObj[kOwnOps].trueValue());
    currentOpSpecBuilder.append("truncateOps", truncateOps);
    currentOpSpecBuilder.doneFast();

    pipeline.push_back(currentOpBuilder.obj());

    // {$match: {<user-defined filter>}}
    BSONObjBuilder matchBuilder;
    BSONObjBuilder matchSpecBuilder(matchBuilder.subobjStart("$match"));

    size_t idx = 0;
    for (const auto& elt : cmdObj) {
        const auto fieldName = elt.fieldNameStringData();

        if (0 == idx++ || kCurOpCmdParams.count(fieldName) || isGenericArgument(fieldName)) {
            continue;
        }

        matchSpecBuilder.append(elt);
    }

    matchSpecBuilder.doneFast();

    pipeline.push_back(matchBuilder.obj());

    // Perform any required modifications to the pipeline before adding the final $group stage.
    modifyPipeline(&pipeline);

    // {$group: {_id: null, inprog: {$push: "$$ROOT"}}}
    BSONObjBuilder groupBuilder;
    BSONObjBuilder groupSpecBuilder(groupBuilder.subobjStart("$group"));

    groupSpecBuilder.append("_id", 0);

    BSONObjBuilder inprogSpecBuilder(groupSpecBuilder.subobjStart("inprog"));

    inprogSpecBuilder.append("$push", "$$ROOT");

    inprogSpecBuilder.doneFast();
    groupSpecBuilder.doneFast();

    pipeline.push_back(groupBuilder.obj());

    // Pipeline is complete; create an AggregationRequest for $currentOp.
    const AggregationRequest request(NamespaceString::makeCollectionlessAggregateNSS("admin"),
                                     std::move(pipeline));

    // Run the pipeline and obtain a CursorResponse.
    auto aggResults = uassertStatusOK(runAggregation(opCtx, request));

    if (aggResults.getBatch().empty()) {
        result.append("inprog", BSONArray());
    } else {
        result.append(aggResults.getBatch().front()["inprog"]);
    }

    // Make any final custom additions to the response object.
    appendToResponse(&result);

    return true;
}