API v4 Grant.get fails for non-Admin users
Overview
When calling Grant.get using API v4, non-admin users always fail the authorization check, even if they have the permission "CiviGrant: access CiviGrant". Calling Grant.get using API v3 works as expected for the same user.
Reproduction steps
- Install this extension: https://github.com/AsylumSeekersCentre/au.org.asylumseekerscentre.testapigrantget (not for use on production sites!)
- Navigate to any CiviCRM page as a non-admin user
- View the CMS log as an admin and see the non-admin's authorization failure following the api3 success
- Optionally remove the try...except wrapping in the testapigrantget_civicrm_alterContent function to see the backtrace and detailed error message
Current behaviour
When calling Grant.get with API v4 for a non-admin user, it encounters an UnauthorizedException, even when the user has permission to view Grants. This affects SearchKit searches involving Grants. This is the backtrace when the try...except block is removed from the demo extension linked above:
$backTrace = #0 /var/www/basepath/sites/all/modules/civicrm/CRM/Core/Error.php(433):
CRM_Core_Error::backtrace("backTrace", TRUE) #1 /var/www/basepath/sites/all/modules/civicrm/CRM/Core/Invoke.php(39):
CRM_Core_Error::handleUnhandledException(Object(Civi\API\Exception\UnauthorizedException)) #2 /var/www/basepath/sites/all/modules/civicrm/drupal/civicrm.module(471):
CRM_Core_Invoke::invoke((Array:1)) #3 /var/www/basepath/includes/menu.inc(527):
civicrm_invoke() #4 /var/www/basepath/index.php(21):
menu_execute_active_handler() #5 {main}
This is the detailed error message (with some extra newline characters added for readability):
$Fatal Error Details = array:3 [ "message" => "Authorization failed" "code" => null "exception" => Civi\API\Exception\UnauthorizedException {#3808 -extraParams: array:1 [ "error_code" => "unauthorized" ]
#message: "Authorization failed" #code: 0 #file: "/var/www/basepath/sites/all/modules/civicrm/Civi/API/Kernel.php" #line: 223 trace: { /var/www/basepath/sites/all/modules/civicrm/Civi/API/Kernel.php:223 { › if (!$event->isAuthorized()) { › throw new \Civi\API\Exception\UnauthorizedException("Authorization failed"); › }
}
/var/www/basepath/sites/all/modules/civicrm/Civi/API/Kernel.php:147 { …}
/var/www/basepath/sites/all/modules/civicrm/Civi/Api4/Generic/AbstractAction.php:234 { …}
/var/www/basepath/CRM/extensions/au.org.asylumseekerscentre.testapigrantget/testapigrantget.php:153 { …}
/var/www/basepath/sites/all/modules/civicrm/CRM/Utils/Hook.php:283 { …}
/var/www/basepath/sites/all/modules/civicrm/CRM/Utils/Hook/DrupalBase.php:73 { …}
/var/www/basepath/sites/all/modules/civicrm/Civi/Core/CiviEventDispatcher.php:249 { …}
/var/www/basepath/sites/all/modules/civicrm/vendor/symfony/event-dispatcher/EventDispatcher.php:214 { …}
/var/www/basepath/sites/all/modules/civicrm/vendor/symfony/event-dispatcher/EventDispatcher.php:44 { …}
/var/www/basepath/sites/all/modules/civicrm/Civi/Core/CiviEventDispatcher.php:198 { …}
/var/www/basepath/sites/all/modules/civicrm/CRM/Utils/Hook.php:167 { …}
/var/www/basepath/sites/all/modules/civicrm/CRM/Utils/Hook.php:1736 { …}
/var/www/basepath/sites/all/modules/civicrm/CRM/Core/Page.php:253 { …}
/var/www/basepath/sites/all/modules/civicrm/CRM/Contact/Page/DashBoard.php:57 { …}
/var/www/basepath/sites/all/modules/civicrm/CRM/Core/Invoke.php:319 { …}
/var/www/basepath/sites/all/modules/civicrm/CRM/Core/Invoke.php:69 { …}
/var/www/basepath/sites/all/modules/civicrm/CRM/Core/Invoke.php:36 { …}
/var/www/basepath/sites/all/modules/civicrm/drupal/civicrm.module:471 { …}
/var/www/basepath/includes/menu.inc:527 { …}
/var/www/basepath/index.php:21 { …}
}
}
]
Expected behaviour
As I understand it, non-admin users with the permission "CiviGrant: access CiviGrant" should be able to view results from SearchKit searches involving Grants. They should also be able to view other pages relying on Grant.get using API v4.
The extension linked above turns every Civi page into a page relying on Grant.get using api4, and when it's installed, the CMS log should show a number of grants returned by the call instead of an error when a Civi page is loaded.
Environment information
- Browser: Chromium 90.0.4430.212 and Firefox 78.12.0esr, Debian versions
- CiviCRM: 5.46.2
-
PHP: 7.3.31-2+0
20211022.89+debian101.gbp745ac7 - CMS: Drupal 7.88
- Database: mysql Ver 15.1 Distrib 10.3.31-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
- Web Server: Apache 2.4.38-3+deb10u7
Comments
I haven't been able to determine the cause of the authorization failure, only that $event->authorized contains "null" after the auth check for API v4, whereas during the equivalent Grant.get call for API v3, $event-authorized contains "1" for the same non-admin user (on line 222 of /Civi/API/Kernel.php in both cases).