/** * 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; }