From: Tim Otten Date: Mon, 30 Mar 2015 06:46:18 +0000 (-0700) Subject: CRM-16173 - CRM_Core_Permission_Temp, extern/cxn.php - Allow temporary permission... X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=59735506109fb50c954da4c9413cd6fd62a726fd;p=civicrm-core.git CRM-16173 - CRM_Core_Permission_Temp, extern/cxn.php - Allow temporary permission escalation --- diff --git a/CRM/Core/BAO/ConfigSetting.php b/CRM/Core/BAO/ConfigSetting.php index c2104d6712..3a5ff2a507 100644 --- a/CRM/Core/BAO/ConfigSetting.php +++ b/CRM/Core/BAO/ConfigSetting.php @@ -745,6 +745,7 @@ WHERE option_group_id = ( 'userFrameworkClass', 'userHookClass', 'userPermissionClass', + 'userPermissionTemp', 'userFrameworkURLVar', 'userFrameworkVersion', 'newBaseURL', diff --git a/CRM/Core/Config/Variables.php b/CRM/Core/Config/Variables.php index 2f4c1d4829..09f82b2ee5 100644 --- a/CRM/Core/Config/Variables.php +++ b/CRM/Core/Config/Variables.php @@ -259,6 +259,11 @@ class CRM_Core_Config_Variables extends CRM_Core_Config_Defaults { */ public $userPermissionClass = 'CRM_Core_Permission_Drupal'; + /** + * @var NULL|CRM_Core_Permission_Temp + */ + public $userPermissionTemp = NULL; + public $userFrameworkURLVar = 'q'; public $userFrameworkDSN = NULL; public $userFrameworkBaseURL = NULL; diff --git a/CRM/Core/Permission.php b/CRM/Core/Permission.php index 2159844e12..238c8ae5be 100644 --- a/CRM/Core/Permission.php +++ b/CRM/Core/Permission.php @@ -120,6 +120,8 @@ class CRM_Core_Permission { public static function check($permissions) { $permissions = (array) $permissions; + $tempPerm = CRM_Core_Config::singleton()->userPermissionTemp; + foreach ($permissions as $permission) { if (is_array($permission)) { foreach ($permission as $orPerm) { @@ -132,7 +134,10 @@ class CRM_Core_Permission { return FALSE; } else { - if (!CRM_Core_Config::singleton()->userPermissionClass->check($permission)) { + if ( + !CRM_Core_Config::singleton()->userPermissionClass->check($permission) + && !($tempPerm && $tempPerm->check($permission)) + ) { //one of our 'and' conditions has not been met return FALSE; } diff --git a/CRM/Core/Permission/Temp.php b/CRM/Core/Permission/Temp.php new file mode 100644 index 0000000000..618ade8d5d --- /dev/null +++ b/CRM/Core/Permission/Temp.php @@ -0,0 +1,115 @@ + array($perm)) + * + * @var array + */ + private $grants; + + /** + * Array ($perm => 1); + * @var array + */ + private $idx; + + /** + * Grant permissions temporarily. + * + * @param string|array $perms + * List of permissions to apply. + * @return string|int + * A handle for the grant. Useful for revoking later on. + */ + public function grant($perms) { + $perms = (array) $perms; + $id = self::$id++; + $this->grants[$id] = $perms; + $this->idx = $this->index($this->grants); + return $id; + } + + /** + * Revoke a previously granted permission. + * + * @param string|int $id + * The handle previously returned by grant(). + */ + public function revoke($id) { + unset($this->grants[$id]); + $this->idx = $this->index($this->grants); + } + + /** + * Determine if a permission has been granted. + * + * @param string $perm + * The permission name (e.g. "view all contacts"). + * @return bool + */ + public function check($perm) { + return (isset($this->idx['administer CiviCRM']) || isset($this->idx[$perm])); + } + + /** + * Generate an optimized index of granted permissions. + * + * @param array $grants + * Array(string $permName). + * @return array + * Array(string $permName => bool $granted). + */ + protected function index($grants) { + $idx = array(); + foreach ($grants as $grant) { + foreach ($grant as $perm) { + $idx[$perm] = 1; + } + } + return $idx; + } + +} diff --git a/extern/cxn.php b/extern/cxn.php index 30e6aa5c5d..407bc32ec1 100644 --- a/extern/cxn.php +++ b/extern/cxn.php @@ -33,9 +33,11 @@ CRM_Utils_System::loadBootStrap(array(), FALSE); $apiServer = new \Civi\Cxn\Rpc\ApiServer(new CRM_Cxn_CiviCxnStore()); $apiServer->setLog(new CRM_Utils_SystemLogger()); $apiServer->setRouter(function ($cxn, $entity, $action, $params) { + $SUPER_PERM = array('administer CiviCRM'); + require_once 'api/v3/utils.php'; - // Note: cxnId is authenticated before router is called. + // Note: $cxn and cxnId are authenticated before router is called. $dao = new CRM_Cxn_DAO_Cxn(); $dao->cxn_id = $cxn['cxnId']; if (empty($cxn['cxnId']) || !$dao->find(TRUE) || !$dao->cxn_id) { @@ -44,9 +46,31 @@ $apiServer->setRouter(function ($cxn, $entity, $action, $params) { if (!$dao->is_active) { return civicrm_api3_create_error('Connection is inactive'); } + if (!is_string($entity) || !is_string($action) || !is_array($params)) { + return civicrm_api3_create_error('API parameters are malformed.'); + } + if ( + empty($cxn['perm']['api']) + || !is_array($cxn['perm']['api']) + || empty($cxn['perm']['grant']) + || !(is_array($cxn['perm']['grant']) || is_string($cxn['perm']['grant'])) + ) { + return civicrm_api3_create_error('Connection has no permissions.'); + } - // FIXME: apply $dao->perm + $whitelist = \Civi\API\WhitelistRule::createAll($cxn['perm']['api']); + Civi\Core\Container::singleton() + ->get('dispatcher') + ->addSubscriber(new \Civi\API\Subscriber\WhitelistSubscriber($whitelist)); + CRM_Core_Config::singleton()->userPermissionTemp = new CRM_Core_Permission_Temp(); + if ($cxn['perm']['grant'] === '*') { + CRM_Core_Config::singleton()->userPermissionTemp->grant($SUPER_PERM); + } + else { + CRM_Core_Config::singleton()->userPermissionTemp->grant($cxn['perm']['grant']); + } + $params['check_permissions'] = 'whitelist'; return civicrm_api($entity, $action, $params); });