From b87406e2cd0706f292248bdd1374cc9a8e795692 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Wed, 9 Jun 2021 03:24:21 -0700 Subject: [PATCH] Expand CustomValue::_checkAccess() Before: Reports that access is available based one delegated-check for `Contact.update` After: Reports that access is available based on multiple checks: 1. The user must have access to the relevant CustomGroup (by way of ACL or perms) 2. The user must have acces to the underlying entity (by way of checkAccessDelgated) Comments: I did a bit of testing with `Custom_*.get`, and it does seem to give access to single-value CustomGroups. So I removed a comment about multi-value CustomGroups and expanded to a larger list of entities. --- CRM/Core/BAO/CustomValue.php | 40 ++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/CRM/Core/BAO/CustomValue.php b/CRM/Core/BAO/CustomValue.php index 3f1760d799..ca4d0ea388 100644 --- a/CRM/Core/BAO/CustomValue.php +++ b/CRM/Core/BAO/CustomValue.php @@ -234,24 +234,46 @@ class CRM_Core_BAO_CustomValue extends CRM_Core_DAO { * TRUE if granted. FALSE if prohibited. NULL if indeterminate. */ public static function _checkAccess(string $entityName, string $action, array $record, int $userID): ?bool { + // This check implements two rules: you must have access to the specific custom-data-group - and to the underlying record (e.g. Contact). + $groupName = substr($entityName, 0, 7) === 'Custom_' ? substr($entityName, 7) : NULL; + $extends = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $groupName, 'extends', 'name'); + $id = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $groupName, 'id', 'name'); if (!$groupName) { // $groupName is required but the function signature has to match the parent. - throw new CRM_Core_Exception('Missing required $groupName in CustomValue::checkAccess'); + throw new CRM_Core_Exception('Missing required group-name in CustomValue::checkAccess'); } - // Currently, multi-record custom data always extends Contacts - $extends = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $groupName, 'extends', 'name'); - if (!in_array($extends, ['Contact', 'Individual', 'Organization', 'Household'])) { - throw new CRM_Core_Exception("Cannot assess delegated permissions for group {$groupName}."); + + if (empty($extends) || empty($id)) { + throw new CRM_Core_Exception('Received invalid group-name in CustomValue::checkAccess'); } - $cid = $record['entity_id'] ?? NULL; - if (!$cid) { + $customGroups = [$id => $id]; + $defaultGroups = CRM_Core_Permission::customGroupAdmin() ? [$id] : []; + // FIXME: Per current onscreen help (Admin=>ACLs=>Add ACLs), CustomGroup ACLs treat VIEW and EDIT as the same. Skimming code, it appears that existing checks use VIEW. + $accessList = CRM_ACL_API::group(CRM_Core_Permission::VIEW, $userID, 'civicrm_custom_group', $customGroups, $defaultGroups); + if (empty($accessList)) { + return FALSE; + } + + $eid = $record['entity_id'] ?? NULL; + if (!$eid) { $tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $groupName, 'table_name', 'name'); - $cid = CRM_Core_DAO::singleValueQuery("SELECT entity_id FROM `$tableName` WHERE id = " . (int) $record['id']); + $eid = CRM_Core_DAO::singleValueQuery("SELECT entity_id FROM `$tableName` WHERE id = " . (int) $record['id']); } - return \Civi\Api4\Utils\CoreUtil::checkAccessDelegated('Contact', 'update', ['id' => $cid], $userID); + // Do we have access to the target record? + if (in_array($extends, ['Contact', 'Individual', 'Organization', 'Household'])) { + return \Civi\Api4\Utils\CoreUtil::checkAccessDelegated('Contact', 'update', ['id' => $eid], $userID); + } + elseif (\Civi\Api4\Utils\CoreUtil::getApiClass($extends)) { + // For most entities (Activity, Relationship, Contribution, ad nauseum), we acn just use an eponymous API. + return \Civi\Api4\Utils\CoreUtil::checkAccessDelegated($extends, 'update', ['id' => $eid], $userID); + } + else { + // Do you need to add a special case for some oddball custom-group type? + throw new CRM_Core_Exception("Cannot assess delegated permissions for group {$groupName}."); + } } } -- 2.25.1