array()) - any role in the array has access // $action == array('AND' => array()) - roles with all permissions in the array have access // If we add any new functionality to MISP and we don't add it to this list, it will only be visible to site admins. private $__aclList = array( '*' => array( 'blackhole' => array(), 'checkAuthUser' => array(), 'checkExternalAuthUser' => array(), 'cleanModelCaches' => array(), 'debugACL' => array(), 'generateCount' => array(), 'pruneDuplicateUUIDs' => array(), 'queryACL' => array(), 'removeDuplicateEvents' => array(), 'restSearch' => array('*'), 'updateDatabase' => array(), 'upgrade2324' => array(), ), 'attributes' => array( 'add' => array('perm_add'), 'add_attachment' => array('perm_add'), 'add_threatconnect' => array('perm_add'), 'addTag' => array('perm_tagger'), 'attributeReplace' => array('perm_add'), 'attributeStatistics' => array('*'), 'bro' => array('*'), 'checkAttachments' => array(), 'checkComposites' => array('perm_admin'), 'checkOrphanedAttributes' => array(), 'delete' => array('perm_add'), 'deleteSelected' => array('perm_add'), 'describeTypes' => array('*'), 'download' => array('*'), 'downloadAttachment' => array('*'), 'downloadSample' => array('*'), 'edit' => array('perm_add'), 'editField' => array('perm_add'), 'editSelected' => array('perm_add'), 'exportSearch' => array('*'), 'fetchEditForm' => array('perm_add'), 'fetchViewValue' => array('*'), 'generateCorrelation' => array(), 'getMassEditForm' => array('perm_add'), 'hoverEnrichment' => array('perm_add'), 'index' => array('*'), 'pruneOrphanedAttributes' => array(), 'removeTag' => array('perm_tagger'), 'reportValidationIssuesAttributes' => array(), 'restore' => array('perm_add'), 'restSearch' => array('*'), 'returnAttributes' => array('*'), 'rpz' => array('*'), 'search' => array('*'), 'searchAlternate' => array('*'), 'toggleCorrelation' => array('perm_add'), 'text' => array('*'), 'toggleToIDS' => array('perm_add'), 'updateAttributeValues' => array('perm_add'), 'view' => array('*'), 'viewPicture' => array('*'), ), 'authKeys' => [ 'add' => ['perm_auth'], 'delete' => ['perm_auth'], 'edit' => ['perm_auth'], 'index' => ['perm_auth'], 'view' => ['perm_auth'] ], 'cerebrates' => [ 'add' => [], 'delete' => [], 'download_org' => [], 'edit' => [], 'index' => [], 'preview_orgs' => [], 'pull_orgs' => [], 'view' => [] ], 'correlationExclusions' => [ 'add' => [], 'edit' => [], 'clean' => [], 'delete' => [], 'index' => [], 'view' => [] ], 'correlations' => [ 'generateTopCorrelations' => [], 'top' => [] ], 'dashboards' => array( 'getForm' => array('*'), 'index' => array('*'), 'updateSettings' => array('*'), 'getEmptyWidget' => array('*'), 'renderWidget' => array('*'), 'listTemplates' => array('*'), 'saveTemplate' => array('*'), 'export' => array('*'), 'import' => array('*'), 'deleteTemplate' => array('*') ), 'decayingModel' => array( "update" => array(), "export" => array('*'), "import" => array('*'), "view" => array('*'), "index" => array('*'), "add" => array( 'OR' => array('perm_admin', 'perm_decaying')), "edit" => array( 'OR' => array('perm_admin', 'perm_decaying')), "delete" => array( 'OR' => array('perm_admin', 'perm_decaying')), "enable" => array( 'OR' => array('perm_admin', 'perm_decaying')), "disable" => array( 'OR' => array('perm_admin', 'perm_decaying')), "decayingTool" => array( 'OR' => array('perm_admin', 'perm_decaying')), "getAllDecayingModels" => array('*'), "decayingToolBasescore" => array('*'), "decayingToolSimulation" => array('*'), "decayingToolRestSearch" => array('*'), "decayingToolComputeSimulation" => array('*') ), 'decayingModelMapping' => array( "viewAssociatedTypes" => array('*'), "linkAttributeTypeToModel" => array( 'OR' => array('perm_admin', 'perm_decaying')) ), 'communities' => array( 'index' => array(), 'requestAccess' => array(), 'view' => array() ), 'eventBlocklists' => array( 'add' => [ 'AND' => [ 'host_org_user', 'perm_add' ] ], 'delete' => [ 'AND' => [ 'host_org_user', 'perm_add' ] ], 'edit' => [ 'AND' => [ 'host_org_user', 'perm_add' ] ], 'index' => [ 'AND' => [ 'host_org_user', 'perm_add' ] ], 'massDelete' => [ 'AND' => [ 'host_org_user', 'perm_add' ] ] ), 'eventDelegations' => array( 'acceptDelegation' => array('AND' => ['delegation_enabled', 'perm_add']), 'delegateEvent' => array('AND' => ['delegation_enabled', 'perm_delegate']), 'deleteDelegation' => array('AND' => ['delegation_enabled', 'perm_add']), 'index' => array('delegation_enabled'), 'view' => array('delegation_enabled'), ), 'eventReports' => array( 'add' => array('perm_add'), 'view' => array('*'), 'viewSummary' => array('*'), 'edit' => array('perm_add'), 'delete' => array('perm_add'), 'reportFromEvent' => array('perm_add'), 'restore' => array('perm_add'), 'index' => array('*'), 'getProxyMISPElements' => array('*'), 'extractAllFromReport' => array('*'), 'extractFromReport' => array('*'), 'replaceSuggestionInReport' => array('*'), 'importReportFromUrl' => array('*'), ), 'events' => array( 'add' => array('perm_add'), 'addIOC' => array('perm_add'), 'addTag' => array('perm_tagger'), 'add_misp_export' => array('perm_modify'), 'alert' => array('perm_publish'), 'automation' => array('perm_auth'), 'checkLocks' => array('perm_add'), 'checkPublishedStatus' => array('*'), 'checkuuid' => array('perm_sync'), 'contact' => array('*'), 'csv' => array('*'), 'cullEmptyEvents' => array(), 'delegation_index' => array('*'), 'delete' => array('perm_add'), 'deleteNode' => array('*'), 'dot' => array(), 'downloadExport' => array('*'), 'downloadOpenIOCEvent' => array('*'), 'edit' => array('perm_add'), 'enrichEvent' => array('perm_add'), 'export' => array('*'), 'exportChoice' => array('*'), 'exportModule' => array('*'), 'filterEventIdsForPush' => array('perm_sync'), 'filterEventIndex' => array('*'), 'freeTextImport' => array('perm_add'), 'getEditStrategy' => array('perm_add'), 'getEventInfoById' => array('*'), 'getEventGraphReferences' => array('*'), 'getEventGraphTags' => array('*'), 'getEventGraphGeneric' => array('*'), 'getEventTimeline' => array('*'), 'genDistributionGraph' => array('*'), 'getDistributionGraph' => array('*'), 'getReferenceData' => array('*'), 'getReferences' => array('*'), 'getObjectTemplate' => array('*'), 'handleModuleResults' => array('*'), 'hids' => array('*'), 'index' => array('*'), 'importChoice' => array('*'), 'importModule' => array('*'), 'massDelete' => array('perm_site_admin'), 'merge' => array('perm_modify'), 'nids' => array('*'), 'proposalEventIndex' => array('*'), 'publish' => array('perm_publish'), 'publishSightings' => array('perm_sighting'), 'pushEventToZMQ' => array('perm_publish_zmq'), 'pushEventToKafka' => array('perm_publish_kafka'), 'pushProposals' => array('perm_sync'), 'queryEnrichment' => array('perm_add'), 'recoverEvent' => array('perm_site_admin'), 'removePivot' => array('*'), 'removeTag' => array('perm_tagger'), 'reportValidationIssuesEvents' => array(), 'restoreDeletedEvents' => array('perm_site_admin'), 'restSearch' => array('*'), 'runTaxonomyExclusivityCheck' => array('*'), 'saveFreeText' => array('perm_add'), 'stix' => array('*'), 'stix2' => array('*'), 'strposarray' => array(), 'toggleCorrelation' => array('perm_add'), 'unpublish' => array('perm_modify'), 'updateGraph' => array('*'), 'upload_analysis_file' => array('perm_add'), 'upload_sample' => array('AND' => array('perm_auth', 'perm_add')), 'upload_stix' => array('perm_add'), 'view' => array('*'), 'viewClusterRelations' => array('*'), 'viewEventAttributes' => array('*'), 'viewGraph' => array('*'), 'viewGalaxyMatrix' => array('*'), 'xml' => array('*'), 'addEventLock' => ['perm_auth'], 'removeEventLock' => ['perm_auth'], ), 'favouriteTags' => array( 'toggle' => array('*'), 'getToggleField' => array('*') ), 'feeds' => array( 'add' => array(), 'cacheFeeds' => array(), 'compareFeeds' => array('*'), 'delete' => array(), 'disable' => array(), 'edit' => array(), 'enable' => array(), 'feedCoverage' => array('*'), 'fetchFromAllFeeds' => array(), 'fetchFromFeed' => array(), 'fetchSelectedFromFreetextIndex' => array(), 'getEvent' => array(), 'importFeeds' => array(), 'index' => ['OR' => [ 'host_org_user', 'perm_site_admin', ]], 'loadDefaultFeeds' => array('perm_site_admin'), 'previewEvent' => array('*'), 'previewIndex' => array('*'), 'searchCaches' => ['OR' => [ 'host_org_user', 'perm_site_admin', ]], 'toggleSelected' => array('perm_site_admin'), 'view' => ['OR' => [ 'host_org_user', 'perm_site_admin', ]], ), 'galaxies' => array( 'attachCluster' => array('perm_tagger'), 'attachMultipleClusters' => array('perm_tagger'), 'delete' => array(), 'disable' => array('perm_site_admin'), 'enable' => array('perm_site_admin'), 'export' => array('*'), 'forkTree' => array('*'), 'index' => array('*'), 'import' => array('perm_galaxy_editor'), 'pushCluster' => array('perm_sync'), 'relationsGraph' => array('*'), 'selectGalaxy' => array('perm_tagger'), 'selectGalaxyNamespace' => array('perm_tagger'), 'selectCluster' => array('perm_tagger'), 'showGalaxies' => array('*'), 'toggle' => array('perm_site_admin'), 'update' => array(), 'view' => array('*'), 'viewGraph' => array('*'), 'wipe_default' => array(), ), 'galaxyClusterBlocklists' => array( 'add' => array(), 'delete' => array(), 'edit' => array(), 'index' => array(), 'massDelete' => array(), ), 'galaxyClusters' => array( 'add' => array('perm_galaxy_editor'), 'attachToEvent' => array('perm_tagger'), 'delete' => array('perm_galaxy_editor'), 'detach' => array('perm_tagger'), 'edit' => array('perm_galaxy_editor'), 'index' => array('*'), 'publish' => array('perm_galaxy_editor'), 'restore' => array('perm_galaxy_editor'), 'restSearch' => array('*'), 'unpublish' => array('perm_galaxy_editor'), 'updateCluster' => array('perm_galaxy_editor'), 'view' => array('*'), 'viewCyCatRelations' => array('*'), 'viewGalaxyMatrix' => array('*'), 'viewRelations' => array('*'), 'viewRelationTree' => array('*'), ), 'galaxyClusterRelations' => array( 'add' => array('perm_galaxy_editor'), 'delete' => array('perm_galaxy_editor'), 'edit' => array('perm_galaxy_editor'), 'index' => array('*'), 'view' => array('*'), ), 'galaxyElements' => array( 'delete' => array('perm_galaxy_editor'), 'flattenJson' => array('perm_galaxy_editor'), 'index' => array('*'), ), 'jobs' => array( 'cache' => array('*'), 'getError' => array(), 'getGenerateCorrelationProgress' => array(), 'getProgress' => array('*'), 'index' => array(), 'clearJobs' => array() ), 'logs' => array( 'admin_index' => array('perm_audit'), 'admin_search' => array('perm_audit'), 'event_index' => array('*'), 'returnDates' => array('*'), 'testForStolenAttributes' => array(), 'pruneUpdateLogs' => array() ), 'auditLogs' => [ 'admin_index' => ['perm_audit'], 'fullChange' => ['perm_audit'], 'eventIndex' => ['*'], 'returnDates' => ['*'], ], 'modules' => array( 'index' => array('perm_auth'), 'queryEnrichment' => array('perm_auth'), ), 'news' => array( 'add' => array(), 'edit' => array(), 'delete' => array(), 'index' => array('*'), ), 'noticelists' => array( 'delete' => array(), 'enableNoticelist' => array(), 'getToggleField' => array(), 'index' => array('*'), 'toggleEnable' => array(), 'update' => array(), 'view' => array('*') ), 'objects' => array( 'add' => array('perm_add'), 'addValueField' => array('perm_add'), 'delete' => array('perm_add'), 'edit' => array('perm_add'), 'get_row' => array('perm_add'), 'orphanedObjectDiagnostics' => array(), 'editField' => array('perm_add'), 'fetchEditForm' => array('perm_add'), 'fetchViewValue' => array('*'), 'quickAddAttributeForm' => array('perm_add'), 'quickFetchTemplateWithValidObjectAttributes' => array('perm_add'), 'restSearch' => array('*'), 'proposeObjectsFromAttributes' => array('*'), 'groupAttributesIntoObject' => array('perm_add'), 'revise_object' => array('perm_add'), 'view' => array('*'), ), 'objectReferences' => array( 'add' => array('perm_add'), 'delete' => array('perm_add'), 'view' => array('*'), ), 'objectTemplates' => array( 'activate' => array(), 'add' => array('perm_object_template'), 'edit' => array('perm_object_template'), 'delete' => array('perm_object_template'), 'getToggleField' => array(), 'getRaw' => array('perm_object_template'), 'objectChoice' => array('*'), 'objectMetaChoice' => array('perm_add'), 'view' => array('*'), 'viewElements' => array('*'), 'index' => array('*'), 'update' => array('perm_site_admin') ), 'objectTemplateElements' => array( 'viewElements' => array('*') ), 'orgBlocklists' => array( 'add' => array(), 'delete' => array(), 'edit' => array(), 'index' => array(), ), 'organisations' => array( 'admin_add' => array(), 'admin_delete' => array(), 'admin_edit' => array(), 'admin_generateuuid' => array(), 'admin_merge' => array(), 'fetchOrgsForSG' => array('perm_sharing_group'), 'fetchSGOrgRow' => array('*'), 'getUUIDs' => array('perm_sync'), 'index' => array('*'), 'view' => array('*'), ), 'pages' => array( 'display' => array('*'), ), 'posts' => array( 'add' => array('*'), 'delete' => array('*'), 'edit' => array('*'), 'pushMessageToZMQ' => array('perm_site_admin') ), 'regexp' => array( 'admin_add' => array('perm_regexp_access'), 'admin_clean' => array('perm_regexp_access'), 'admin_delete' => array('perm_regexp_access'), 'admin_edit' => array('perm_regexp_access'), 'admin_index' => array('perm_regexp_access'), 'cleanRegexModifiers' => array('perm_regexp_access'), 'index' => array('*'), ), 'restClientHistory' => array( 'delete' => array('*'), 'index' => array('*') ), 'roles' => array( 'admin_add' => array(), 'admin_delete' => array(), 'admin_edit' => array(), 'admin_set_default' => array(), 'index' => array('*'), 'view' => array('*'), ), 'servers' => array( 'add' => array(), 'dbSchemaDiagnostic' => array(), 'cache' => array(), 'changePriority' => array(), 'checkout' => array(), 'clearWorkerQueue' => array(), 'createSync' => array('perm_sync'), 'delete' => array(), 'deleteFile' => array(), 'edit' => array(), 'eventBlockRule' => array(), 'fetchServersForSG' => array('perm_sharing_group'), 'filterEventIndex' => array(), 'getApiInfo' => array('*'), 'getAvailableSyncFilteringRules' => array('*'), 'getInstanceUUID' => array('perm_sync'), 'getPyMISPVersion' => array('*'), 'getRemoteUser' => array(), 'getSetting' => array(), 'getSubmodulesStatus' => array(), 'getSubmoduleQuickUpdateForm' => array(), 'getWorkers' => array(), 'getVersion' => array('perm_auth'), 'idTranslator' => ['OR' => [ 'host_org_user', 'perm_site_admin', ]], 'import' => array(), 'index' => array(), 'ondemandAction' => array(), 'postTest' => array('*'), 'previewEvent' => array(), 'previewIndex' => array(), 'compareServers' => [], 'pull' => array(), 'purgeSessions' => array(), 'push' => array(), 'queryAvailableSyncFilteringRules' => array('*'), 'releaseUpdateLock' => array(), 'resetRemoteAuthKey' => array(), 'removeOrphanedCorrelations' => array('perm_site_admin'), 'rest' => array('perm_auth'), 'openapi' => array('*'), 'restartDeadWorkers' => array(), 'restartWorkers' => array(), 'serverSettings' => array(), 'serverSettingsEdit' => array(), 'serverSettingsReloadSetting' => array(), 'startWorker' => array(), 'startZeroMQServer' => array(), 'statusZeroMQServer' => array(), 'stopWorker' => array(), 'stopZeroMQServer' => array(), 'testConnection' => array(), 'update' => array(), 'updateJSON' => array(), 'updateProgress' => array(), 'updateSubmodule' => array(), 'uploadFile' => array(), 'viewDeprecatedFunctionUse' => array(), 'killAllWorkers' => ['perm_site_admin'], 'cspReport' => ['*'], ), 'shadowAttributes' => array( 'accept' => array('perm_add'), 'acceptSelected' => array('perm_add'), 'add' => array('perm_add'), 'add_attachment' => array('perm_add'), 'delete' => array('perm_add'), 'discard' => array('perm_add'), 'discardSelected' => array('perm_add'), 'download' => array('*'), 'edit' => array('perm_add'), 'generateCorrelation' => array(), 'index' => array('*'), 'view' => array('*'), 'viewPicture' => array('*'), ), 'sharingGroups' => array( 'add' => array('perm_sharing_group'), 'addServer' => array('perm_sharing_group'), 'addOrg' => array('perm_sharing_group'), 'delete' => array('perm_sharing_group'), 'edit' => array('perm_sharing_group'), 'index' => array('*'), 'removeServer' => array('perm_sharing_group'), 'removeOrg' => array('perm_sharing_group'), 'view' => array('*'), ), 'sightings' => array( 'add' => array('perm_sighting'), 'restSearch' => array('perm_sighting'), 'advanced' => array('perm_sighting'), 'delete' => array('perm_sighting'), 'index' => array('*'), 'listSightings' => array('*'), 'quickDelete' => array('perm_sighting'), 'viewSightings' => array('*'), 'bulkSaveSightings' => array('OR' => array('perm_sync', 'perm_sighting')), 'quickAdd' => array('perm_sighting') ), 'sightingdb' => array( 'add' => array(), 'edit' => array(), 'delete' => array(), 'index' => array(), 'requestStatus' => array(), 'search' => array() ), 'tagCollections' => array( 'add' => array('perm_tag_editor'), 'addTag' => array('perm_tag_editor'), 'delete' => array('perm_tag_editor'), 'edit' => array('perm_tag_editor'), 'getRow' => array('perm_tag_editor'), 'import' => array('perm_tag_editor'), 'index' => array('*'), 'removeTag' => array('perm_tag_editor'), 'view' => array('*') ), 'tags' => array( 'add' => array('perm_tag_editor'), 'attachTagToObject' => array('perm_tagger'), 'delete' => array(), 'edit' => array(), 'index' => array('*'), 'quickAdd' => array('perm_tag_editor'), 'removeTagFromObject' => array('perm_tagger'), 'search' => array('*'), 'selectTag' => array('perm_tagger'), 'selectTaxonomy' => array('perm_tagger'), 'showEventTag' => array('*'), 'showAttributeTag' => array('*'), 'showTagControllerTag' => array('*'), 'tagStatistics' => array('*'), 'view' => array('*'), 'viewGraph' => array('*'), 'viewTag' => array('*') ), 'tasks' => array( 'index' => array(), 'setTask' => array(), ), 'taxonomies' => array( 'addTag' => array(), 'delete' => array(), 'disable' => array(), 'disableTag' => array(), 'enable' => array(), 'index' => array('*'), 'taxonomyMassConfirmation' => array('perm_tagger'), 'taxonomyMassHide' => array('perm_tagger'), 'taxonomyMassUnhide' => array('perm_tagger'), 'toggleRequired' => array('perm_site_admin'), 'update' => array(), 'import' => [], 'view' => array('*'), 'unhideTag' => array('perm_tagger'), 'hideTag' => array('perm_tagger'), ), 'templateElements' => array( 'add' => array('perm_template'), 'delete' => array('perm_template'), 'edit' => array('perm_template'), 'index' => array('*'), 'templateElementAddChoices' => array('perm_template'), ), 'templates' => array( 'add' => array('perm_template'), 'delete' => array('perm_template'), 'deleteTemporaryFile' => array('perm_add'), 'edit' => array('perm_template'), 'index' => array('*'), 'populateEventFromTemplate' => array('perm_add'), 'saveElementSorting' => array('perm_template'), 'submitEventPopulation' => array('perm_add'), 'templateChoices' => array('*'), 'uploadFile' => array('*'), 'view' => array('*'), ), 'threads' => array( 'index' => array('*'), 'view' => array('*'), 'viewEvent' => array('*'), ), 'users' => array( 'acceptRegistrations' => array('perm_site_admin'), 'admin_add' => ['AND' => ['perm_admin', 'add_user_enabled']], 'admin_delete' => array('perm_admin'), 'admin_edit' => array('perm_admin'), 'admin_email' => array('perm_admin'), 'admin_filterUserIndex' => array('perm_admin'), 'admin_index' => array('perm_admin'), 'admin_massToggleField' => array('perm_admin'), 'admin_monitor' => array('perm_site_admin'), 'admin_quickEmail' => array('perm_admin'), 'admin_view' => array('perm_admin'), 'attributehistogram' => array('*'), 'change_pw' => ['AND' => ['self_management_enabled', 'password_change_enabled']], 'checkAndCorrectPgps' => array(), 'checkIfLoggedIn' => array('*'), 'dashboard' => array('*'), 'delete' => array('perm_admin'), 'discardRegistrations' => array('perm_site_admin'), 'downloadTerms' => array('*'), 'edit' => array('self_management_enabled'), 'email_otp' => array('*'), 'searchGpgKey' => array('*'), 'fetchGpgKey' => array('*'), 'histogram' => array('*'), 'initiatePasswordReset' => ['AND' => ['perm_admin', 'password_change_enabled']], 'login' => array('*'), 'logout' => array('*'), 'register' => array('*'), 'registrations' => array('perm_site_admin'), 'resetAllSyncAuthKeys' => array(), 'resetauthkey' => ['AND' => ['self_management_enabled', 'perm_auth']], 'request_API' => array('*'), 'routeafterlogin' => array('*'), 'statistics' => array('*'), 'tagStatisticsGraph' => array('*'), 'terms' => array('*'), 'updateLoginTime' => array('*'), 'updateToAdvancedAuthKeys' => array(), 'verifyCertificate' => array(), 'verifyGPG' => array(), 'view' => array('*'), 'getGpgPublicKey' => array('*'), ), 'userSettings' => array( 'index' => array('*'), 'view' => array('*'), 'setSetting' => array('*'), 'getSetting' => array('*'), 'delete' => array('*'), 'setHomePage' => array('*'), 'eventIndexColumnToggle' => ['*'], ), 'warninglists' => array( 'checkValue' => array('perm_auth'), 'delete' => array(), 'enableWarninglist' => array(), 'getToggleField' => array(), 'index' => array('*'), 'toggleEnable' => array(), 'update' => array(), 'view' => array('*') ), 'allowedlists' => array( 'admin_add' => array('perm_regexp_access'), 'admin_delete' => array('perm_regexp_access'), 'admin_edit' => array('perm_regexp_access'), 'admin_index' => array('perm_regexp_access'), 'index' => array('*'), ), 'eventGraph' => array( 'view' => array('*'), 'viewPicture' => array('*'), 'add' => array('perm_add'), 'delete' => array('perm_modify'), ) ); private $dynamicChecks = []; public function __construct(ComponentCollection $collection, $settings = array()) { parent::__construct($collection, $settings); $this->dynamicChecks['host_org_user'] = function (array $user) { $hostOrgId = Configure::read('MISP.host_org_id'); return (int)$user['org_id'] === (int)$hostOrgId; }; $this->dynamicChecks['self_management_enabled'] = function (array $user) { if (Configure::read('MISP.disableUserSelfManagement') && !$user['Role']['perm_admin']) { throw new MethodNotAllowedException('User self-management has been disabled on this instance.'); } return true; }; $this->dynamicChecks['password_change_enabled'] = function (array $user) { if (Configure::read('MISP.disable_user_password_change')) { throw new MethodNotAllowedException('User password change has been disabled on this instance.'); } return true; }; $this->dynamicChecks['add_user_enabled'] = function (array $user) { if (Configure::read('MISP.disable_user_add')) { throw new MethodNotAllowedException('Adding users has been disabled on this instance.'); } return true; }; $this->dynamicChecks['delegation_enabled'] = function (array $user) { return (bool)Configure::read('MISP.delegation'); }; } private function __checkLoggedActions($user, $controller, $action) { $loggedActions = array( 'servers' => array( 'index' => array( 'role' => array( 'NOT' => array( 'perm_site_admin' ) ), 'message' => __('This could be an indication of an attempted privilege escalation on older vulnerable versions of MISP (<2.4.115)') ) ) ); foreach ($loggedActions as $k => $v) { $loggedActions[$k] = array_change_key_case($v); } if (!empty($loggedActions[$controller])) { if (!empty($loggedActions[$controller][$action])) { $message = $loggedActions[$controller][$action]['message']; $hit = false; if (empty($loggedActions[$controller][$action]['role'])) { $hit = true; } else { $role_req = $loggedActions[$controller][$action]['role']; if (empty($role_req['OR']) && empty($role_req['AND']) && empty($role_req['NOT'])) { $role_req = array('OR' => $role_req); } if (!empty($role_req['NOT'])) { foreach ($role_req['NOT'] as $k => $v) { if (!$user['Role'][$v]) { $hit = true; continue; } } } if (!$hit && !empty($role_req['AND'])) { $subhit = true; foreach ($role_req['AND'] as $k => $v) { $subhit = $subhit && $user['Role'][$v]; } if ($subhit) { $hit = true; } } if (!$hit && !empty($role_req['OR'])) { foreach ($role_req['OR'] as $k => $v) { if ($user['Role'][$v]) { $hit = true; continue; } } } if ($hit) { $this->Log = ClassRegistry::init('Log'); $this->Log->create(); $this->Log->save(array( 'org' => 'SYSTEM', 'model' => 'User', 'model_id' => $user['id'], 'email' => $user['email'], 'action' => 'security', 'user_id' => $user['id'], 'title' => __('User triggered security alert by attempting to access /%s/%s. Reason why this endpoint is of interest: %s', $controller, $action, $message), )); } } } } } /** * @param array $user * @param string $controller * @param string $action * @return bool */ public function canUserAccess($user, $controller, $action) { try { $this->checkAccess($user, $controller, $action, false); } catch (NotFoundException $e) { throw new RuntimeException("Invalid controller '$controller' specified.", 0, $e); } catch (MethodNotAllowedException $e) { return false; } return true; } /** * The check works like this: * - If the user is a site admin, return true * - If the requested action has an OR-d list, iterate through the list. If any of the permissions are set for the user, return true * - If the requested action has an AND-ed list, iterate through the list. If any of the permissions for the user are not set, turn the check to false. Otherwise return true. * - If the requested action has a permission, check if the user's role has it flagged. If yes, return true * - If we fall through all of the checks, return an exception. * * @param array|null $user * @param string $controller * @param string $action * @param bool $checkLoggedActions * @return true * @throws NotFoundException * @throws MethodNotAllowedException * @throws InternalErrorException */ public function checkAccess($user, $controller, $action, $checkLoggedActions = true) { $controller = lcfirst(Inflector::camelize($controller)); $action = strtolower($action); if ($checkLoggedActions) { $this->__checkLoggedActions($user, $controller, $action); } if ($user && $user['Role']['perm_site_admin']) { return true; } $aclList = $this->__aclList; foreach ($aclList as $k => $v) { $aclList[$k] = array_change_key_case($v); } if (!isset($aclList[$controller])) { $this->__error(404); } if (isset($aclList[$controller][$action]) && !empty($aclList[$controller][$action])) { $rules = $aclList[$controller][$action]; if (in_array('*', $rules)) { return true; } if (isset($rules['OR'])) { foreach ($rules['OR'] as $permission) { if (isset($this->dynamicChecks[$permission])) { if ($this->dynamicChecks[$permission]($user)) { return true; } } else { if ($user['Role'][$permission]) { return true; } } } } elseif (isset($rules['AND'])) { $allConditionsMet = true; foreach ($rules['AND'] as $permission) { if (isset($this->dynamicChecks[$permission])) { if (!$this->dynamicChecks[$permission]($user)) { $allConditionsMet = false; } } else { if (!$user['Role'][$permission]) { $allConditionsMet = false; } } } if ($allConditionsMet) { return true; } } elseif (isset($this->dynamicChecks[$rules[0]])) { if ($this->dynamicChecks[$rules[0]]($user)) { return true; } } elseif ($user['Role'][$rules[0]]) { return true; } } $this->__error(403); } /** * @param int $code * @throws InternalErrorException|MethodNotAllowedException|NotFoundException */ private function __error($code) { switch ($code) { case 404: throw new NotFoundException('Invalid controller.'); case 403: throw new MethodNotAllowedException('You do not have permission to use this functionality.'); default: throw new InternalErrorException('Unknown error'); } } private function __findAllFunctions() { $functionFinder = '/function[\s\n]+(\S+)[\s\n]*\(/'; $dir = new Folder(APP . 'Controller'); $files = $dir->find('.*\.php'); $results = array(); foreach ($files as $file) { $controllerName = lcfirst(str_replace('Controller.php', "", $file)); if ($controllerName === 'app') { $controllerName = '*'; } $functionArray = array(); $fileContents = file_get_contents(APP . 'Controller' . DS . $file); $fileContents = preg_replace('/\/\*[^\*]+?\*\//', '', $fileContents); preg_match_all($functionFinder, $fileContents, $functionArray); foreach ($functionArray[1] as $function) { if (substr($function, 0, 1) !== '_' && $function !== 'beforeFilter' && $function !== 'afterFilter') { $results[$controllerName][] = $function; } } } return $results; } public function printAllFunctionNames($content = false) { $results = $this->__findAllFunctions(); ksort($results); return $results; } public function findMissingFunctionNames($content = false) { $results = $this->__findAllFunctions(); $missing = array(); foreach ($results as $controller => $functions) { foreach ($functions as $function) { if (!isset($this->__aclList[$controller]) || !in_array($function, array_keys($this->__aclList[$controller]))) { $missing[$controller][] = $function; } } } return $missing; } public function printRoleAccess($content = false) { $results = array(); $this->Role = ClassRegistry::init('Role'); $conditions = array(); if (is_numeric($content)) { $conditions = array('Role.id' => $content); } $roles = $this->Role->find('all', array( 'recursive' => -1, 'conditions' => $conditions )); if (empty($roles)) { throw new NotFoundException('Role not found.'); } foreach ($roles as $role) { $urls = $this->__checkRoleAccess($role['Role']); $results[$role['Role']['id']] = array('name' => $role['Role']['name'], 'urls' => $urls); } return $results; } private function __checkRoleAccess(array $role) { $result = array(); $fakeUser = ['Role' => $role, 'org_id' => Configure::read('MISP.host_org_id')]; foreach ($this->__aclList as $controller => $actions) { $controllerNames = Inflector::variable($controller) === Inflector::underscore($controller) ? array(Inflector::variable($controller)) : array(Inflector::variable($controller), Inflector::underscore($controller)); foreach ($controllerNames as $controllerName) { foreach ($actions as $action => $permissions) { if ($this->canUserAccess($fakeUser, $controllerName, $action)) { $result[] = "/$controllerName/$action"; } } } } return $result; } }