Index: trunk/core/units/general/helpers/permissions_helper.php =================================================================== diff -u -N --- trunk/core/units/general/helpers/permissions_helper.php (revision 8779) +++ trunk/core/units/general/helpers/permissions_helper.php (revision 0) @@ -1,592 +0,0 @@ -Application->getUnitOption('perm', 'TableName'); - $perm_table = $this->Application->GetTempName($perm_table, 'prefix:'.$prefix); - $sql = 'SELECT * - FROM '.$perm_table.' - WHERE (GroupId = '.$group_id.') AND (CatId = '.$cat_id.') AND (Type = '.$type.')'; - $permissions = $this->Conn->Query($sql, 'Permission'); - - $this->Permissions = Array(); - foreach ($permissions as $perm_name => $perm_options) { - $perm_record['value'] = $perm_options['PermissionValue']; - $perm_record['id'] = $perm_options['PermissionId']; - $this->Permissions[$perm_name] = $perm_record; - } - } - - function getPermissionValue($perm_name) - { - return isset($this->Permissions[$perm_name]) ? $this->Permissions[$perm_name]['value'] : 0; - } - - function getPermissionID($perm_name) - { - return isset($this->Permissions[$perm_name]) ? $this->Permissions[$perm_name]['id'] : 0; - } - - /** - * This is old permission like ADMIN or LOGIN - * - * @param string $section_name - * @param string $perm_name - * @return bool - */ - function isOldPermission($section_name, $perm_name) - { - return $section_name == 'in-portal:root' && $perm_name != 'view'; - } - - /** - * Returns permission names to check based on event name and item prefix (main item or subitem) - * - * @param kEvent $event - * @return Array - */ - function getPermissionByEvent(&$event, $perm_mapping) - { - $top_prefix = $event->getEventParam('top_prefix'); - - $pefix_type = ($top_prefix == $event->Prefix) ? 'self' : 'subitem'; - $perm_mapping = getArrayValue($perm_mapping, $event->Name); - - if (!$perm_mapping[$pefix_type]) { - trigger_error('Permission mappings not defined for event '.$top_prefix.' <- '.$event->Prefix.':'.$event->Name.'', E_USER_ERROR); - } - - if ($perm_mapping[$pefix_type] === true) { - // event is defined in mapping but is not checked by permissions - return true; - } - - return explode('|', $perm_mapping[$pefix_type]); - } - - /** - * Common event permission checking method - * - * @param kEvent $event - */ - function CheckEventPermission(&$event, $perm_mapping) - { - $section = $event->getSection(); - if (preg_match('/^CATEGORY:(.*)/', $section)) { - return $this->CheckEventCategoryPermission($event, $perm_mapping); - } - - $top_prefix = $event->getEventParam('top_prefix'); - $check_perms = $this->getPermissionByEvent($event, $perm_mapping); - - if ($check_perms === true) { - // event is defined in mapping but is not checked by permissions - return true; - } - - $perm_status = false; - foreach ($check_perms as $perm_name) { - // check if at least one of required permissions is set - $perm_name = $section.'.'.$perm_name; - $perm_status = $this->CheckPermission($perm_name, 1); - if (($perm_name == $section.'.add') && $perm_status && ($top_prefix == $event->Prefix)) { - // main item, add permission allowed, but ID is > 0, then deny permission - // how to get id here - } - if ($perm_status) { - return $perm_status; - } - } - - if (!$perm_status) { - if ($this->Application->isDebugMode()) { - // for debugging purposes - $event->SetRedirectParam('section', $section); - $event->SetRedirectParam('main_prefix', $top_prefix); - $event->SetRedirectParam('event_name', $event->Name); - $event->SetRedirectParam('next_template', $this->Application->GetVar('t')); - } - $event->status = erPERM_FAIL; - } - return $perm_status; - } - - /** - * Returns owner + primary category for each item (used for permission checking) - * - * @param string $prefix - * @param string $ids - * @return Array - * @author Alex - */ - function GetCategoryItemData($prefix, $ids) - { - if (is_array($ids)) { - $ids = implode(',', $ids); - } - $id_field = $this->Application->getUnitOption($prefix, 'IDField'); - $table_name = $this->Application->getUnitOption($prefix, 'TableName'); - $ci_table = $this->Application->getUnitOption('ci', 'TableName'); - - $owner_field = $this->Application->getUnitOption($prefix, 'OwnerField'); - if (!$owner_field) { - $owner_field = 'CreatedById'; - } - - $sql = 'SELECT item_table.'.$id_field.', item_table.'.$owner_field.' AS CreatedById, ci.CategoryId - FROM '.$table_name.' item_table - LEFT JOIN '.$ci_table.' ci ON ci.ItemResourceId = item_table.ResourceId - WHERE item_table.'.$id_field.' IN ('.$ids.') AND (ci.PrimaryCat = 1)'; - return $this->Conn->Query($sql, $id_field); - } - - /** - * Checks non-system permission on event per category basis - * - * @param kEvent $event - */ - function CheckEventCategoryPermission(&$event, $event_perm_mapping) - { - // mapping between specific permissions and common permissions - $perm_mapping = Array('add' => 'ADD', 'add.pending' => 'ADD.PENDING', 'edit' => 'MODIFY', 'edit.pending' => 'MODIFY.PENDING', 'delete' => 'DELETE', 'view' => 'VIEW'); - - $top_prefix = $event->getEventParam('top_prefix'); - $event_handler =& $this->Application->recallObject($event->Prefix.'_EventHandler'); - /* @var $event_handler kCatDBEventHandler */ - - $raise_warnings = $event->getEventParam('raise_warnings'); - $event->setEventParam('raise_warnings', 0); - if ($event->Prefix != $top_prefix) { - $top_event = new kEvent($top_prefix.':'.$event->Name); - $id = $event_handler->getPassedID($top_event); - } - else { - $id = $event_handler->getPassedID($event); - } - $event->setEventParam('raise_warnings', $raise_warnings); - - $owner_id = -1; // owner is root if not detected - if (!$id) { - // item being created -> check by current (before editing started, saved in OnPreCreate event) category permissions - $category_id = $this->Application->IsAdmin() ? $this->Application->RecallVar('m_cat_id') : $this->Application->GetVar('m_cat_id'); - } - elseif ($top_prefix == 'c' || $top_prefix == 'st') { - $category_id = $id; - } - else { - // item being edited -> check by it's primary category permissions - $items_info = $this->GetCategoryItemData($top_prefix, $id); - $category_id = $items_info[$id]['CategoryId']; - $owner_id = $items_info[$id]['CreatedById']; - } - - // specific permission check for pending & owner permissions: begin - $new_item = $this->Application->IsAdmin() && $event_handler->isNewItemCreate($event) ? true : false; - $check_status = $this->checkCombinedPermissions($event, $owner_id, $category_id, $new_item); - if (isset($check_status)) { - return $check_status; - } - // specific permission check for pending & owner permissions: end - - $perm_status = false; - $check_perms = $this->getPermissionByEvent($event, $event_perm_mapping); - - if ($check_perms === true) { - // event is defined in mapping but is not checked by permissions - return true; - } - - $item_prefix = $this->Application->getUnitOption($top_prefix, 'PermItemPrefix'); - foreach ($check_perms as $perm_name) { - // check if at least one of required permissions is set - if (!isset($perm_mapping[$perm_name])) { - // not mapped permission (e.g. advanced:approve) -> skip - continue; - } - $perm_name = $item_prefix.'.'.$perm_mapping[$perm_name]; - $perm_status = $this->CheckPermission($perm_name, 0, $category_id); - - if ($perm_status) { - return $perm_status; - } - } - - if (!$perm_status) { - $event->SetRedirectParam('index_file', 'index.php'); // because called from browse.php - if ($this->Application->isDebugMode()) { - // for debugging purposes - $event->SetRedirectParam('section', $event->getSection()); - $event->SetRedirectParam('main_prefix', $top_prefix); - $event->SetRedirectParam('event_name', $event->Name); - $event->SetRedirectParam('next_template', $this->Application->GetVar('t')); - } - $event->status = erPERM_FAIL; - } - return $perm_status; - } - - /** - * Allows to check combined permissions (*.owner, *.pending) for add/modify/delete operations from admin & front-end - * - * @param kEvent $event - * @param int $owner_id - * @param int $category_id - * @param bool $new_item - * @return mixed - */ - function checkCombinedPermissions(&$event, $owner_id, $category_id, $new_item = false) - { - $ret = null; // true/false when used, null when not used - $top_prefix = $event->getEventParam('top_prefix'); - - // check admin permission - if (substr($event->Name, 0, 9) == 'OnPreSave') { - if ($new_item) { - $ret = $this->AddCheckPermission($category_id, $top_prefix); - } - else { - // add & modify because $new_item is false, when item is aready created & then saved in temp table (even with 0 id) - $ret = $this->AddCheckPermission($category_id, $top_prefix) || - $this->ModifyCheckPermission($owner_id, $category_id, $top_prefix); - } - } - - // check front-end permissions - switch ($event->Name) { - case 'OnCreate': - $ret = $this->AddCheckPermission($category_id, $top_prefix); - break; - - case 'OnUpdate': - $ret = $this->ModifyCheckPermission($owner_id, $category_id, $top_prefix); - break; - - case 'OnDelete': - case 'OnMassDelete': - $ret = $this->DeleteCheckPermission($owner_id, $category_id, $top_prefix); - break; - } - - if ($ret === 0) { - // permission check failed (user has no permission) - $event->status = erPERM_FAIL; - } - - return $ret; - } - - function TagPermissionCheck($params, $is_owner = false) - { - $perm_prefix = getArrayValue($params, 'perm_prefix'); - $perm_event = getArrayValue($params, 'perm_event'); - $permission_groups = getArrayValue($params, 'permissions'); - - if ($permission_groups) { - // check permissions by permission names in current category - $permission_groups = explode('|', $permission_groups); - $group_has_permission = false; - - $perm_category = isset($params['cat_id']) ? $params['cat_id'] : $this->Application->GetVar('m_cat_id'); - - if ($perm_prefix) { - // use primary category of item with id from {perm_prefix}_id as base for permission checking - $perm_category = $this->getPrimaryCategory($perm_prefix); - } - - $is_system = isset($params['system']) && $params['system'] ? 1 : 0; - foreach ($permission_groups as $permission_group) { - $permissions = explode(',', $permission_group); - $has_permission = true; - foreach ($permissions as $permission) { - $owner_checked = (strpos($permission, '.OWNER.') !== false) ? $is_owner : true; - $has_permission = $has_permission && $this->CheckPermission($permission, $is_system, $perm_category) && $owner_checked; - } - $group_has_permission = $group_has_permission || $has_permission; - - if ($group_has_permission) { - return true; - } - } - return false; - } - elseif ($perm_event) { - // check permission by event name - list($prefix, $event) = explode(':', $perm_event); - $event_handler =& $this->Application->recallObject($prefix.'_EventHandler'); - return $event_handler->CheckPermission( new kEvent($perm_event) ); - } - - return true; - } - - /** - * Returns item's primary category (get item_id from request) - * - * @param string $prefix - * @return int - */ - function getPrimaryCategory($prefix) - { - $id_field = $this->Application->getUnitOption($prefix, 'IDField'); - $table_name = $this->Application->getUnitOption($prefix, 'TableName'); - $id = $this->Application->GetVar($prefix.'_id'); - - if (!$id) return $this->Application->GetVar('m_cat_id'); - - $sql = 'SELECT ResourceId - FROM '.$table_name.' - WHERE '.$id_field.' = '.$id; - $resource_id = $this->Conn->GetOne($sql); - - $sql = 'SELECT CategoryId - FROM '.$this->Application->getUnitOption('ci', 'TableName').' - WHERE ItemResourceId = '.$resource_id.' AND PrimaryCat = 1'; - return $this->Conn->GetOne($sql); - } - - /** - * Returns no permission template to redirect to - * - * @param Array $params - * @return Array - */ - function getPermissionTemplate($params) - { - $t = $this->Application->GetVar('t'); - if ($next_t = getArrayValue($params, 'next_template')) { - $t = $next_t; - } - - if (!$this->Application->LoggedIn()) { - $redirect_template = $params['login_template']; - if (!$redirect_template && $this->Application->IsAdmin()) $redirect_template = 'login'; - $redirect_params = Array('next_template' => $t); - } - else { - if (isset($params['no_permissions_template'])) { - $redirect_template = $params['no_permissions_template']; - } - else { - $redirect_template = $this->Application->IsAdmin() ? 'no_permission' : $this->Application->ConfigValue('NoPermissionTemplate'); - } - - $redirect_params = $this->Application->isDebugMode() ? Array('from_template' => 1, 'perms' => $params[ isset($params['permissions']) ? 'permissions' : 'perm_event'], 'next_template' => $t) : Array(); - } - - if (isset($params['index_file']) && $params['index_file']) { - $redirect_params['index_file'] = $params['index_file']; - } - - return Array($redirect_template, $redirect_params); - } - - /** - * Check current user permissions based on it's group permissions in specified category (for non-system permissions) or just checks if system permission is set - * - * @param string $name permission name - * @param int $cat_id category id, current used if not specified - * @param int $type permission type {1 - system, 0 - per category} - * @return int - */ - function CheckPermission($name, $type = 1, $cat_id = null) - { - $user_id = $this->Application->RecallVar('user_id'); - return $this->CheckUserPermission($user_id, $name, $type, $cat_id); - } - - function CheckUserPermission($user_id, $name, $type = 1, $cat_id = null) - { - if ($user_id == -1) { - // "root" is allowed anywhere - return $name == 'SYSTEM_ACCESS.READONLY' ? 0 : 1; - } - - if ($type == 1) { - // "system" permission are always checked per "Home" category (ID = 0) - $cat_id = 0; - } - - if (!isset($cat_id)) { - $cat_id = $this->Application->GetVar('m_cat_id'); - } - - $cache_key = $name.'|'.$type.'|'.$cat_id; - $perm_value = $this->Application->getCache('permissions', $cache_key); - if ($perm_value !== false) { - return $perm_value; - } - - // perm cache is build only based on records in db, that's why if permission is not explicitly denied, then - // that (perm cache creator) code thinks that it is allowed & adds corresponding record and code below will - // return incorrect results - - if ($user_id == $this->Application->RecallVar('user_id')) { - $groups = explode(',', $this->Application->RecallVar('UserGroups')); - } - else { // checking not current user - $sql = 'SELECT GroupId FROM '.TABLE_PREFIX.'UserGroup - WHERE (PortalUserId = '.$user_id.') AND - ( (MembershipExpires IS NULL) OR ( MembershipExpires >= UNIX_TIMESTAMP() ) )'; - $groups = $this->Conn->GetCol($sql); - array_push($groups, $this->Application->ConfigValue('User_LoggedInGroup') ); - } - - if (preg_match('/(.*)\.VIEW$/', $name) && ($type == 0)) { - // cached view permission of category: begin - if (strpos($cat_id, '|') !== false) { - $category_path = explode('|', substr($cat_id, 1, -1)); - $cat_id = end($category_path); - } - - $sql = 'SELECT PermissionConfigId - FROM '.TABLE_PREFIX.'PermissionConfig - WHERE PermissionName = '.$this->Conn->qstr($name); - $perm_id = $this->Conn->GetOne($sql); - - $sql = 'SELECT PermId - FROM '.TABLE_PREFIX.'PermCache - WHERE (PermId = '.$perm_id.') AND (CategoryId = '.$cat_id.')'; - - $view_filters = Array(); - foreach ($groups as $group) { - $view_filters[] = 'FIND_IN_SET('.$group.', ACL)'; - } - $sql .= ' AND ('.implode(' OR ', $view_filters).')'; - $perm_value = $this->Conn->GetOne($sql) ? 1 : 0; - - $this->Application->setCache('permissions', $cache_key, $perm_value); - return $perm_value; - // cached view permission of category: end - } - - if (is_numeric($cat_id) && $cat_id == 0) { - $cat_hierarchy = Array(0); - } - else { - if (strpos($cat_id, '|') !== false) { - $cat_hierarchy = $cat_id; - } - else { - $sql = 'SELECT ParentPath - FROM '.$this->Application->getUnitOption('c', 'TableName').' - WHERE CategoryId = '.$cat_id; - $cat_hierarchy = $this->Conn->GetOne($sql); - } - - $cat_hierarchy = explode('|', substr($cat_hierarchy, 1, -1)); - $cat_hierarchy = array_reverse($cat_hierarchy); - array_push($cat_hierarchy, 0); - } - - $perm_value = 0; - $groups = implode(',',$groups); - foreach ($cat_hierarchy as $category_id) { - $sql = 'SELECT SUM(PermissionValue) - FROM '.TABLE_PREFIX.'Permissions - WHERE Permission = "'.$name.'" AND CatId = '.$category_id.' AND GroupId IN ('.$groups.') AND Type = '.$type; - $res = $this->Conn->GetOne($sql); - if ($res !== false && !is_null($res)) { - $perm_value = $res ? 1 : 0; - break; - } - } - - $this->Application->setCache('permissions', $cache_key, $perm_value); - return $perm_value; - } - - /** - * Allows to check MODIFY & OWNER.MODFY +/- PENDING permission combinations on item - * - * @param int $owner_id user_id, that is owner of the item - * @param int $category_id primary category of item - * @param string $prefix prefix of item - * @return int {0 - no MODIFY permission, 1 - has MODIFY permission, 2 - has MODIFY.PENDING permission} - */ - function ModifyCheckPermission($owner_id, $category_id, $prefix) - { - $perm_prefix = $this->Application->getUnitOption($prefix, 'PermItemPrefix'); - - $live_modify = $this->CheckPermission($perm_prefix.'.MODIFY', ptCATEGORY, $category_id); - if ($live_modify) { - return 1; - } - else if ($this->CheckPermission($perm_prefix.'.MODIFY.PENDING', ptCATEGORY, $category_id)) { - return 2; - } - - if ($owner_id == $this->Application->RecallVar('user_id')) { - // user is item's OWNER -> check this permissions first - $live_modify = $this->CheckPermission($perm_prefix.'.OWNER.MODIFY', ptCATEGORY, $category_id); - if ($live_modify) { - return 1; - } - else if ($this->CheckPermission($perm_prefix.'.OWNER.MODIFY.PENDING', ptCATEGORY, $category_id)) { - return 2; - } - } - - return 0; - } - - /** - * Allows to check DELETE & OWNER.DELETE permission combinations on item - * - * @param int $owner_id user_id, that is owner of the item - * @param int $category_id primary category of item - * @param string $prefix prefix of item - * @return int {0 - no DELETE permission, 1 - has DELETE/OWNER.DELETE permission} - */ - function DeleteCheckPermission($owner_id, $category_id, $prefix) - { - $perm_prefix = $this->Application->getUnitOption($prefix, 'PermItemPrefix'); - - $live_delete = $this->CheckPermission($perm_prefix.'.DELETE', ptCATEGORY, $category_id); - if ($live_delete) { - return 1; - } - - if ($owner_id == $this->Application->RecallVar('user_id')) { - // user is item's OWNER -> check this permissions first - $live_delete = $this->CheckPermission($perm_prefix.'.OWNER.DELETE', ptCATEGORY, $category_id); - if ($live_delete) { - return 1; - } - } - - return 0; - } - - /** - * Allows to check ADD +/- PENDING permission combinations on item - * - * @param int $category_id primary category of item - * @param string $prefix prefix of item - * @return int {0 - no ADD permission, 1 - has ADD permission, 2 - has ADD.PENDING permission} - */ - function AddCheckPermission($category_id, $prefix) - { - $perm_prefix = $this->Application->getUnitOption($prefix, 'PermItemPrefix'); - - $live_add = $this->CheckPermission($perm_prefix.'.ADD', ptCATEGORY, $category_id); - if ($live_add) { - return 1; - } - else if ($this->CheckPermission($perm_prefix.'.ADD.PENDING', ptCATEGORY, $category_id)) { - return 2; - } - - return 0; - } - } - -?> \ No newline at end of file