Fix issue 4853: implied permission not applied
authorRich Lott / Artful Robot <code.commits@artfulrobot.uk>
Tue, 12 Dec 2023 14:34:29 +0000 (14:34 +0000)
committerRich Lott / Artful Robot <code.commits@artfulrobot.uk>
Tue, 12 Dec 2023 14:58:23 +0000 (14:58 +0000)
CRM/Core/Permission/Base.php
CRM/Core/Permission/Standalone.php
ext/standaloneusers/Civi/Standalone/Security.php

index 2ecb7e553daa73ab448a0275f5b0cca40ae88146..ad59662886f55c21ccfc41f3f73e996d75bba12c 100644 (file)
@@ -154,7 +154,7 @@ class CRM_Core_Permission_Base {
 
       $groups = CRM_Core_PseudoConstant::allGroup($groupType, $excludeHidden);
 
-      if ($this->check('edit all contacts')) {
+      if (CRM_Core_Permission::check('edit all contacts')) {
         // this is the most powerful permission, so we return
         // immediately rather than dilute it further
         $this->_editAdminUser = $this->_viewAdminUser = TRUE;
@@ -163,7 +163,7 @@ class CRM_Core_Permission_Base {
         Civi::$statics['CRM_ACL_API']['viewPermissionedGroups_' . $domainId . '_' . $userId][$groupKey] = $groups;
         return Civi::$statics['CRM_ACL_API']['viewPermissionedGroups_' . $domainId . '_' . $userId][$groupKey];
       }
-      elseif ($this->check('view all contacts')) {
+      elseif (CRM_Core_Permission::check('view all contacts')) {
         $this->_viewAdminUser = TRUE;
         $this->_viewPermission = TRUE;
         Civi::$statics['CRM_ACL_API']['viewPermissionedGroups_' . $domainId . '_' . $userId][$groupKey] = $groups;
index a201f698aab5bace667a9e015441cd25e3c32282..bcc62bb2d662b8a77422c946ade5c82e89571780 100644 (file)
  */
 
 /**
+ * Permissions class for Standalone.
+ *
+ * Note that CRM_Core_Permission_Base is unrelated to CRM_Core_Permission
+ * This class, and the _Base class, is to do with CMS permissions, whereas
+ * the CRM_Core_Permission class deals with Civi-specific permissioning.
  *
  */
 class CRM_Core_Permission_Standalone extends CRM_Core_Permission_Base {
@@ -27,7 +32,13 @@ class CRM_Core_Permission_Standalone extends CRM_Core_Permission_Base {
   public $permissions = NULL;
 
   /**
-   * Given a permission string, check for access requirements
+   * Given a permission string, check for access requirements.
+   *
+   * Note this differs from CRM_Core_Permission::check() which handles
+   * composite permissions (ORs etc) and Contacts.
+   *
+   * Some codepaths assume to be able to check a permission through this class;
+   * others through CRM_Core_Permission::check().
    *
    * @param string $str
    *   The permission to check.
@@ -37,19 +48,7 @@ class CRM_Core_Permission_Standalone extends CRM_Core_Permission_Base {
    *   true if yes, else false
    */
   public function check($str, $userId = NULL) {
-    if ($str == CRM_Core_Permission::ALWAYS_DENY_PERMISSION) {
-      return FALSE;
-    }
-    if ($str == CRM_Core_Permission::ALWAYS_ALLOW_PERMISSION) {
-      return TRUE;
-    }
-
-    if (class_exists(\Civi\Standalone\Security::class)) {
-      return \Civi\Standalone\Security::singleton()->checkPermission($this, $str, $userId);
-    }
-
-    // return the stubbed permission (defaulting to true if the array is missing)
-    return isset($this->permissions) && is_array($this->permissions) ? in_array($str, $this->permissions) : TRUE;
+    return \Civi\Standalone\Security::singleton()->checkPermission($this, $str, $userId);
   }
 
 }
index 7b5313a0c7878cb9ee957038a8952684168a34e9..f9fca9b68b90a222cf4a1f427faff4673ef24fb0 100644 (file)
@@ -34,15 +34,21 @@ class Security {
    * @param string $permissionName
    *   The permission to check.
    *
-   * @param int $userID
-   *   It is unclear if this typehint is true: The Drupal version has a default NULL!
+   * @param ?int $userID
+   *   The User ID (not ContactID) to check. If NULL, current logged in user.
    *
    * @return bool
    *   true if yes, else false
    */
-  public function checkPermission(\CRM_Core_Permission_Standalone $permissionObject, string $permissionName, $userID) {
+  public function checkPermission(\CRM_Core_Permission_Standalone $permissionObject, string $permissionName, ?int $userID = NULL) {
+    if ($permissionName == \CRM_Core_Permission::ALWAYS_DENY_PERMISSION) {
+      return FALSE;
+    }
+    if ($permissionName == \CRM_Core_Permission::ALWAYS_ALLOW_PERMISSION) {
+      return TRUE;
+    }
 
-    // I think null means the current logged-in user
+    // NULL means the current logged-in user
     $userID = $userID ?? $this->getLoggedInUfID() ?? 0;
 
     if (!isset(\Civi::$statics[__METHOD__][$userID])) {
@@ -67,6 +73,8 @@ class Security {
       else {
         $permissionsPerRoleApiCall->addWhere('name', '=', 'everyone');
       }
+
+      // Get and cache an array of permission names for this user.
       $permissions = array_unique(array_merge(...$permissionsPerRoleApiCall->execute()->column('permissions')));
       \Civi::$statics[__METHOD__][$userID] = $permissions;
     }