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(), 'checkAction' => array(), 'checkAuthUser' => array(), 'checkExternalAuthUser' => array(), 'cleanModelCaches' => array(), 'debugACL' => array(), 'generateCount' => array(), 'getActions' => array(), 'pruneDuplicateUUIDs' => array(), 'queryACL' => array(), 'removeDuplicateEvents' => array(), 'updateDatabase' => array(), 'upgrade2324' => array(), ), 'attributes' => array( 'add' => array('perm_add'), 'add_attachment' => array('perm_add'), 'add_threatconnect' => array('perm_add'), 'attributeReplace' => array('perm_add'), 'attributeStatistics' => array('*'), 'checkComposites' => array('perm_admin'), 'delete' => array('perm_add'), 'deleteSelected' => array('perm_add'), 'describeTypes' => array('perm_auth'), 'download' => array('*'), 'downloadAttachment' => array('*'), 'downloadSample' => array('*'), 'edit' => array('perm_add'), 'editField' => array('perm_add'), 'editSelected' => array('perm_add'), 'fetchEditForm' => array('perm_add'), 'fetchViewValue' => array('*'), 'generateCorrelation' => array(), 'hoverEnrichment' => array('perm_add'), 'index' => array('*'), 'pruneOrphanedAttributes' => array(), 'reportValidationIssuesAttributes' => array(), 'restore' => array('perm_add'), 'restSearch' => array('*'), 'returnAttributes' => array('*'), 'rpz' => array('*'), 'search' => array('*'), 'searchAlternate' => array('*'), 'text' => array('*'), 'updateAttributeValues' => array('perm_add'), 'view' => array('*'), ), 'eventBlacklists' => array( 'add' => array(), 'delete' => array(), 'edit' => array(), 'index' => array(), ), 'eventDelegations' => array( 'acceptDelegation' => array('perm_add'), 'delegateEvent' => array('perm_add'), 'deleteDelegation' => array('perm_add'), 'view' => 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'), 'checkuuid' => array('perm_sync'), 'contact' => array('*'), 'create_dummy_event' => array(), 'create_massive_dummy_events' => array(), 'csv' => array('*'), 'delegation_index' => array('*'), 'delete' => array('perm_add'), 'dot' => array(), 'downloadExport' => array('*'), 'downloadOpenIOCEvent' => array('*'), 'downloadSearchResult' => array('*'), 'edit' => array('perm_add'), 'export' => array('*'), 'exportChoice' => array('*'), 'filterEventIdsForPush' => array('perm_sync'), 'filterEventIndex' => array('*'), 'freeTextImport' => array('perm_add'), 'hids' => array('*'), 'index' => array('*'), 'nids' => array('*'), 'proposalEventIndex' => array('*'), 'publish' => array('perm_publish'), 'pushProposals' => array('perm_sync'), 'queryEnrichment' => array('perm_add'), 'removePivot' => array('*'), 'removeTag' => array('perm_tagger'), 'reportValidationIssuesEvents' => array(), 'restSearch' => array('*'), 'saveFreeText' => array('perm_add'), 'stix' => array('*'), 'strposarray' => array(), 'updateGraph' => array('*'), 'upload_sample' => array('perm_auth'), 'view' => array('*'), 'viewEventAttributes' => array('*'), 'viewGraph' => array('*'), 'xml' => array('*'), ), 'favouriteTags' => array( 'index' => array('*'), 'toggle' => array('*'), 'getToggleField' => array('*') ), 'feeds' => array( 'add' => array(), 'delete' => array(), 'disable' => array(), 'edit' => array(), 'enable' => array(), 'fetchFromFeed' => array(), 'getEvent' => array(), 'index' => array(), 'previewEvent' => array(), 'previewIndex' => array(), 'view' => array(), ), 'jobs' => array( 'cache' => array('*'), 'getGenerateCorrelationProgress' => array('*'), 'getProgress' => array('*'), 'index' => array(), ), 'logs' => array( 'admin_index' => array('perm_audit'), 'admin_search' => array('perm_audit'), 'event_index' => array('*'), 'maxDateActivity' => array('*'), 'returnDates' => array('*'), ), 'news' => array( 'add' => array(), 'edit' => array(), 'delete' => array(), 'index' => array('*'), ), 'orgBlacklists' => 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('*'), 'fetchSGOrgRow' => array('*'), 'getUUIDs' => array('perm_sync'), 'index' => array('*'), 'landingpage' => array('*'), 'view' => array('*'), ), 'pages' => array( 'display' => array('*'), ), 'posts' => array( 'add' => array('*'), 'delete' => array('*'), 'edit' => array('*'), ), '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('*'), ), 'roles' => array( 'admin_add' => array(), 'admin_delete' => array(), 'admin_edit' => array(), 'admin_index' => array('perm_admin'), 'index' => array('*'), 'view' => array('*'), ), 'servers' => array( 'add' => array(), 'delete' => array(), 'deleteFile' => array(), 'edit' => array(), 'fetchServersForSG' => array('*'), 'filterEventIndex' => array(), 'getVersion' => array('*'), 'index' => array('OR' => array('perm_sync', 'perm_admin')), 'previewEvent' => array(), 'previewIndex' => array(), 'pull' => array('perm_auth'), 'purgeSessions' => array(), 'push' => array('perm_auth'), 'restartWorkers' => array(), 'serverSettings' => array(), 'serverSettingsEdit' => array(), 'serverSettingsReloadSetting' => array(), 'startWorker' => array(), 'startZeroMQServer' => array(), 'statusZeroMQServer' => array(), 'stopWorker' => array(), 'stopZeroMQServer' => array(), 'testConnection' => array('perm_sync'), 'uploadFile' => array(), ), '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'), 'editField' => array('perm_add'), 'fetchEditForm' => array('perm_add'), 'generateCorrelation' => array(), 'getProposalsByUuid' => array('perm_sync'), 'getProposalsByUuidList' => array('perm_sync'), 'index' => array('*'), 'view' => array('*'), ), 'sharingGroups' => array( 'add' => array('perm_sharing_group'), 'delete' => array('perm_sharing_group'), 'edit' => array('perm_sharing_group'), 'index' => array('*'), 'view' => array('*'), ), 'sightings' => array( 'add' => array('perm_add'), 'delete' => array('perm_add'), ), 'tags' => array( 'add' => array('perm_tag_editor'), 'delete' => array('perm_tag_editor'), 'edit' => array('perm_tag_editor'), 'index' => array('*'), 'quickAdd' => array('perm_tag_editor'), 'selectTag' => array('perm_tagger'), 'selectTaxonomy' => array('perm_tagger'), 'showEventTag' => array('*'), 'tagStatistics' => array('*'), 'view' => array('*'), 'viewTag' => array('*'), ), 'tasks' => array( 'index' => array(), 'setTask' => array(), ), 'taxonomies' => array( 'addTag' => array(), 'disable' => array(), 'enable' => array(), 'index' => array('*'), 'taxonomyMassConfirmation' => array('perm_tagger'), 'update' => array(), 'view' => array('*'), ), '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( 'admin_add' => array('perm_admin'), '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_view' => array('perm_admin'), 'arrayCopy' => array(), 'change_pw' => array('*'), 'checkAndCorrectPgps' => array(), 'dashboard' => array('*'), 'delete' => array('perm_admin'), 'downloadTerms' => array('*'), 'edit' => array('*'), 'fetchPGPKey' => array('perm_admin'), 'histogram' => array('*'), 'index' => array('*'), 'initiatePasswordReset' => array('perm_admin'), 'login' => array('*'), 'logout' => array('*'), 'memberslist' => array('*'), 'resetauthkey' => array('*'), 'routeafterlogin' => array('*'), 'statistics' => array('*'), 'terms' => array('*'), 'updateLoginTime' => array('*'), 'verifyCertificate' => array(), 'verifyGPG' => array(), 'view' => array('*'), ), 'warninglists' => array( 'enableWarninglist' => array(), 'getToggleField' => array(), 'index' => array('*'), 'toggleEnable' => array(), 'update' => array(), 'view' => array('*') ), 'whitelists' => 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('*'), ) ); // 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. public function checkAccess($user, $controller, $action) { if ($user['Role']['perm_site_admin']) return true; if (!isset($this->__aclList[$controller])) $this->__error(404, 'Invalid controller.'); if ($user['Role']['perm_site_admin']) return true; if (isset($this->__aclList[$controller][$action]) && !empty($this->__aclList[$controller][$action])) { if (in_array('*', $this->__aclList[$controller][$action])) return true; if (isset($this->__aclList[$controller][$action]['OR'])) { foreach ($this->__aclList[$controller][$action]['OR'] as $permission) if ($user['Role'][$permission]) return true; } else if (isset($this->__aclList[$controller][$action]['AND'])) { $allConditionsMet = true; foreach ($this->__aclList[$controller][$action]['AND'] as $permission) if (!$user['Role'][$permission]) $allConditionsMet = false; if ($allConditionsMet) return true; } else if ($user['Role'][$this->__aclList[$controller][$action][0]]) return true; } $this->__error(403, 'You do not have permission to use this functionality.'); } private function __error($code, $message) { switch ($code) { case 404: throw new NotFoundException($message); break; case 403: throw new MethodNotAllowedException($message); default: throw new InternalErrorException('Unknown error: ' . $message); } } 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); preg_match_all($functionFinder, $fileContents, $functionArray); foreach ($functionArray[1] as $function) { if (substr($function, 0, 1) !== '_' && $function !== 'beforeFilter') $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($role) { $result = array(); 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 ($role['perm_site_admin']) $result[] = DS . $controllerName . DS . $action; else if (in_array('*', $permissions)) $result[] = DS . $controllerName . DS . $action . DS . '*'; else if (isset($permissions['OR'])) { $access = false; foreach ($permissions['OR'] as $permission) if ($role[$permission]) $access = true; if ($access) $result[] = DS . $controllerName . DS . $action . DS . '*'; } else if (isset($permissions['AND'])) { $access = true; foreach ($permissions['AND'] as $permission) if ($role[$permission]) $access = false; if ($access) $result[] = DS . $controllerName . DS . $action . DS . '*'; } else if (isset($permissions[0]) && $role[$permissions[0]]) $result[] = DS . $controllerName . DS . $action . DS . '*'; } } } return $result; } }