예제 #1
0
/**
 * Updates roleGraph for command-type oplog operations on the admin database.
 */
Status handleOplogCommand(RoleGraph* roleGraph, const BSONObj& cmdObj) {
    const NamespaceString& rolesCollectionNamespace =
        AuthorizationManager::rolesCollectionNamespace;
    const StringData cmdName(cmdObj.firstElement().fieldNameStringData());
    if (cmdName == "applyOps") {
        // Operations applied by applyOps will be passed into RoleGraph::handleOplog() by the
        // implementation of applyOps itself.
        return Status::OK();
    }
    if (cmdName == "create") {
        return Status::OK();
    }
    if (cmdName == "drop") {
        if (cmdObj.firstElement().str() == rolesCollectionNamespace.coll()) {
            *roleGraph = RoleGraph();
        }
        return Status::OK();
    }
    if (cmdName == "dropDatabase") {
        *roleGraph = RoleGraph();
        return Status::OK();
    }
    if (cmdName == "renameCollection") {
        if (cmdObj.firstElement().str() == rolesCollectionNamespace.ns()) {
            *roleGraph = RoleGraph();
            return Status::OK();
        }
        if (cmdObj["to"].str() == rolesCollectionNamespace.ns()) {
            *roleGraph = RoleGraph();
            return Status(ErrorCodes::OplogOperationUnsupported,
                          "Renaming into admin.system.roles produces inconsistent state; "
                          "must resynchronize role graph.");
        }
        return Status::OK();
    }

    if (cmdName == "dropIndexes" || cmdName == "deleteIndexes") {
        return Status::OK();
    }
    if ((cmdName == "collMod" || cmdName == "emptycapped" || cmdName == "createIndexes") &&
        cmdObj.firstElement().str() != rolesCollectionNamespace.coll()) {
        // We don't care about these if they're not on the roles collection.
        return Status::OK();
    }

    if ((cmdName == "collMod") && (cmdObj.nFields() == 1)) {
        // We also don't care about empty modifications even if they are on roles collection
        return Status::OK();
    }

    //  No other commands expected.  Warn.
    return Status(ErrorCodes::OplogOperationUnsupported, "Unsupported oplog operation");
}
    Status AuthzManagerExternalStateMongod::_initializeRoleGraph() {
        boost::lock_guard<boost::mutex> lkInitialzeRoleGraph(_roleGraphMutex);
        switch (_roleGraphState) {
        case roleGraphStateInitial:
        case roleGraphStateHasCycle:
            break;
        case roleGraphStateConsistent:
            return Status(ErrorCodes::AlreadyInitialized,
                          "Role graph already initialized and consistent.");
        default:
            return Status(ErrorCodes::InternalError,
                          mongoutils::str::stream() << "Invalid role graph state " <<
                          _roleGraphState);
        }

        RoleGraph newRoleGraph;
        Status status = query(
                AuthorizationManager::rolesCollectionNamespace,
                BSONObj(),
                BSONObj(),
                boost::bind(addRoleFromDocumentOrWarn, &newRoleGraph, _1));
        if (!status.isOK())
            return status;

        status = newRoleGraph.recomputePrivilegeData();

        RoleGraphState newState;
        if (status == ErrorCodes::GraphContainsCycle) {
            error() << "Inconsistent role graph during authorization manager intialization.  Only "
                "direct privileges available. " << status.reason();
            newState = roleGraphStateHasCycle;
            status = Status::OK();
        }
        else if (status.isOK()) {
            newState = roleGraphStateConsistent;
        }
        else {
            newState = roleGraphStateInitial;
            newRoleGraph = RoleGraph();
        }

        if (status.isOK()) {
            _roleGraph.swap(newRoleGraph);
            _roleGraphState = newState;
        }
        return status;
    }
    void AuthzManagerExternalStateLocal::logOp(
            const char* op,
            const char* ns,
            const BSONObj& o,
            BSONObj* o2,
            bool* b) {

        if (ns == AuthorizationManager::rolesCollectionNamespace.ns() ||
            ns == AuthorizationManager::adminCommandNamespace.ns()) {

            boost::lock_guard<boost::mutex> lk(_roleGraphMutex);
            Status status = _roleGraph.handleLogOp(op, NamespaceString(ns), o, o2);

            if (status == ErrorCodes::OplogOperationUnsupported) {
                _roleGraph = RoleGraph();
                _roleGraphState = roleGraphStateInitial;
                BSONObjBuilder oplogEntryBuilder;
                oplogEntryBuilder << "op" << op << "ns" << ns << "o" << o;
                if (o2)
                    oplogEntryBuilder << "o2" << *o2;
                if (b)
                    oplogEntryBuilder << "b" << *b;
                error() << "Unsupported modification to roles collection in oplog; "
                    "restart this process to reenable user-defined roles; " << status.reason() <<
                    "; Oplog entry: " << oplogEntryBuilder.done();
            }
            else if (!status.isOK()) {
                warning() << "Skipping bad update to roles collection in oplog. " << status <<
                    " Oplog entry: " << op;
            }
            status = _roleGraph.recomputePrivilegeData();
            if (status == ErrorCodes::GraphContainsCycle) {
                _roleGraphState = roleGraphStateHasCycle;
                error() << "Inconsistent role graph during authorization manager initialization.  "
                    "Only direct privileges available. " << status.reason() <<
                    " after applying oplog entry " << op;
            }
            else {
                fassert(17183, status);
                _roleGraphState = roleGraphStateConsistent;
            }
        }
    }
    void AuthzManagerExternalStateMongod::logOp(
            const char* op,
            const char* ns,
            const BSONObj& o,
            BSONObj* o2,
            bool* b,
            bool fromMigrateUnused,
            const BSONObj* fullObjUnused) {

        if (ns == AuthorizationManager::rolesCollectionNamespace.ns() ||
            ns == AuthorizationManager::adminCommandNamespace.ns()) {

            boost::lock_guard<boost::mutex> lk(_roleGraphMutex);
            Status status = updateRoleGraphWithLogOpSignature(
                    &_roleGraph, op, NamespaceString(ns), o, o2);

            if (status == ErrorCodes::OplogOperationUnsupported) {
                _roleGraph = RoleGraph();
                _roleGraphState = roleGraphStateInitial;
                error() << "Unsupported modification to roles collection in oplog; "
                    "TODO how to remedy. " << status << " Oplog entry: " << op;
            }
            else if (!status.isOK()) {
                warning() << "Skipping bad update to roles collection in oplog. " << status <<
                    " Oplog entry: " << op;
            }
            status = _roleGraph.recomputePrivilegeData();
            if (status == ErrorCodes::GraphContainsCycle) {
                _roleGraphState = roleGraphStateHasCycle;
                error() << "Inconsistent role graph during authorization manager intialization.  "
                    "Only direct privileges available. " << status.reason() <<
                    " after applying oplog entry " << op;
            }
            else if (!status.isOK()) {
                _roleGraphState = roleGraphStateInitial;
                error() << "Error updating role graph; only builtin roles available. "
                    "TODO how to remedy. " << status << " Oplog entry: " << op;
            }
            else {
                _roleGraphState = roleGraphStateConsistent;
            }
        }
    }
    Status AuthzManagerExternalStateLocal::_initializeRoleGraph() {
        boost::lock_guard<boost::mutex> lkInitialzeRoleGraph(_roleGraphMutex);

        _roleGraphState = roleGraphStateInitial;
        _roleGraph = RoleGraph();

        RoleGraph newRoleGraph;
        Status status = query(
                AuthorizationManager::rolesCollectionNamespace,
                BSONObj(),
                BSONObj(),
                boost::bind(addRoleFromDocumentOrWarn, &newRoleGraph, _1));
        if (!status.isOK())
            return status;

        status = newRoleGraph.recomputePrivilegeData();

        RoleGraphState newState;
        if (status == ErrorCodes::GraphContainsCycle) {
            error() << "Inconsistent role graph during authorization manager initialization.  Only "
                "direct privileges available. " << status.reason();
            newState = roleGraphStateHasCycle;
            status = Status::OK();
        }
        else if (status.isOK()) {
            newState = roleGraphStateConsistent;
        }
        else {
            newState = roleGraphStateInitial;
        }

        if (status.isOK()) {
            _roleGraph.swap(newRoleGraph);
            _roleGraphState = newState;
        }
        return status;
    }