CRM-17795 - Api.create/delete - support acls for contact related entities
authorColeman Watts <coleman@civicrm.org>
Sun, 17 Jan 2016 21:12:39 +0000 (16:12 -0500)
committerColeman Watts <coleman@civicrm.org>
Mon, 18 Jan 2016 19:26:46 +0000 (14:26 -0500)
CRM/Core/DAO/permissions.php
api/v3/Address.php
api/v3/Website.php
api/v3/utils.php

index dab7812857421610d51760660d0c6f9811c6f5ff..45367c124c93f3f7da7b1f154a5f64a6bc66bd4a 100644 (file)
@@ -106,21 +106,21 @@ function _civicrm_api3_permissions($entity, $action, &$params) {
   );
 
   // Contact-related data permissions.
-  // CRM-14094 - Users can edit and delete contact-related objects using inline edit with 'edit all contacts' permission
   $permissions['address'] = array(
     // get is managed by BAO::addSelectWhereClause
-    'get' => array(),
-    'default' => array(
-      'access CiviCRM',
-      'edit all contacts',
-    ),
+    // create/delete are managed by _civicrm_api3_check_edit_permissions
+    'default' => array(),
   );
   $permissions['email'] = $permissions['address'];
   $permissions['phone'] = $permissions['address'];
   $permissions['website'] = $permissions['address'];
   $permissions['im'] = $permissions['address'];
+
   // @todo - implement CRM_Core_BAO_EntityTag::addSelectWhereClause and remove this heavy-handed restriction
-  $permissions['entity_tag'] = array('get' => array('access CiviCRM', 'view all contacts')) + $permissions['address'];
+  $permissions['entity_tag'] = array(
+    'get' => array('access CiviCRM', 'view all contacts'),
+    'default' => array('access CiviCRM', 'edit all contacts'),
+  );
   // @todo - ditto
   $permissions['note'] = $permissions['entity_tag'];
 
index 4984da2384e043adfee9a29df280484ced0b1c97..452539c6a1b07d89c30f884242cbdd060517399e 100644 (file)
@@ -34,6 +34,8 @@
 /**
  * Add an Address for a contact.
  *
+ * FIXME: Should be using basic_create util
+ *
  * @param array $params
  *   Array per getfields metadata.
  *
@@ -41,6 +43,7 @@
  *   API result array
  */
 function civicrm_api3_address_create(&$params) {
+  _civicrm_api3_check_edit_permissions('CRM_Core_BAO_Address', $params);
   /**
    * If street_parsing, street_address has to be parsed into
    * separate parts
index 50f80d020c143b86efd8bbe4f746f52e375b6e89..1eaedb214b03f0e5bc397545f73021625866cba0 100644 (file)
@@ -42,7 +42,7 @@
  */
 function civicrm_api3_website_create($params) {
   //DO NOT USE THIS FUNCTION AS THE BASIS FOR A NEW API http://wiki.civicrm.org/confluence/display/CRM/API+Architecture+Standards
-
+  _civicrm_api3_check_edit_permissions('CRM_Core_BAO_Website', $params);
   $websiteBAO = CRM_Core_BAO_Website::add($params);
   $values = array();
   _civicrm_api3_object_to_array($websiteBAO, $values[$websiteBAO->id]);
@@ -74,10 +74,10 @@ function _civicrm_api3_website_create_spec(&$params) {
  */
 function civicrm_api3_website_delete($params) {
   //DO NOT USE THIS FUNCTION AS THE BASIS FOR A NEW API http://wiki.civicrm.org/confluence/display/CRM/API+Architecture+Standards
-  $websiteID = CRM_Utils_Array::value('id', $params);
-
+  civicrm_api3_verify_mandatory($params, NULL, array('id'));
+  _civicrm_api3_check_edit_permissions('CRM_Core_BAO_Website', array('id' => $params['id']));
   $websiteDAO = new CRM_Core_DAO_Website();
-  $websiteDAO->id = $websiteID;
+  $websiteDAO->id = $params['id'];
   if ($websiteDAO->find()) {
     while ($websiteDAO->fetch()) {
       $websiteDAO->delete();
@@ -85,7 +85,7 @@ function civicrm_api3_website_delete($params) {
     }
   }
   else {
-    throw new API_Exception('Could not delete Website with id ' . $websiteID);
+    throw new API_Exception('Could not delete Website with id ' . $params['id']);
   }
 }
 
index ecae06f1bbd7331ff4cbd5d92f6b7e7f481e304b..27b51835389337950f2048b097cec49d63b47efa 100644 (file)
@@ -1353,9 +1353,11 @@ function _civicrm_api3_basic_get($bao_name, $params, $returnAsSuccess = TRUE, $e
  *   Entity - pass in if entity is non-standard & required $ids array.
  *
  * @throws API_Exception
+ * @throws \Civi\API\Exception\UnauthorizedException
  * @return array
  */
 function _civicrm_api3_basic_create($bao_name, &$params, $entity = NULL) {
+  _civicrm_api3_check_edit_permissions($bao_name, $params);
   _civicrm_api3_format_params_for_create($params, $entity);
   $args = array(&$params);
   if ($entity) {
@@ -1445,10 +1447,11 @@ function _civicrm_api3_basic_create_fallback($bao_name, &$params) {
  * @return array
  *   API result array
  * @throws API_Exception
+ * @throws \Civi\API\Exception\UnauthorizedException
  */
 function _civicrm_api3_basic_delete($bao_name, &$params) {
-
   civicrm_api3_verify_mandatory($params, NULL, array('id'));
+  _civicrm_api3_check_edit_permissions($bao_name, array('id' => $params['id']));
   $args = array(&$params['id']);
   if (method_exists($bao_name, 'del')) {
     $bao = call_user_func_array(array($bao_name, 'del'), $args);
@@ -2432,3 +2435,27 @@ function _civicrm_api3_basic_array_get($entity, $params, $records, $idCol, $fiel
 
   return civicrm_api3_create_success($matches, $params);
 }
+
+/**
+ * @param string $bao_name
+ * @param array $params
+ * @throws \Civi\API\Exception\UnauthorizedException
+ */
+function _civicrm_api3_check_edit_permissions($bao_name, $params) {
+  // For lack of something more clever, here's a whitelist of entities whos permissions
+  // are inherited from a contact record.
+  // Note, when adding here, also remember to modify _civicrm_api3_permissions()
+  $contactEntities = array(
+    'CRM_Core_BAO_Email',
+    'CRM_Core_BAO_Phone',
+    'CRM_Core_BAO_Address',
+    'CRM_Core_BAO_IM',
+    'CRM_Core_BAO_Website',
+  );
+  if (!empty($params['check_permissions']) && in_array($bao_name, $contactEntities)) {
+    $cid = !empty($params['contact_id']) ? $params['contact_id'] : CRM_Core_DAO::getFieldValue($bao_name, $params['id'], 'contact_id');
+    if (!CRM_Contact_BAO_Contact_Permission::allow($cid, CRM_Core_Permission::EDIT)) {
+      throw new \Civi\API\Exception\UnauthorizedException('Permission denied to modify contact record');
+    }
+  }
+}