CoreUtil::checkAccess() - Accept optional argument $userID
authorTim Otten <totten@civicrm.org>
Fri, 4 Jun 2021 23:42:29 +0000 (16:42 -0700)
committerTim Otten <totten@civicrm.org>
Tue, 8 Jun 2021 04:10:02 +0000 (21:10 -0700)
Technically, there is an inheritable contract-change here - modifying
`isAuthorized()` to accept the current user ID. However, I grepped
universe for references:

```
[bknix-min:~/bknix/build/universe] grep -ri isAuthorized $( find -name Civi )
```

And all references were internal to `civicrm-core.git`.  This makes some
sense, given the available alternative extension-points
(`Civi\Api4\$ENTITY::permissions()` and `civi.api.authorize`).

Civi/Api4/Action/GetActions.php
Civi/Api4/Event/Subscriber/PermissionCheckSubscriber.php
Civi/Api4/Generic/AbstractAction.php
Civi/Api4/Generic/CheckAccessAction.php
Civi/Api4/Utils/CoreUtil.php
ext/oauth-client/Civi/Api4/Action/OAuthContactToken/OnlyModifyOwnTokensTrait.php

index e0dfbb597b3f7483f3f5539b89271fa0317eb7af..1720ee701655f33bc10c327498611366f2332fe8 100644 (file)
@@ -79,7 +79,7 @@ class GetActions extends BasicGetAction {
     try {
       if (!isset($this->_actions[$actionName]) && (!$this->_actionsToGet || in_array($actionName, $this->_actionsToGet))) {
         $action = \Civi\API\Request::create($this->getEntityName(), $actionName, ['version' => 4]);
-        if (is_object($action) && (!$this->checkPermissions || $action->isAuthorized())) {
+        if (is_object($action) && (!$this->checkPermissions || $action->isAuthorized(\CRM_Core_Session::singleton()->getLoggedInContactID()))) {
           $this->_actions[$actionName] = ['name' => $actionName];
           if ($this->_isFieldSelected('description', 'comment', 'see')) {
             $vars = ['entity' => $this->getEntityName(), 'action' => $actionName];
index 70fecac90789eb619b5976f3a131bfa8bad8a111..e71e6707e017f649ac23770c4770fbdb71bd2354 100644 (file)
@@ -40,7 +40,7 @@ class PermissionCheckSubscriber implements EventSubscriberInterface {
     /* @var \Civi\Api4\Generic\AbstractAction $apiRequest */
     $apiRequest = $event->getApiRequest();
     if ($apiRequest['version'] == 4) {
-      if (!$apiRequest->getCheckPermissions() || $apiRequest->isAuthorized()) {
+      if (!$apiRequest->getCheckPermissions() || $apiRequest->isAuthorized(\CRM_Core_Session::singleton()->getLoggedInContactID())) {
         $event->authorize();
         $event->stopPropagation();
       }
index d73a78cd5c51e6990433a92b76538643d61a343a..275bd690774a18d1fabe871c379834214a1df544 100644 (file)
@@ -389,11 +389,13 @@ abstract class AbstractAction implements \ArrayAccess {
    *
    * This function is called if checkPermissions is set to true.
    *
+   * @param int|null $userID
+   *   Contact ID of the user we are testing, or NULL for the default/active user.
    * @return bool
    */
-  public function isAuthorized() {
+  public function isAuthorized(?int $userID): bool {
     $permissions = $this->getPermissions();
-    return \CRM_Core_Permission::check($permissions);
+    return \CRM_Core_Permission::check($permissions, $userID);
   }
 
   /**
index cc26a5e6e55510295cb6a9e497f03d5251245ec6..bdbc82156701cc5263c326deab7e354c4bebdd21 100644 (file)
@@ -62,7 +62,7 @@ class CheckAccessAction extends AbstractAction {
    *
    * @return bool
    */
-  public function isAuthorized() {
+  public function isAuthorized(?int $userID): bool {
     return TRUE;
   }
 
index 3f984656a18f69ca4cc02ddc97ef87963a7adb5d..e0c6061bfa504c6fef096fe7ec21e9afa5d87909 100644 (file)
@@ -158,16 +158,18 @@ class CoreUtil {
    * @param string $entityName
    * @param string $actionName
    * @param array $record
+   * @param int|null $userID
+   *   Contact ID of the user we are testing, or NULL for the default/active user.
    * @return bool
    * @throws \API_Exception
    * @throws \CRM_Core_Exception
    * @throws \Civi\API\Exception\NotImplementedException
    * @throws \Civi\API\Exception\UnauthorizedException
    */
-  public static function checkAccess(string $entityName, string $actionName, array $record) {
+  public static function checkAccess(string $entityName, string $actionName, array $record, $userID = NULL) {
     $action = Request::create($entityName, $actionName, ['version' => 4]);
     // This checks gatekeeper permissions
-    $granted = $action->isAuthorized();
+    $granted = $action->isAuthorized($userID);
     // For get actions, just run a get and ACLs will be applied to the query.
     // It's a cheap trick and not as efficient as not running the query at all,
     // but BAO::checkAccess doesn't consistently check permissions for the "get" action.
@@ -179,14 +181,14 @@ class CoreUtil {
       $baoName = self::getBAOFromApiName($entityName);
       // CustomValue also requires the name of the group
       if ($baoName === 'CRM_Core_BAO_CustomValue') {
-        $granted = \CRM_Core_BAO_CustomValue::checkAccess($actionName, $record, NULL, $granted, substr($entityName, 7));
+        $granted = \CRM_Core_BAO_CustomValue::checkAccess($actionName, $record, $userID, $granted, substr($entityName, 7));
       }
       elseif ($baoName) {
-        $granted = $baoName::checkAccess($actionName, $record, NULL, $granted);
+        $granted = $baoName::checkAccess($actionName, $record, $userID, $granted);
       }
       // Otherwise, call the hook directly
       else {
-        \CRM_Utils_Hook::checkAccess($entityName, $actionName, $record, NULL, $granted);
+        \CRM_Utils_Hook::checkAccess($entityName, $actionName, $record, $userID, $granted);
       }
     }
     return $granted;
index 77817ab4aa156a6dfdc7dde24b9a6a293499c5a5..749b296d114f967f19bcfbe68110736a687942a0 100644 (file)
@@ -4,14 +4,13 @@ namespace Civi\Api4\Action\OAuthContactToken;
 
 trait OnlyModifyOwnTokensTrait {
 
-  public function isAuthorized(): bool {
-    if (\CRM_Core_Permission::check(['manage all OAuth contact tokens'])) {
+  public function isAuthorized(?int $loggedInContactID): bool {
+    if (\CRM_Core_Permission::check(['manage all OAuth contact tokens'], $loggedInContactID)) {
       return TRUE;
     }
-    if (!\CRM_Core_Permission::check(['manage my OAuth contact tokens'])) {
+    if (!\CRM_Core_Permission::check(['manage my OAuth contact tokens'], $loggedInContactID)) {
       return FALSE;
     }
-    $loggedInContactID = \CRM_Core_Session::singleton()->getLoggedInContactID();
     foreach ($this->where as $clause) {
       [$field, $op, $val] = $clause;
       if ($field !== 'contact_id') {