From bb4cd62e316a2152951fa4b18425e45b1e3f6fc9 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Thu, 22 May 2025 13:20:48 +0900 Subject: [PATCH] Return different "Not permitted" error message depending on what is required #2548 --- classes/module/ModuleObject.class.php | 116 ++++++++++++++++++-------- common/lang/en.php | 3 +- common/lang/ko.php | 1 + modules/member/lang/en.php | 3 + modules/member/lang/ko.php | 3 + 5 files changed, 91 insertions(+), 35 deletions(-) diff --git a/classes/module/ModuleObject.class.php b/classes/module/ModuleObject.class.php index c874df2b0..82cbde6a0 100644 --- a/classes/module/ModuleObject.class.php +++ b/classes/module/ModuleObject.class.php @@ -249,7 +249,7 @@ class ModuleObject extends BaseObject */ public function setPrivileges() { - if(!$this->user->isAdmin()) + if (!$this->user->isAdmin()) { // Get privileges(granted) information for target module by of module.xml if(($permission = $this->xml_info->action->{$this->act}->permission) && $permission->check_var) @@ -278,33 +278,28 @@ class ModuleObject extends BaseObject foreach($check_module_srl as $target_srl) { // Get privileges(granted) information of current user for target module - if(($grant = ModuleModel::getInstance()->getPrivilegesBySrl($target_srl, $permission->check_type)) === false) + $check_grant = ModuleModel::getPrivilegesBySrl($target_srl, $permission->check_type); + if ($check_grant === false) { return false; } // Check permission - if(!$this->checkPermission($grant, $this->user)) + if(!$this->checkPermission($check_grant, $this->user, $failed_requirement)) { - $this->stop($this->user->isMember() ? 'msg_not_permitted_act' : 'msg_not_logged'); + $this->stop($this->_generatePermissionError($failed_requirement)); return false; } } } } - // If no privileges(granted) information, check permission by privileges(granted) information for current module - if(!isset($grant)) + // Check permission based on the grant information for the current module. + $grant = ModuleModel::getInstance()->getGrant($this->module_info, $this->user, $this->xml_info); + if(!$this->checkPermission($grant, $this->user, $failed_requirement)) { - // Get privileges(granted) information of current user for current module - $grant = ModuleModel::getInstance()->getGrant($this->module_info, $this->user, $this->xml_info); - - // Check permission - if(!$this->checkPermission($grant, $this->user)) - { - $this->stop($this->user->isMember() ? 'msg_not_permitted_act' : 'msg_not_logged'); - return false; - } + $this->stop($this->_generatePermissionError($failed_requirement)); + return false; } // If member action, grant access for log-in, sign-up, member pages @@ -313,7 +308,7 @@ class ModuleObject extends BaseObject $grant->access = true; } - // Set privileges(granted) variables + // Set aliases to grant object $this->grant = $grant; Context::set('grant', $grant); @@ -325,9 +320,10 @@ class ModuleObject extends BaseObject * * @param object $grant privileges(granted) information of user * @param object $member_info member information + * @param string|array &$failed_requirement * @return bool */ - public function checkPermission($grant = null, $member_info = null) + public function checkPermission($grant = null, $member_info = null, &$failed_requirement = '') { // Get logged-in member information if(!$member_info) @@ -361,24 +357,45 @@ class ModuleObject extends BaseObject { return true; } + // If permission is 'member', the user must be logged in - elseif ($permission === 'member') + if ($permission === 'member') { - if($member_info->member_srl) + if ($member_info->member_srl) { return true; } + else + { + $failed_requirement = 'member'; + return false; + } } + // If permission is 'not_member', the user must be logged out - elseif ($permission === 'not_member' || $permission === 'not-member') + if ($permission === 'not_member' || $permission === 'not-member') { - if(!$member_info->member_srl) + if (!$member_info->member_srl || $grant->manager) { return true; } + else + { + $failed_requirement = 'not_member'; + return false; + } } + + // If permission is 'root', false + // Because an administrator who have root privilege(granted) was passed already + if ($permission == 'root') + { + $failed_requirement = 'root'; + return false; + } + // If permission is 'manager', check 'is user have manager privilege(granted)' - elseif (preg_match('/^(manager(?::(.+))?|([a-z0-9\_]+)-managers)$/', $permission, $type)) + if (preg_match('/^(manager(?::(.+))?|([a-z0-9\_]+)-managers)$/', $permission, $type)) { // If permission is manager(:scope), check manager privilege and scope if ($grant->manager) @@ -412,32 +429,63 @@ class ModuleObject extends BaseObject return true; } } - } - // If permission is 'root', false - // Because an administrator who have root privilege(granted) was passed already - elseif ($permission == 'root') - { + + $failed_requirement = 'manager'; return false; } - // If grant name, check the privilege(granted) of the user - elseif ($grant_names = explode(',', $permission)) - { - $privilege_list = array_keys((array) $this->xml_info->grant); - foreach($grant_names as $name) + // Check grant name + // If multiple names are given, all of them must pass. + elseif ($grant_names = array_map('trim', explode(',', $permission))) + { + foreach ($grant_names as $name) { - if(!in_array($name, $privilege_list) || !$grant->$name) + if (!isset($grant->{$name})) { return false; } + if (!$grant->{$name}) + { + $failed_requirement = $grant->whocan($name); + return false; + } } - return true; } return false; } + /** + * Generate an error message for a failed permission. + * + * @param mixed $failed_requirement + * @return string + */ + protected function _generatePermissionError($failed_requirement) + { + if ($failed_requirement === 'member' || !$this->user->isMember()) + { + return 'msg_not_logged'; + } + elseif ($failed_requirement === 'not_member') + { + return 'msg_required_not_logged'; + } + elseif ($failed_requirement === 'manager' || $failed_requirement === 'root') + { + return 'msg_administrator_only'; + } + elseif (is_array($failed_requirement)) + { + return 'msg_required_specific_group'; + } + else + { + return 'msg_not_permitted_act'; + } + } + /** * Stop processing this module instance. * diff --git a/common/lang/en.php b/common/lang/en.php index 4bc239931..561616c76 100644 --- a/common/lang/en.php +++ b/common/lang/en.php @@ -251,7 +251,8 @@ $lang->msg_not_founded = 'Cannot find the target.'; $lang->msg_no_result = 'No results found.'; $lang->msg_fail_to_request_open = 'Failed to open your request.'; $lang->msg_invalid_format = 'Invalid Format'; -$lang->msg_not_permitted_act = 'You do not have permission to execute requested action.'; +$lang->msg_administrator_only = 'Only administrators can access this page.'; +$lang->msg_not_permitted_act = 'You do not have permission to access this page.'; $lang->msg_module_is_not_exists = 'Cannot find the page you requested. Ask your Site Admin to check the page.'; $lang->msg_module_is_not_standalone = 'Requested page cannot be executed independently.'; $lang->msg_module_class_not_found = 'Cannot find class to handle the requested action.'; diff --git a/common/lang/ko.php b/common/lang/ko.php index ab22c229c..3a5cce58b 100644 --- a/common/lang/ko.php +++ b/common/lang/ko.php @@ -251,6 +251,7 @@ $lang->msg_not_founded = '대상을 찾을 수 없습니다.'; $lang->msg_no_result = '검색 결과가 없습니다.'; $lang->msg_fail_to_request_open = '요청한 연결에 실패했습니다.'; $lang->msg_invalid_format = '잘못된 형식입니다.'; +$lang->msg_administrator_only = '관리자만 사용할 수 있는 기능입니다.'; $lang->msg_not_permitted_act = '요청한 기능을 실행할 수 있는 권한이 없습니다.'; $lang->msg_module_is_not_exists = '요청한 페이지를 찾을 수 없습니다. 사이트 관리자에게 문의해 주세요.'; $lang->msg_module_is_not_standalone = '요청한 페이지는 독립적으로 동작할 수 없습니다.'; diff --git a/modules/member/lang/en.php b/modules/member/lang/en.php index 6e2bff345..305947b29 100644 --- a/modules/member/lang/en.php +++ b/modules/member/lang/en.php @@ -201,6 +201,9 @@ $lang->msg_email_address_not_changeable = 'You cannot change your email address $lang->msg_signup_disabled = 'You are not able to sign up'; $lang->msg_already_logged = 'You have already signed up.'; $lang->msg_not_logged = 'Please log in.'; +$lang->msg_required_not_logged = 'This page is only available to users who are not logged in.'; +$lang->msg_required_specific_group = 'You need to belong to a certain group in order to access this page.'; +$lang->msg_required_minimum_level = 'YOu need to be level %d or higher in order to access this page.'; $lang->msg_insert_group_name = 'Please enter the name of group.'; $lang->msg_check_group = 'Please select the group.'; $lang->msg_not_uploaded_profile_image = 'Profile image could not be registered.'; diff --git a/modules/member/lang/ko.php b/modules/member/lang/ko.php index 26840358d..d49ba42ea 100644 --- a/modules/member/lang/ko.php +++ b/modules/member/lang/ko.php @@ -203,6 +203,9 @@ $lang->msg_email_address_not_changeable = '이메일 주소는 이 화면에서 $lang->msg_signup_disabled = '회원 가입할 수 없습니다.'; $lang->msg_already_logged = '이미 로그인되어 있습니다.'; $lang->msg_not_logged = '로그인이 필요합니다.'; +$lang->msg_required_not_logged = '로그인하지 않은 상태에서만 사용할 수 있는 기능입니다.'; +$lang->msg_required_specific_group = '이 기능을 사용할 수 있는 그룹이 제한되어 있습니다.'; +$lang->msg_required_minimum_level = '이 기능을 사용하려면 레벨 %d 이상이어야 합니다.'; $lang->msg_insert_group_name = '그룹명을 입력해 주세요.'; $lang->msg_check_group = '그룹을 선택해 주세요.'; $lang->msg_not_uploaded_profile_image = '프로필 이미지를 등록할 수 없습니다.';