3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
19 * This is the basic permission class wrapper
21 class CRM_Core_Permission
{
24 * Static strings used to compose permissions.
29 const EDIT_GROUPS
= 'edit contacts in ', VIEW_GROUPS
= 'view contacts in ';
32 * The various type of permissions.
36 const EDIT
= 1, VIEW
= 2, DELETE
= 3, CREATE
= 4, SEARCH
= 5, ALL
= 6, ADMIN
= 7;
39 * A placeholder permission which always fails.
41 const ALWAYS_DENY_PERMISSION
= "*always deny*";
44 * A placeholder permission which always fails.
46 const ALWAYS_ALLOW_PERMISSION
= "*always allow*";
49 * Various authentication sources.
53 const AUTH_SRC_UNKNOWN
= 0, AUTH_SRC_CHECKSUM
= 1, AUTH_SRC_SITEKEY
= 2, AUTH_SRC_LOGIN
= 4;
56 * Get the current permission of this user.
59 * the permission of the user (edit or view or null)
61 public static function getPermission() {
62 $config = CRM_Core_Config
::singleton();
63 return $config->userPermissionClass
->getPermission();
67 * Given a permission string or array, check for access requirements
69 * Ex 1: Must have 'access CiviCRM'
70 * (string) 'access CiviCRM'
72 * Ex 2: Must have 'access CiviCRM' and 'access Ajax API'
73 * ['access CiviCRM', 'access Ajax API']
75 * Ex 3: Must have 'access CiviCRM' or 'access Ajax API'
77 * ['access CiviCRM', 'access Ajax API'],
80 * Ex 4: Must have 'access CiviCRM' or 'access Ajax API' AND 'access CiviEvent'
82 * ['access CiviCRM', 'access Ajax API'],
86 * Note that in permissions.php this is keyed by the action eg.
87 * (access Civi || access AJAX) && (access CiviEvent || access CiviContribute)
89 * ['access CiviCRM', 'access Ajax API'],
90 * ['access CiviEvent', 'access CiviContribute']
93 * @param string|array $permissions
94 * The permission to check as an array or string -see examples.
96 * @param int $contactId
97 * Contact id to check permissions for. Defaults to current logged-in user.
100 * true if contact has permission(s), else false
102 public static function check($permissions, $contactId = NULL) {
103 $permissions = (array) $permissions;
104 $userId = CRM_Core_BAO_UFMatch
::getUFId($contactId);
106 /** @var CRM_Core_Permission_Temp $tempPerm */
107 $tempPerm = CRM_Core_Config
::singleton()->userPermissionTemp
;
109 foreach ($permissions as $permission) {
110 if (is_array($permission)) {
111 foreach ($permission as $orPerm) {
112 if (self
::check($orPerm, $contactId)) {
113 //one of our 'or' permissions has succeeded - stop checking this permission
117 //none of our our conditions was met
121 // This is an individual permission
122 $impliedPermissions = self
::getImpliedPermissionsFor($permission);
123 $impliedPermissions[] = $permission;
124 foreach ($impliedPermissions as $permissionOption) {
125 $granted = CRM_Core_Config
::singleton()->userPermissionClass
->check($permissionOption, $userId);
126 // Call the permission_check hook to permit dynamic escalation (CRM-19256)
127 CRM_Utils_Hook
::permission_check($permissionOption, $granted, $contactId);
135 && !($tempPerm && $tempPerm->check($permission))
137 //one of our 'and' conditions has not been met
146 * Determine if any one of the permissions strings applies to current user.
148 * @param array $perms
151 public static function checkAnyPerm($perms) {
152 foreach ($perms as $perm) {
153 if (CRM_Core_Permission
::check($perm)) {
161 * Given a group/role array, check for access requirements
163 * @param array $array
164 * The group/role to check.
167 * true if yes, else false
169 public static function checkGroupRole($array) {
170 $config = CRM_Core_Config
::singleton();
171 return $config->userPermissionClass
->checkGroupRole($array);
175 * Get the permissioned where clause for the user.
178 * The type of permission needed.
179 * @param array $tables
180 * (reference ) add the tables that are needed for the select clause.
181 * @param array $whereTables
182 * (reference ) add the tables that are needed for the where clause.
185 * the group where clause for this user
187 public static function getPermissionedStaticGroupClause($type, &$tables, &$whereTables) {
188 $config = CRM_Core_Config
::singleton();
189 return $config->userPermissionClass
->getPermissionedStaticGroupClause($type, $tables, $whereTables);
193 * Get all groups from database, filtered by permissions
196 * @param string $groupType
197 * Type of group(Access/Mailing).
198 * @param bool $excludeHidden
199 * exclude hidden groups.
203 * array reference of all groups.
205 public static function group($groupType, $excludeHidden = TRUE) {
206 $config = CRM_Core_Config
::singleton();
207 return $config->userPermissionClass
->group($groupType, $excludeHidden);
213 public static function customGroupAdmin() {
216 // check if user has all powerful permission
217 // or administer civicrm permission (CRM-1905)
218 if (self
::check('access all custom data')) {
223 self
::check('administer Multiple Organizations') &&
224 self
::isMultisiteEnabled()
229 if (self
::check('administer CiviCRM')) {
242 public static function customGroup($type = CRM_Core_Permission
::VIEW
, $reset = FALSE) {
243 $customGroups = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_CustomField', 'custom_group_id',
244 ['fresh' => $reset]);
247 // check if user has all powerful permission
248 // or administer civicrm permission (CRM-1905)
249 if (self
::customGroupAdmin()) {
250 $defaultGroups = array_keys($customGroups);
253 return CRM_ACL_API
::group($type, NULL, 'civicrm_custom_group', $customGroups, $defaultGroups);
258 * @param null $prefix
263 public static function customGroupClause($type = CRM_Core_Permission
::VIEW
, $prefix = NULL, $reset = FALSE) {
264 if (self
::customGroupAdmin()) {
268 $groups = self
::customGroup($type, $reset);
269 if (empty($groups)) {
273 return "{$prefix}id IN ( " . implode(',', $groups) . ' ) ';
283 public static function ufGroupValid($gid, $type = CRM_Core_Permission
::VIEW
) {
288 $groups = self
::ufGroup($type);
289 return !empty($groups) && in_array($gid, $groups);
297 public static function ufGroup($type = CRM_Core_Permission
::VIEW
) {
298 $ufGroups = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_UFField', 'uf_group_id');
300 $allGroups = array_keys($ufGroups);
302 // check if user has all powerful permission
303 if (self
::check('profile listings and forms')) {
308 case CRM_Core_Permission
::VIEW
:
309 if (self
::check('profile view')) {
314 case CRM_Core_Permission
::CREATE
:
315 if (self
::check('profile create')) {
320 case CRM_Core_Permission
::EDIT
:
321 if (self
::check('profile edit')) {
326 case CRM_Core_Permission
::SEARCH
:
327 if (self
::check('profile listings')) {
333 return CRM_ACL_API
::group($type, NULL, 'civicrm_uf_group', $ufGroups);
338 * @param null $prefix
339 * @param bool $returnUFGroupIds
341 * @return array|string
343 public static function ufGroupClause($type = CRM_Core_Permission
::VIEW
, $prefix = NULL, $returnUFGroupIds = FALSE) {
344 $groups = self
::ufGroup($type);
345 if ($returnUFGroupIds) {
348 elseif (empty($groups)) {
352 return "{$prefix}id IN ( " . implode(',', $groups) . ' ) ';
358 * @param int $eventID
359 * @param string $context
363 public static function event($type = CRM_Core_Permission
::VIEW
, $eventID = NULL, $context = '') {
364 if (!empty($context)) {
365 if (CRM_Core_Permission
::check($context)) {
369 $events = CRM_Event_PseudoConstant
::event(NULL, TRUE);
372 // check if user has all powerful permission
373 if (self
::check('register for events')) {
374 $includeEvents = array_keys($events);
377 if ($type == CRM_Core_Permission
::VIEW
&&
378 self
::check('view event info')
380 $includeEvents = array_keys($events);
383 $permissionedEvents = CRM_ACL_API
::group($type, NULL, 'civicrm_event', $events, $includeEvents);
385 return $permissionedEvents;
387 if (!empty($permissionedEvents)) {
388 return array_search($eventID, $permissionedEvents) === FALSE ?
NULL : $eventID;
395 * @param null $prefix
399 public static function eventClause($type = CRM_Core_Permission
::VIEW
, $prefix = NULL) {
400 $events = self
::event($type);
401 if (empty($events)) {
405 return "{$prefix}id IN ( " . implode(',', $events) . ' ) ';
410 * Checks that component is enabled and optionally that user has basic perm.
412 * @param string $module
413 * Specifies the name of the CiviCRM component.
414 * @param bool $checkPermission
415 * Check not only that module is enabled, but that user has necessary
417 * @param bool $requireAllCasesPermOnCiviCase
418 * Significant only if $module == CiviCase
419 * Require "access all cases and activities", not just
420 * "access my cases and activities".
423 * Access to specified $module is granted.
425 public static function access($module, $checkPermission = TRUE, $requireAllCasesPermOnCiviCase = FALSE) {
426 $config = CRM_Core_Config
::singleton();
428 if (!in_array($module, $config->enableComponents
)) {
432 if ($checkPermission) {
435 $access_all_cases = CRM_Core_Permission
::check("access all cases and activities");
436 $access_my_cases = CRM_Core_Permission
::check("access my cases and activities");
437 return $access_all_cases ||
(!$requireAllCasesPermOnCiviCase && $access_my_cases);
440 return CRM_Core_Permission
::check("administer $module");
443 return CRM_Core_Permission
::check("access $module");
451 * Check permissions for delete and edit actions.
453 * @param string $module
456 * Action to be check across component.
461 public static function checkActionPermission($module, $action) {
462 //check delete related permissions.
463 if ($action & CRM_Core_Action
::DELETE
) {
464 $permissionName = "delete in $module";
468 'CiviEvent' => 'edit event participants',
469 'CiviMember' => 'edit memberships',
470 'CiviPledge' => 'edit pledges',
471 'CiviContribute' => 'edit contributions',
472 'CiviGrant' => 'edit grants',
473 'CiviMail' => 'access CiviMail',
474 'CiviAuction' => 'add auction items',
476 $permissionName = $editPermissions[$module] ??
NULL;
479 if ($module == 'CiviCase' && !$permissionName) {
480 return CRM_Case_BAO_Case
::accessCiviCase();
483 //check for permission.
484 return CRM_Core_Permission
::check($permissionName);
494 public static function checkMenu(&$args, $op = 'and') {
495 if (!is_array($args)) {
498 foreach ($args as $str) {
499 $res = CRM_Core_Permission
::check($str);
500 if ($op == 'or' && $res) {
503 elseif ($op == 'and' && !$res) {
507 return ($op == 'or') ?
FALSE : TRUE;
516 public static function checkMenuItem(&$item) {
517 if (!array_key_exists('access_callback', $item)) {
518 CRM_Core_Error
::backtrace();
519 throw new CRM_Core_Exception('Missing Access Callback key in menu item');
522 // if component_id is present, ensure it is enabled
523 if (isset($item['component_id']) && $item['component_id']) {
524 if (!isset(Civi
::$statics[__CLASS__
]['componentNameId'])) {
525 Civi
::$statics[__CLASS__
]['componentNameId'] = array_flip(CRM_Core_Component
::getComponentIDs());
527 $componentName = Civi
::$statics[__CLASS__
]['componentNameId'][$item['component_id']];
529 $config = CRM_Core_Config
::singleton();
530 if (is_array($config->enableComponents
) && in_array($componentName, $config->enableComponents
)) {
531 // continue with process
538 // the following is imitating drupal 6 code in includes/menu.inc
539 if (empty($item['access_callback']) ||
540 is_numeric($item['access_callback'])
542 return (bool) $item['access_callback'];
545 // check whether the following Ajax requests submitted the right key
546 // FIXME: this should be integrated into ACLs proper
547 if (CRM_Utils_Array
::value('page_type', $item) == 3) {
548 if (!CRM_Core_Key
::validate($_REQUEST['key'], $item['path'])) {
553 // check if callback is for checkMenu, if so optimize it
554 if (is_array($item['access_callback']) &&
555 $item['access_callback'][0] == 'CRM_Core_Permission' &&
556 $item['access_callback'][1] == 'checkMenu'
558 $op = CRM_Utils_Array
::value(1, $item['access_arguments'], 'and');
559 return self
::checkMenu($item['access_arguments'][0], $op);
562 return call_user_func_array($item['access_callback'], $item['access_arguments']);
568 * Include disabled components
569 * @param bool $descriptions
570 * Whether to return descriptions
574 public static function basicPermissions($all = FALSE, $descriptions = FALSE) {
575 $cacheKey = implode('-', [$all, $descriptions]);
576 if (empty(Civi
::$statics[__CLASS__
][__FUNCTION__
][$cacheKey])) {
577 Civi
::$statics[__CLASS__
][__FUNCTION__
][$cacheKey] = self
::assembleBasicPermissions($all, $descriptions);
579 return Civi
::$statics[__CLASS__
][__FUNCTION__
][$cacheKey];
584 * @param bool $descriptions
585 * whether to return descriptions
589 public static function assembleBasicPermissions($all = FALSE, $descriptions = FALSE) {
590 $config = CRM_Core_Config
::singleton();
591 $permissions = self
::getCorePermissions();
593 if (!$descriptions) {
594 foreach ($permissions as $name => $attr) {
595 $permissions[$name] = array_shift($attr);
599 $components = CRM_Core_Component
::getEnabledComponents();
602 $components = CRM_Core_Component
::getComponents();
605 foreach ($components as $comp) {
606 $perm = $comp->getPermissions($all, $descriptions);
608 $info = $comp->getInfo();
609 foreach ($perm as $p => $attr) {
611 if (!is_array($attr)) {
615 $attr[0] = $info['translatedName'] . ': ' . $attr[0];
618 $permissions[$p] = $attr;
621 $permissions[$p] = $attr[0];
627 // Add any permissions defined in hook_civicrm_permission implementations.
628 $module_permissions = $config->userPermissionClass
->getAllModulePermissions($descriptions);
629 $permissions = array_merge($permissions, $module_permissions);
636 public static function getAnonymousPermissionsWarnings() {
637 static $permissions = [];
638 if (empty($permissions)) {
640 'administer CiviCRM',
642 $components = CRM_Core_Component
::getComponents();
643 foreach ($components as $comp) {
644 if (!method_exists($comp, 'getAnonymousPermissionWarnings')) {
647 $permissions = array_merge($permissions, $comp->getAnonymousPermissionWarnings());
654 * @param $anonymous_perms
658 public static function validateForPermissionWarnings($anonymous_perms) {
659 return array_intersect($anonymous_perms, self
::getAnonymousPermissionsWarnings());
663 * Get core permissions.
667 public static function getCorePermissions() {
668 $prefix = ts('CiviCRM') . ': ';
671 $prefix . ts('add contacts'),
672 ts('Create a new contact record in CiviCRM'),
674 'view all contacts' => [
675 $prefix . ts('view all contacts'),
676 ts('View ANY CONTACT in the CiviCRM database, export contact info and perform activities such as Send Email, Phone Call, etc.'),
678 'edit all contacts' => [
679 $prefix . ts('edit all contacts'),
680 ts('View, Edit and Delete ANY CONTACT in the CiviCRM database; Create and edit relationships, tags and other info about the contacts'),
682 'view my contact' => [
683 $prefix . ts('view my contact'),
685 'edit my contact' => [
686 $prefix . ts('edit my contact'),
688 'delete contacts' => [
689 $prefix . ts('delete contacts'),
691 'access deleted contacts' => [
692 $prefix . ts('access deleted contacts'),
693 ts('Access contacts in the trash'),
695 'import contacts' => [
696 $prefix . ts('import contacts'),
697 ts('Import contacts and activities'),
699 'import SQL datasource' => [
700 $prefix . ts('import SQL datasource'),
701 ts('When importing, consume data directly from a SQL datasource'),
704 $prefix . ts('edit groups'),
705 ts('Create new groups, edit group settings (e.g. group name, visibility...), delete groups'),
707 'administer CiviCRM' => [
708 $prefix . ts('administer CiviCRM'),
709 ts('Perform all tasks in the Administer CiviCRM control panel and Import Contacts'),
711 'skip IDS check' => [
712 $prefix . ts('skip IDS check'),
713 ts('Warning: Give to trusted roles only; this permission has security implications. IDS system is bypassed for users with this permission. Prevents false errors for admin users.'),
715 'access uploaded files' => [
716 $prefix . ts('access uploaded files'),
717 ts('View / download files including images and photos'),
719 'profile listings and forms' => [
720 $prefix . ts('profile listings and forms'),
721 ts('Warning: Give to trusted roles only; this permission has privacy implications. Add/edit data in online forms and access public searchable directories.'),
723 'profile listings' => [
724 $prefix . ts('profile listings'),
725 ts('Warning: Give to trusted roles only; this permission has privacy implications. Access public searchable directories.'),
727 'profile create' => [
728 $prefix . ts('profile create'),
729 ts('Add data in a profile form.'),
732 $prefix . ts('profile edit'),
733 ts('Edit data in a profile form.'),
736 $prefix . ts('profile view'),
737 ts('View data in a profile.'),
739 'access all custom data' => [
740 $prefix . ts('access all custom data'),
741 ts('View all custom fields regardless of ACL rules'),
743 'view all activities' => [
744 $prefix . ts('view all activities'),
745 ts('View all activities (for visible contacts)'),
747 'delete activities' => [
748 $prefix . ts('Delete activities'),
750 'edit inbound email basic information' => [
751 $prefix . ts('edit inbound email basic information'),
752 ts('Edit all inbound email activities (for visible contacts) basic information. Content editing not allowed.'),
754 'edit inbound email basic information and content' => [
755 $prefix . ts('edit inbound email basic information and content'),
756 ts('Edit all inbound email activities (for visible contacts) basic information and content.'),
758 'access CiviCRM' => [
759 $prefix . ts('access CiviCRM backend and API'),
760 ts('Master control for access to the main CiviCRM backend and API. Give to trusted roles only.'),
762 'access Contact Dashboard' => [
763 $prefix . ts('access Contact Dashboard'),
764 ts('View Contact Dashboard (for themselves and visible contacts)'),
766 'translate CiviCRM' => [
767 $prefix . ts('translate CiviCRM'),
768 ts('Allow User to enable multilingual'),
771 $prefix . ts('manage tags'),
772 ts('Create and rename tags'),
774 'administer reserved groups' => [
775 $prefix . ts('administer reserved groups'),
776 ts('Edit and disable Reserved Groups (Needs Edit Groups)'),
778 'administer Tagsets' => [
779 $prefix . ts('administer Tagsets'),
781 'administer reserved tags' => [
782 $prefix . ts('administer reserved tags'),
784 'administer dedupe rules' => [
785 $prefix . ts('administer dedupe rules'),
786 ts('Create and edit rules, change the supervised and unsupervised rules'),
788 'merge duplicate contacts' => [
789 $prefix . ts('merge duplicate contacts'),
790 ts('Delete Contacts must also be granted in order for this to work.'),
792 'force merge duplicate contacts' => [
793 $prefix . ts('force merge duplicate contacts'),
794 ts('Delete Contacts must also be granted in order for this to work.'),
796 'view debug output' => [
797 $prefix . ts('view debug output'),
798 ts('View results of debug and backtrace'),
801 'view all notes' => [
802 $prefix . ts('view all notes'),
803 ts("View notes (for visible contacts) even if they're marked admin only"),
805 'add contact notes' => [
806 $prefix . ts('add contact notes'),
807 ts("Create notes for contacts"),
809 'access AJAX API' => [
810 $prefix . ts('access AJAX API'),
811 ts('Allow API access even if Access CiviCRM is not granted'),
813 'access contact reference fields' => [
814 $prefix . ts('access contact reference fields'),
815 ts('Allow entering data into contact reference fields'),
817 'create manual batch' => [
818 $prefix . ts('create manual batch'),
819 ts('Create an accounting batch (with Access to CiviContribute and View Own/All Manual Batches)'),
821 'edit own manual batches' => [
822 $prefix . ts('edit own manual batches'),
823 ts('Edit accounting batches created by user'),
825 'edit all manual batches' => [
826 $prefix . ts('edit all manual batches'),
827 ts('Edit all accounting batches'),
829 'close own manual batches' => [
830 $prefix . ts('close own manual batches'),
831 ts('Close accounting batches created by user (with Access to CiviContribute)'),
833 'close all manual batches' => [
834 $prefix . ts('close all manual batches'),
835 ts('Close all accounting batches (with Access to CiviContribute)'),
837 'reopen own manual batches' => [
838 $prefix . ts('reopen own manual batches'),
839 ts('Reopen accounting batches created by user (with Access to CiviContribute)'),
841 'reopen all manual batches' => [
842 $prefix . ts('reopen all manual batches'),
843 ts('Reopen all accounting batches (with Access to CiviContribute)'),
845 'view own manual batches' => [
846 $prefix . ts('view own manual batches'),
847 ts('View accounting batches created by user (with Access to CiviContribute)'),
849 'view all manual batches' => [
850 $prefix . ts('view all manual batches'),
851 ts('View all accounting batches (with Access to CiviContribute)'),
853 'delete own manual batches' => [
854 $prefix . ts('delete own manual batches'),
855 ts('Delete accounting batches created by user'),
857 'delete all manual batches' => [
858 $prefix . ts('delete all manual batches'),
859 ts('Delete all accounting batches'),
861 'export own manual batches' => [
862 $prefix . ts('export own manual batches'),
863 ts('Export accounting batches created by user'),
865 'export all manual batches' => [
866 $prefix . ts('export all manual batches'),
867 ts('Export all accounting batches'),
869 'administer payment processors' => [
870 $prefix . ts('administer payment processors'),
871 ts('Add, Update, or Disable Payment Processors'),
873 'edit message templates' => [
874 $prefix . ts('edit message templates'),
876 'edit system workflow message templates' => [
877 $prefix . ts('edit system workflow message templates'),
879 'edit user-driven message templates' => [
880 $prefix . ts('edit user-driven message templates'),
882 'view my invoices' => [
883 $prefix . ts('view my invoices'),
884 ts('Allow users to view/ download their own invoices'),
887 $prefix . ts('edit api keys'),
890 'edit own api keys' => [
891 $prefix . ts('edit own api keys'),
892 ts('Edit user\'s own API keys'),
895 $prefix . ts('send SMS'),
898 'administer CiviCRM system' => [
899 'label' => $prefix . ts('administer CiviCRM System'),
900 'description' => ts('Perform all system administration tasks in CiviCRM'),
902 'administer CiviCRM data' => [
903 'label' => $prefix . ts('administer CiviCRM Data'),
904 'description' => ts('Permit altering all restricted data options'),
907 if (self
::isMultisiteEnabled()) {
908 // This could arguably be moved to the multisite extension but
909 // within core it does permit editing group-organization records.
910 $permissions['administer Multiple Organizations'] = [
911 'label' => $prefix . ts('administer Multiple Organizations'),
912 'description' => ts('Administer multiple organizations. In practice this allows editing the group organization link'),
915 foreach (self
::getImpliedPermissions() as $name => $includes) {
916 foreach ($includes as $permission) {
917 $permissions[$name][] = $permissions[$permission];
924 * Get permissions implied by 'superset' permissions.
928 public static function getImpliedPermissions() {
930 'administer CiviCRM' => ['administer CiviCRM system', 'administer CiviCRM data'],
931 'administer CiviCRM data' => ['edit message templates', 'administer dedupe rules'],
932 'administer CiviCRM system' => ['edit system workflow message templates'],
937 * Get any super-permissions that imply the given permission.
939 * @param string $permission
943 public static function getImpliedPermissionsFor(string $permission) {
945 foreach (self
::getImpliedPermissions() as $superPermission => $components) {
946 if (in_array($permission, $components, TRUE)) {
947 $return[$superPermission] = $superPermission;
954 * For each entity provides an array of permissions required for each action
956 * The action is the array key, possible values:
957 * * create: applies to create (with no id in params)
958 * * update: applies to update, setvalue, create (with id in params)
959 * * get: applies to getcount, getsingle, getvalue and other gets
960 * * delete: applies to delete, replace
961 * * meta: applies to getfields, getoptions, getspec
962 * * default: catch-all for anything not declared
964 * Note: some APIs declare other actions as well
966 * Permissions should use arrays for AND and arrays of arrays for OR
967 * @see CRM_Core_Permission::check
969 * @return array of permissions
971 public static function getEntityActionPermissions() {
973 // These are the default permissions - if any entity does not declare permissions for a given action,
974 // (or the entity does not declare permissions at all) - then the action will be used from here
975 $permissions['default'] = [
976 // applies to getfields, getoptions, etc.
977 'meta' => ['access CiviCRM'],
978 // catch-all, applies to create, get, delete, etc.
979 // If an entity declares it's own 'default' action it will override this one
980 'default' => ['administer CiviCRM'],
983 // Note: Additional permissions in DynamicFKAuthorization
984 $permissions['attachment'] = [
986 ['access CiviCRM', 'access AJAX API'],
990 // Contact permissions
991 $permissions['contact'] = [
1000 // managed by query object
1002 // managed by _civicrm_api3_check_edit_permissions
1005 ['access CiviCRM', 'access AJAX API'],
1007 'duplicatecheck' => [
1010 'merge' => ['merge duplicate contacts'],
1013 $permissions['dedupe'] = [
1014 'getduplicates' => ['access CiviCRM'],
1015 'getstatistics' => ['access CiviCRM'],
1018 // CRM-16963 - Permissions for country.
1019 $permissions['country'] = [
1024 'administer CiviCRM',
1028 // Contact-related data permissions.
1029 $permissions['address'] = [
1030 // get is managed by BAO::addSelectWhereClause
1031 // create/delete are managed by _civicrm_api3_check_edit_permissions
1034 $permissions['email'] = $permissions['address'];
1035 $permissions['phone'] = $permissions['address'];
1036 $permissions['website'] = $permissions['address'];
1037 $permissions['im'] = $permissions['address'];
1038 $permissions['open_i_d'] = $permissions['address'];
1040 // Also managed by ACLs - CRM-19448
1041 $permissions['entity_tag'] = ['default' => []];
1042 $permissions['note'] = $permissions['entity_tag'];
1044 // Allow non-admins to get and create tags to support tagset widget
1045 // Delete is still reserved for admins
1046 $permissions['tag'] = [
1047 'get' => ['access CiviCRM'],
1048 'create' => ['access CiviCRM'],
1049 'update' => ['access CiviCRM'],
1052 //relationship permissions
1053 $permissions['relationship'] = [
1054 // get is managed by BAO::addSelectWhereClause
1058 'edit all contacts',
1062 'edit all contacts',
1066 // CRM-17741 - Permissions for RelationshipType.
1067 $permissions['relationship_type'] = [
1072 'administer CiviCRM',
1076 // Activity permissions
1077 $permissions['activity'] = [
1080 'delete activities',
1084 // Note that view all activities is also required within the api
1085 // if the id is not passed in. Where the id is passed in the activity
1086 // specific check functions are used and tested.
1090 'view all activities',
1093 $permissions['activity_contact'] = $permissions['activity'];
1096 $permissions['case'] = [
1103 'delete in CiviCase',
1106 'administer CiviCase',
1109 'administer CiviCase',
1112 // At minimum the user needs one of the following. Finer-grained access is controlled by CRM_Case_BAO_Case::addSelectWhereClause
1113 ['access my cases and activities', 'access all cases and activities'],
1116 $permissions['case_contact'] = $permissions['case'];
1118 $permissions['case_type'] = [
1119 'default' => ['administer CiviCase'],
1121 // nested array = OR
1122 ['access my cases and activities', 'access all cases and activities'],
1126 // Campaign permissions
1127 $permissions['campaign'] = [
1128 'get' => ['access CiviCRM'],
1130 // nested array = OR
1131 ['administer CiviCampaign', 'manage campaign'],
1134 $permissions['survey'] = $permissions['campaign'];
1136 // Financial permissions
1137 $permissions['contribution'] = [
1140 'access CiviContribute',
1144 'access CiviContribute',
1145 'delete in CiviContribute',
1147 'completetransaction' => [
1148 'edit contributions',
1152 'access CiviContribute',
1153 'edit contributions',
1156 $permissions['line_item'] = $permissions['contribution'];
1158 // Payment permissions
1159 $permissions['payment'] = [
1162 'access CiviContribute',
1166 'access CiviContribute',
1167 'delete in CiviContribute',
1171 'access CiviContribute',
1172 'edit contributions',
1176 'access CiviContribute',
1177 'edit contributions',
1181 'access CiviContribute',
1182 'edit contributions',
1185 $permissions['contribution_recur'] = $permissions['payment'];
1187 // Custom field permissions
1188 $permissions['custom_field'] = [
1190 'administer CiviCRM',
1191 'access all custom data',
1194 $permissions['custom_group'] = $permissions['custom_field'];
1196 // Event permissions
1197 $permissions['event'] = [
1206 'delete in CiviEvent',
1219 // Exception refers to dedupe_exception.
1220 $permissions['exception'] = [
1221 'default' => ['merge duplicate contacts'],
1224 $permissions['job'] = [
1225 'process_batch_merge' => ['merge duplicate contacts'],
1227 $permissions['rule_group']['get'] = [['merge duplicate contacts', 'administer CiviCRM']];
1228 // Loc block is only used for events
1229 $permissions['loc_block'] = $permissions['event'];
1231 $permissions['state_province'] = [
1237 // Price sets are shared by several components, user needs access to at least one of them
1238 $permissions['price_set'] = [
1240 ['access CiviEvent', 'access CiviContribute', 'access CiviMember'],
1243 ['access CiviCRM', 'view event info', 'make online contributions'],
1248 $permissions['file'] = [
1251 'access uploaded files',
1254 $permissions['files_by_entity'] = $permissions['file'];
1256 // Group permissions
1257 $permissions['group'] = [
1267 $permissions['group_nesting'] = $permissions['group'];
1268 $permissions['group_organization'] = $permissions['group'];
1270 //Group Contact permission
1271 $permissions['group_contact'] = [
1277 'edit all contacts',
1281 // CiviMail Permissions
1282 $civiMailBasePerms = [
1283 // To get/preview/update, one must have least one of these perms:
1284 // Mailing API implementations enforce nuances of create/approve/schedule permissions.
1287 'schedule mailings',
1290 $permissions['mailing'] = [
1298 'delete in CiviMail',
1302 ['access CiviMail', 'schedule mailings'],
1309 $permissions['mailing_group'] = $permissions['mailing'];
1310 $permissions['mailing_job'] = $permissions['mailing'];
1311 $permissions['mailing_recipients'] = $permissions['mailing'];
1313 $permissions['mailing_a_b'] = [
1321 'delete in CiviMail',
1325 ['access CiviMail', 'schedule mailings'],
1333 // Membership permissions
1334 $permissions['membership'] = [
1337 'access CiviMember',
1341 'access CiviMember',
1342 'delete in CiviMember',
1346 'access CiviMember',
1350 $permissions['membership_status'] = $permissions['membership'];
1351 $permissions['membership_type'] = $permissions['membership'];
1352 $permissions['membership_payment'] = [
1355 'access CiviMember',
1357 'access CiviContribute',
1358 'edit contributions',
1362 'access CiviMember',
1363 'delete in CiviMember',
1364 'access CiviContribute',
1365 'delete in CiviContribute',
1369 'access CiviMember',
1370 'access CiviContribute',
1374 'access CiviMember',
1376 'access CiviContribute',
1377 'edit contributions',
1381 // Participant permissions
1382 $permissions['participant'] = [
1386 'register for events',
1391 'edit event participants',
1396 'view event participants',
1401 'edit event participants',
1404 $permissions['participant_payment'] = [
1408 'register for events',
1409 'access CiviContribute',
1410 'edit contributions',
1415 'edit event participants',
1416 'access CiviContribute',
1417 'delete in CiviContribute',
1422 'view event participants',
1423 'access CiviContribute',
1428 'edit event participants',
1429 'access CiviContribute',
1430 'edit contributions',
1434 // Pledge permissions
1435 $permissions['pledge'] = [
1438 'access CiviPledge',
1443 'access CiviPledge',
1444 'delete in CiviPledge',
1448 'access CiviPledge',
1452 'access CiviPledge',
1457 //CRM-16777: Disable schedule reminder for user that have 'edit all events' and 'administer CiviCRM' permission.
1458 $permissions['action_schedule'] = [
1467 $permissions['pledge_payment'] = [
1470 'access CiviPledge',
1472 'access CiviContribute',
1473 'edit contributions',
1477 'access CiviPledge',
1478 'delete in CiviPledge',
1479 'access CiviContribute',
1480 'delete in CiviContribute',
1484 'access CiviPledge',
1485 'access CiviContribute',
1489 'access CiviPledge',
1491 'access CiviContribute',
1492 'edit contributions',
1496 // Dashboard permissions
1497 $permissions['dashboard'] = [
1502 $permissions['dashboard_contact'] = [
1508 // Profile permissions
1509 $permissions['profile'] = [
1510 // the profile will take care of this
1514 $permissions['uf_group'] = [
1518 'administer CiviCRM',
1519 'manage event profiles',
1528 'administer CiviCRM',
1529 'manage event profiles',
1533 $permissions['uf_field'] = $permissions['uf_join'] = $permissions['uf_group'];
1534 $permissions['uf_field']['delete'] = [
1537 'administer CiviCRM',
1538 'manage event profiles',
1541 $permissions['option_value'] = $permissions['uf_group'];
1542 $permissions['option_group'] = $permissions['option_value'];
1544 $permissions['custom_value'] = [
1545 'gettree' => ['access CiviCRM'],
1548 $permissions['message_template'] = [
1549 'get' => ['access CiviCRM'],
1550 'create' => [['edit message templates', 'edit user-driven message templates', 'edit system workflow message templates']],
1551 'update' => [['edit message templates', 'edit user-driven message templates', 'edit system workflow message templates']],
1554 $permissions['report_template']['update'] = 'save Report Criteria';
1555 $permissions['report_template']['create'] = 'save Report Criteria';
1556 return $permissions;
1560 * Translate an unknown action to a canonical form.
1562 * @param string $action
1565 * the standardised action name
1567 public static function getGenericAction($action) {
1568 $snippet = substr($action, 0, 3);
1569 if ($action == 'replace' ||
$snippet == 'del') {
1570 // 'Replace' is a combination of get+create+update+delete; however, the permissions
1571 // on each of those will be tested separately at runtime. This is just a sniff-test
1572 // based on the heuristic that 'delete' tends to be the most closely guarded
1573 // of the necessary permissions.
1576 elseif ($action == 'setvalue' ||
$snippet == 'upd') {
1579 elseif ($action == 'getfields' ||
$action == 'getfield' ||
$action == 'getspec' ||
$action == 'getoptions') {
1582 elseif ($snippet == 'get') {
1589 * Validate user permission across.
1590 * edit or view or with supportable acls.
1594 public static function giveMeAllACLs() {
1595 if (CRM_Core_Permission
::check('view all contacts') ||
1596 CRM_Core_Permission
::check('edit all contacts')
1601 $session = CRM_Core_Session
::singleton();
1602 $contactID = $session->get('userID');
1605 $aclPermission = self
::getPermission();
1606 if (in_array($aclPermission, [
1607 CRM_Core_Permission
::EDIT
,
1608 CRM_Core_Permission
::VIEW
,
1614 // run acl where hook and see if the user is supplying an ACL clause
1615 // that is not false
1616 $tables = $whereTables = [];
1619 CRM_Utils_Hook
::aclWhereClause(CRM_Core_Permission
::VIEW
,
1620 $tables, $whereTables,
1623 return empty($whereTables) ?
FALSE : TRUE;
1627 * Get component name from given permission.
1629 * @param string $permission
1631 * @return null|string
1632 * the name of component.
1634 public static function getComponentName($permission) {
1635 $componentName = NULL;
1636 $permission = trim($permission);
1637 if (empty($permission)) {
1638 return $componentName;
1641 static $allCompPermissions = [];
1642 if (empty($allCompPermissions)) {
1643 $components = CRM_Core_Component
::getComponents();
1644 foreach ($components as $name => $comp) {
1645 //get all permissions of each components unconditionally
1646 $allCompPermissions[$name] = $comp->getPermissions(TRUE);
1650 if (is_array($allCompPermissions)) {
1651 foreach ($allCompPermissions as $name => $permissions) {
1652 if (array_key_exists($permission, $permissions)) {
1653 $componentName = $name;
1659 return $componentName;
1663 * Get all the contact emails for users that have a specific permission.
1665 * @param string $permissionName
1666 * Name of the permission we are interested in.
1669 * a comma separated list of email addresses
1671 public static function permissionEmails($permissionName) {
1672 $config = CRM_Core_Config
::singleton();
1673 return $config->userPermissionClass
->permissionEmails($permissionName);
1677 * Get all the contact emails for users that have a specific role.
1679 * @param string $roleName
1680 * Name of the role we are interested in.
1683 * a comma separated list of email addresses
1685 public static function roleEmails($roleName) {
1686 $config = CRM_Core_Config
::singleton();
1687 return $config->userRoleClass
->roleEmails($roleName);
1693 public static function isMultisiteEnabled() {
1694 return (bool) Civi
::settings()->get('is_enabled');
1698 * Verify if the user has permission to get the invoice.
1701 * TRUE if the user has download all invoices permission or download my
1702 * invoices permission and the invoice author is the current user.
1704 public static function checkDownloadInvoice() {
1705 $cid = CRM_Core_Session
::getLoggedInContactID();
1706 if (CRM_Core_Permission
::check('access CiviContribute') ||
1707 (CRM_Core_Permission
::check('view my invoices') && $_GET['cid'] == $cid)