CRM-17795 - Api.contact.create/delete - support acls for contacts
authorColeman Watts <coleman@civicrm.org>
Mon, 18 Jan 2016 18:06:26 +0000 (13:06 -0500)
committerColeman Watts <coleman@civicrm.org>
Mon, 18 Jan 2016 19:26:53 +0000 (14:26 -0500)
CRM/Core/DAO/permissions.php
api/v3/Contact.php
tests/phpunit/api/v3/ACLPermissionTest.php

index 45367c124c93f3f7da7b1f154a5f64a6bc66bd4a..11af708f3a75435ac56ebe3d4f177792621c9305 100644 (file)
@@ -86,10 +86,8 @@ function _civicrm_api3_permissions($entity, $action, &$params) {
     ),
     // managed by query object
     'get' => array(),
-    'update' => array(
-      'access CiviCRM',
-      'edit all contacts',
-    ),
+    // managed by _civicrm_api3_check_edit_permissions
+    'update' => array(),
     'getquick' => array(
       array('access CiviCRM', 'access AJAX API'),
     ),
index c0b08bdde9875e142aec28404f36c0fe38da3bb1..3dfe80f5a74322308adfed114f792b3ed120a5ce 100644 (file)
  *   API Result Array
  */
 function civicrm_api3_contact_create($params) {
-
   $contactID = CRM_Utils_Array::value('contact_id', $params, CRM_Utils_Array::value('id', $params));
+
+  if ($contactID && !empty($params['check_permissions']) && !CRM_Contact_BAO_Contact_Permission::allow($contactID, CRM_Core_Permission::EDIT)) {
+    throw new \Civi\API\Exception\UnauthorizedException('Permission denied to modify contact record');
+  }
+
   $dupeCheck = CRM_Utils_Array::value('dupe_check', $params, FALSE);
   $values = _civicrm_api3_contact_check_params($params, $dupeCheck);
   if ($values) {
@@ -368,13 +372,17 @@ function _civicrm_api3_contact_get_supportanomalies(&$params, &$options) {
  * @param array $params
  *   input parameters per getfields
  *
+ * @throws \Civi\API\Exception\UnauthorizedException
  * @return array
  *   API Result Array
  */
 function civicrm_api3_contact_delete($params) {
-
   $contactID = CRM_Utils_Array::value('id', $params);
 
+  if (!empty($params['check_permissions']) && !CRM_Contact_BAO_Contact_Permission::allow($contactID, CRM_Core_Permission::DELETE)) {
+    throw new \Civi\API\Exception\UnauthorizedException('Permission denied to modify contact record');
+  }
+
   $session = CRM_Core_Session::singleton();
   if ($contactID == $session->get('userID')) {
     return civicrm_api3_create_error('This contact record is linked to the currently logged in user account - and cannot be deleted.');
index f74de1077bd744a33c53dd5d7b1fa08ad14578a6..065e567a70014802b2c1faba9d348c4bfa277a62 100644 (file)
@@ -37,6 +37,7 @@ class api_v3_ACLPermissionTest extends CiviUnitTestCase {
   protected $_apiversion = 3;
   public $DBResetRequired = FALSE;
   protected $_entity;
+  protected $allowedContactId = 0;
 
   public function setUp() {
     parent::setUp();
@@ -102,7 +103,6 @@ class api_v3_ACLPermissionTest extends CiviUnitTestCase {
    * Function tests that a user with "edit my contact" can edit themselves.
    */
   public function testContactEditHookWithEditMyContact() {
-    $this->markTestIncomplete('api acls only work with contact get so far');
     $cid = $this->createLoggedInUser();
     $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
     CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM', 'edit my contact');
@@ -112,6 +112,39 @@ class api_v3_ACLPermissionTest extends CiviUnitTestCase {
     ));
   }
 
+  /**
+   * Ensure contact permissions extend to related entities like email
+   */
+  public function testRelatedEntityPermissions() {
+    $disallowedContact = $this->individualCreate(array(), 0);
+    $this->allowedContactId = $this->individualCreate(array(), 1);
+    $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlyOne'));
+    CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM');
+    $testEntities = array(
+      'Email' => array('email' => 'null@nothing'),
+      'Phone' => array('phone' => '123456'),
+      'IM' => array('name' => 'hello'),
+      'Website' => array('url' => 'http://test'),
+      'Address' => array('street_address' => '123 Sesame St.'),
+    );
+    foreach ($testEntities as $entity => $params) {
+      $params += array(
+        'contact_id' => $disallowedContact,
+        'check_permissions' => 1,
+      );
+      // We should be prevented from getting or creating entities for a contact we don't have permission for
+      $this->callAPIFailure($entity, 'create', $params);
+      $results = $this->callAPISuccess($entity, 'get', array('contact_id' => $disallowedContact, 'check_permissions' => 1));
+      $this->assertEquals(0, $results['count']);
+
+      // We should be allowed to create and get for contacts we do have permission on
+      $params['contact_id'] = $this->allowedContactId;
+      $this->callAPISuccess($entity, 'create', $params);
+      $results = $this->callAPISuccess($entity, 'get', array('contact_id' => $this->allowedContactId, 'check_permissions' => 1));
+      $this->assertGreaterThan(0, $results['count']);
+    }
+  }
+
   /**
    * Function tests all results are returned.
    */
@@ -367,6 +400,7 @@ class api_v3_ACLPermissionTest extends CiviUnitTestCase {
 
   /**
    * No results returned.
+   * @implements CRM_Utils_Hook::aclWhereClause
    * @param $type
    * @param $tables
    * @param $whereTables
@@ -390,7 +424,7 @@ class api_v3_ACLPermissionTest extends CiviUnitTestCase {
   }
 
   /**
-   * Full results returned.
+   * All but first results returned.
    * @implements CRM_Utils_Hook::aclWhereClause
    * @param $type
    * @param $tables
@@ -402,4 +436,17 @@ class api_v3_ACLPermissionTest extends CiviUnitTestCase {
     $where = " contact_a.id > 1";
   }
 
+  /**
+   * Only specified contact returned.
+   * @implements CRM_Utils_Hook::aclWhereClause
+   * @param $type
+   * @param $tables
+   * @param $whereTables
+   * @param $contactID
+   * @param $where
+   */
+  public function aclWhereOnlyOne($type, &$tables, &$whereTables, &$contactID, &$where) {
+    $where = " contact_a.id = " . $this->allowedContactId;
+  }
+
 }