Index: core/kernel/event_handler.php =================================================================== --- core/kernel/event_handler.php +++ core/kernel/event_handler.php @@ -201,26 +201,73 @@ } /** - * Checks user permission to execute given $event + * Automatically decides what permission checking method to use for a given event/user. * - * @param kEvent $event - * @return bool - * @access public + * @param kEvent $event Event. + * + * @return boolean + */ + public function AutoCheckPermission(kEvent $event) + { + if ( $this->Application->permissionCheckingDisabled() ) { + return $this->CheckMetaPermission($event); + } + + return $this->CheckPermission($event); + } + + /** + * Checks user static permission to execute given $event. + * + * @param kEvent $event Event. + * + * @return boolean */ public function CheckPermission(kEvent $event) { + $this->addDynamicPermissionMappings($event); + /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); - if ( !isset($this->permMapping[$event->Name]) ) { - $ajax_event_name = $this->getAjaxSubEventName($event); + return $perm_helper->CheckEventPermission($event, $this->permMapping); + } - if ( $ajax_event_name != '' && isset($this->permMapping[$ajax_event_name]) ) { - $this->permMapping[$event->Name] = $this->permMapping[$ajax_event_name]; - } + /** + * Checks user meta-permission to execute given $event. + * + * @param kEvent $event Event. + * + * @return boolean + */ + public function CheckMetaPermission(kEvent $event) + { + $this->addDynamicPermissionMappings($event); + + /** @var kPermissionsHelper $perm_helper */ + $perm_helper = $this->Application->recallObject('PermissionsHelper'); + + return $perm_helper->CheckEventMetaPermission($event, $this->permMapping); + } + + /** + * Adds dynamic permission mappings. + * + * @param kEvent $event Event. + * + * @return void + */ + protected function addDynamicPermissionMappings(kEvent $event) + { + if ( isset($this->permMapping[$event->Name]) ) { + return; } - return $perm_helper->CheckEventPermission($event, $this->permMapping); + $ajax_event_name = $this->getAjaxSubEventName($event); + + if ( $ajax_event_name != '' && isset($this->permMapping[$ajax_event_name]) ) { + $this->permMapping[$event->Name] = $this->permMapping[$ajax_event_name]; + } } /** @@ -271,4 +318,4 @@ $event->setEventParam('sql', $sql); } - } \ No newline at end of file + } Index: core/kernel/managers/request_manager.php =================================================================== --- core/kernel/managers/request_manager.php +++ core/kernel/managers/request_manager.php @@ -157,7 +157,7 @@ /** @var kEventHandler $event_handler */ $event_handler = $this->Application->recallObject($event->Prefix . '_EventHandler'); - if ( $this->Application->permissionCheckingDisabled() || $event_handler->CheckPermission($event) ) { + if ( $event_handler->AutoCheckPermission($event) ) { $this->Application->HandleEvent($event); $this->Application->notifyEventSubscribers($event); } Index: core/units/helpers/permissions_helper.php =================================================================== --- core/units/helpers/permissions_helper.php +++ core/units/helpers/permissions_helper.php @@ -111,15 +111,15 @@ } $perm_status = false; - foreach ($check_perms as $perm_name) { - // check if at least one of required permissions is set - if ($perm_name == 'debug' && $this->Application->isDebugMode(false)) { - // universal "debug" permission - return true; - } - elseif ( $perm_name == 'admin' && $this->Application->isAdminUser ) { - // any logged-in admin user will suffice - return true; + + foreach ( $check_perms as $perm_name ) { + // Check if at least one of required permissions is set. + if ( $this->isMetaPermission($perm_name) ) { + if ( $this->checkMetaPermission($perm_name) ) { + return true; + } + + continue; } $perm_name = $section.'.'.$perm_name; @@ -138,6 +138,84 @@ } /** + * Common event meta-permission checking method. + * + * @param kEvent $event Event. + * @param array $perm_mapping Perm mapping. + * + * @return boolean + */ + public function CheckEventMetaPermission(kEvent $event, array $perm_mapping) + { + // For a non-root user a "kEventHandler::CheckPermission" method is overridden to fix below issues. + try { + /* + * Exception will be thrown, when "PermSection" isn't defined. + * + * This populates "top_prefix" event parameter used in "getPermissionByEvent" method. + */ + $event->getSection(); + + // Exception will be thrown if a permission mapping is absent. + $check_perms = $this->getPermissionByEvent($event, $perm_mapping); + } + catch ( Exception $e ) { + // Permission mapping is absent > grant access. + return true; + } + + // Event is defined in mapping but is not checked by permissions. + if ( $check_perms === true ) { + return true; + } + + // Event is mapped to a meta-permission > check used meta-permission. + foreach ( $check_perms as $perm_name ) { + if ( $this->isMetaPermission($perm_name) ) { + return $this->finalizePermissionCheck($event, $this->checkMetaPermission($perm_name)); + } + } + + // Event isn't mapped to a meta-permission > grant access. + return true; + } + + /** + * Determines if this is a meta-permission. + * + * @param string $permission_name Permission name. + * + * @return boolean + */ + public function isMetaPermission($permission_name) + { + return $permission_name === 'admin' || $permission_name === 'debug'; + } + + /** + * Determines if this is a meta-permission. + * + * @param string $permission_name Permission name. + * + * @return boolean + * @throws InvalidArgumentException When a non-meta-permission is given. + */ + public function checkMetaPermission($permission_name) + { + if ( $permission_name === 'debug' ) { + // Universal "debug" permission. + return $this->Application->isDebugMode(false); + } + + if ( $permission_name === 'admin' ) { + // Any logged-in admin user will suffice. + return $this->Application->isAdminUser; + } + + throw new InvalidArgumentException('The "' . $permission_name . '" permission is not a meta permission.'); + } + + /** * Returns owner + primary category for each item (used for permission checking) * * @param string $prefix @@ -260,13 +338,12 @@ continue; } - if ( $perm_name == 'debug' && $this->Application->isDebugMode(false) ) { - // universal "debug" permission - return true; - } - elseif ( $perm_name == 'admin' && $this->Application->isAdminUser ) { - // any logged-in admin user will suffice - return true; + if ( $this->isMetaPermission($perm_name) ) { + if ( $this->checkMetaPermission($perm_name) ) { + return true; + } + + continue; } $perm_name = $item_prefix . '.' . $perm_mapping[$perm_name]; @@ -406,8 +483,8 @@ $permission_groups = getArrayValue($params, 'permissions'); $check_admin = isset($params['admin']) && $params['admin']; - if ($permission_groups && !$perm_event) { - // check permissions by permission names in current category + if ( $permission_groups && !$perm_event ) { + // Check permissions by permission names in current category. $permission_groups = explode('|', $permission_groups); $group_has_permission = false; @@ -444,14 +521,15 @@ } return false; } - elseif ( $perm_event && !$this->Application->permissionCheckingDisabled() ) { - // check permission by event name - list ($prefix, ) = explode(':', $perm_event); + + if ( $perm_event ) { + // Check permission by event name. + list ($prefix,) = explode(':', $perm_event); /** @var kEventHandler $event_handler */ $event_handler = $this->Application->recallObject($prefix . '_EventHandler'); - return $event_handler->CheckPermission( new kEvent($perm_event) ); + return $event_handler->AutoCheckPermission(new kEvent($perm_event)); } return true;