Ian province abbreviation patch - issue 724
[civicrm-core.git] / tests / phpunit / api / v3 / ACLPermissionTest.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
81621fee 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
e7112fa7 6 | Copyright CiviCRM LLC (c) 2004-2015 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28require_once 'CiviTest/CiviUnitTestCase.php';
29
30/**
31 * This class is intended to test ACL permission using the multisite module
32 *
7884d958 33 * @package CiviCRM_APIv3
34 * @subpackage API_Contact
6a488035 35 */
6a488035 36class api_v3_ACLPermissionTest extends CiviUnitTestCase {
4e420887 37 protected $_apiversion = 3;
4e420887 38 public $DBResetRequired = FALSE;
430ae6dd
TO
39 protected $_entity;
40
00be9182 41 public function setUp() {
6a488035
TO
42 parent::setUp();
43 $baoObj = new CRM_Core_DAO();
44 $baoObj->createTestObject('CRM_Pledge_BAO_Pledge', array(), 1, 0);
45 $baoObj->createTestObject('CRM_Core_BAO_Phone', array(), 1, 0);
6a488035
TO
46 $config = CRM_Core_Config::singleton();
47 $config->userPermissionClass->permissions = array();
48 }
7884d958 49
50 /**
51 * (non-PHPdoc)
52 * @see CiviUnitTestCase::tearDown()
53 */
00be9182 54 public function tearDown() {
e182b859 55 CRM_Utils_Hook::singleton()->reset();
6a488035 56 $tablesToTruncate = array(
7884d958 57 'civicrm_contact',
ae4bb4c9
EM
58 'civicrm_group_contact',
59 'civicrm_group',
60 'civicrm_acl',
61 'civicrm_acl_cache',
62 'civicrm_acl_entity_role',
63 'civicrm_acl_contact_cache',
64 'civicrm_contribution',
65 'civicrm_participant',
225d474b 66 'civicrm_uf_match',
6a488035
TO
67 );
68 $this->quickCleanup($tablesToTruncate);
69 $config = CRM_Core_Config::singleton();
70 unset($config->userPermissionClass->permissions);
71 }
7884d958 72
73 /**
eceb18cc 74 * Function tests that an empty where hook returns no results.
7884d958 75 */
00be9182 76 public function testContactGetNoResultsHook() {
6a488035 77 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
4e420887 78 $result = $this->callAPISuccess('contact', 'get', array(
6a488035
TO
79 'check_permissions' => 1,
80 'return' => 'display_name',
81 ));
6a488035
TO
82 $this->assertEquals(0, $result['count']);
83 }
84
1028f75e 85 /**
1a4651ba 86 * Function tests that an empty where hook returns exactly 1 result with "view my contact".
1028f75e 87 *
88 * CRM-16512 caused contacts with Edit my contact to be able to view all records.
89 */
1a4651ba 90 public function testContactGetOneResultHookWithViewMyContact() {
1028f75e 91 $this->createLoggedInUser();
92 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
93 CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM', 'view my contact');
94 $result = $this->callAPISuccess('contact', 'get', array(
95 'check_permissions' => 1,
96 'return' => 'display_name',
97 ));
1a4651ba
CW
98 $this->assertEquals(1, $result['count']);
99 }
100
101 /**
102 * Function tests that a user with "edit my contact" can edit themselves.
103 */
104 public function testContactEditHookWithEditMyContact() {
105 $this->markTestIncomplete('api acls only work with contact get so far');
106 $cid = $this->createLoggedInUser();
107 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
108 CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM', 'edit my contact');
109 $this->callAPISuccess('contact', 'create', array(
110 'check_permissions' => 1,
111 'id' => $cid,
112 ));
1028f75e 113 }
114
6a488035 115 /**
eceb18cc 116 * Function tests all results are returned.
7884d958 117 */
00be9182 118 public function testContactGetAllResultsHook() {
6a488035 119 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
4e420887 120 $result = $this->callAPISuccess('contact', 'get', array(
7884d958 121 'check_permissions' => 1,
122 'return' => 'display_name',
6a488035
TO
123 ));
124
6a488035
TO
125 $this->assertEquals(2, $result['count']);
126 }
7884d958 127
6a488035 128 /**
eceb18cc 129 * Function tests that deleted contacts are not returned.
7884d958 130 */
00be9182 131 public function testContactGetPermissionHookNoDeleted() {
f5052d4d 132 $this->callAPISuccess('contact', 'create', array('id' => 2, 'is_deleted' => 1));
6a488035 133 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
4e420887 134 $result = $this->callAPISuccess('contact', 'get', array(
7884d958 135 'check_permissions' => 1,
136 'return' => 'display_name',
6a488035 137 ));
6a488035
TO
138 $this->assertEquals(1, $result['count']);
139 }
140
141 /**
eceb18cc 142 * Test permissions limited by hook.
6a488035 143 */
00be9182 144 public function testContactGetHookLimitingHook() {
6a488035
TO
145 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlySecond'));
146
4e420887 147 $result = $this->callAPISuccess('contact', 'get', array(
6a488035
TO
148 'check_permissions' => 1,
149 'return' => 'display_name',
7884d958 150 ));
6a488035
TO
151 $this->assertEquals(1, $result['count']);
152 }
153
7884d958 154 /**
1028f75e 155 * Confirm that without check permissions we still get 2 contacts returned.
7884d958 156 */
00be9182 157 public function testContactGetHookLimitingHookDontCheck() {
4e420887 158 $result = $this->callAPISuccess('contact', 'get', array(
159 'check_permissions' => 0,
160 'return' => 'display_name',
6a488035 161 ));
6a488035
TO
162 $this->assertEquals(2, $result['count']);
163 }
7884d958 164
6a488035 165 /**
eceb18cc 166 * Check that id works as a filter.
6a488035 167 */
00be9182 168 public function testContactGetIDFilter() {
6a488035 169 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
4e420887 170 $result = $this->callAPISuccess('contact', 'get', array(
6a488035
TO
171 'sequential' => 1,
172 'id' => 2,
173 'check_permissions' => 1,
174 ));
175
6a488035
TO
176 $this->assertEquals(1, $result['count']);
177 $this->assertEquals(2, $result['id']);
178 }
179
7884d958 180 /**
eceb18cc 181 * Check that address IS returned.
7884d958 182 */
00be9182 183 public function testContactGetAddressReturned() {
7884d958 184 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlySecond'));
185 $fullresult = $this->callAPISuccess('contact', 'get', array(
186 'sequential' => 1,
187 ));
188 //return doesn't work for all keys - can't fix that here so let's skip ...
189 //prefix & suffix are inconsistent due to CRM-7929
190 // unsure about others but return doesn't work on them
191 $elementsReturnDoesntSupport = array(
7884d958 192 'prefix',
7884d958 193 'suffix',
7884d958 194 'gender',
195 'current_employer',
196 'phone_id',
197 'phone_type_id',
198 'phone',
199 'worldregion_id',
21dfd5f5 200 'world_region',
7884d958 201 );
202 $expectedReturnElements = array_diff(array_keys($fullresult['values'][0]), $elementsReturnDoesntSupport);
203 $result = $this->callAPISuccess('contact', 'get', array(
204 'check_permissions' => 1,
205 'return' => $expectedReturnElements,
206 'sequential' => 1,
207 ));
208 $this->assertEquals(1, $result['count']);
209 foreach ($expectedReturnElements as $element) {
210 $this->assertArrayHasKey($element, $result['values'][0]);
6a488035 211 }
7884d958 212 }
213
214 /**
eceb18cc 215 * Check that pledge IS not returned.
7884d958 216 */
00be9182 217 public function testContactGetPledgeIDNotReturned() {
7884d958 218 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
f5052d4d 219 $this->callAPISuccess('contact', 'get', array(
7884d958 220 'sequential' => 1,
221 ));
222 $result = $this->callAPISuccess('contact', 'get', array(
223 'check_permissions' => 1,
224 'return' => 'pledge_id',
225 'sequential' => 1,
226 ));
227 $this->assertArrayNotHasKey('pledge_id', $result['values'][0]);
228 }
6a488035 229
7884d958 230 /**
eceb18cc 231 * Check that pledge IS not an allowable filter.
7884d958 232 */
00be9182 233 public function testContactGetPledgeIDNotFiltered() {
7884d958 234 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
f5052d4d 235 $this->callAPISuccess('contact', 'get', array(
7884d958 236 'sequential' => 1,
237 ));
238 $result = $this->callAPISuccess('contact', 'get', array(
239 'check_permissions' => 1,
240 'pledge_id' => 1,
241 'sequential' => 1,
242 ));
243 $this->assertEquals(2, $result['count']);
244 }
245
246 /**
247 * Check that chaining doesn't bypass permissions
248 */
00be9182 249 public function testContactGetPledgeNotChainable() {
7884d958 250 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlySecond'));
f5052d4d 251 $this->callAPISuccess('contact', 'get', array(
7884d958 252 'sequential' => 1,
253 ));
f5052d4d 254 $this->callAPIFailure('contact', 'get', array(
6a488035 255 'check_permissions' => 1,
7884d958 256 'api.pledge.get' => 1,
6a488035 257 'sequential' => 1,
4e420887 258 ),
259 'Error in call to pledge_get : API permission check failed for pledge/get call; missing permission: access CiviCRM.'
7884d958 260 );
261 }
6a488035 262
00be9182 263 public function setupCoreACL() {
ae4bb4c9 264 $this->createLoggedInUser();
5896d037 265 $this->_permissionedDisabledGroup = $this->groupCreate(array(
92915c55
TO
266 'title' => 'pick-me-disabled',
267 'is_active' => 0,
268 'name' => 'pick-me-disabled',
269 ));
5896d037 270 $this->_permissionedGroup = $this->groupCreate(array(
92915c55
TO
271 'title' => 'pick-me-active',
272 'is_active' => 1,
273 'name' => 'pick-me-active',
274 ));
ae4bb4c9
EM
275 $this->setupACL();
276 }
5896d037 277
ae4bb4c9
EM
278 /**
279 * @dataProvider entities
280 * confirm that without check permissions we still get 2 contacts returned
1e1fdcf6 281 * @param $entity
ae4bb4c9 282 */
00be9182 283 public function testEntitiesGetHookLimitingHookNoCheck($entity) {
ae4bb4c9
EM
284 CRM_Core_Config::singleton()->userPermissionClass->permissions = array();
285 $this->setUpEntities($entity);
286 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
287 $result = $this->callAPISuccess($entity, 'get', array(
288 'check_permissions' => 0,
289 'return' => 'contact_id',
290 ));
291 $this->assertEquals(2, $result['count']);
292 }
293
294 /**
295 * @dataProvider entities
296 * confirm that without check permissions we still get 2 entities returned
1e1fdcf6 297 * @param $entity
ae4bb4c9 298 */
00be9182 299 public function testEntitiesGetCoreACLLimitingHookNoCheck($entity) {
ae4bb4c9
EM
300 $this->setupCoreACL();
301 //CRM_Core_Config::singleton()->userPermissionClass->permissions = array();
302 $this->setUpEntities($entity);
303 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
304 $result = $this->callAPISuccess($entity, 'get', array(
305 'check_permissions' => 0,
306 'return' => 'contact_id',
307 ));
308 $this->assertEquals(2, $result['count']);
309 }
5896d037 310
ae4bb4c9
EM
311 /**
312 * @dataProvider entities
313 * confirm that with check permissions we don't get entities
1e1fdcf6
EM
314 * @param $entity
315 * @throws \PHPUnit_Framework_IncompleteTestError
ae4bb4c9 316 */
00be9182 317 public function testEntitiesGetCoreACLLimitingCheck($entity) {
9730e9e3 318 $this->markTestIncomplete('this does not work in 4.4 but can be enabled in 4.5 or a security release of 4.4 including the important security fix CRM-14877');
ae4bb4c9
EM
319 $this->setupCoreACL();
320 $this->setUpEntities($entity);
ae4bb4c9
EM
321 $result = $this->callAPISuccess($entity, 'get', array(
322 'check_permissions' => 1,
323 'return' => 'contact_id',
324 ));
325 $this->assertEquals(0, $result['count']);
326 }
327
328
329 /**
330 * @dataProvider entities
331 * Function tests that an empty where hook returns no results
1028f75e 332 * @param string $entity
1e1fdcf6 333 * @throws \PHPUnit_Framework_IncompleteTestError
ae4bb4c9 334 */
00be9182 335 public function testEntityGetNoResultsHook($entity) {
ae4bb4c9
EM
336 $this->markTestIncomplete('hook acls only work with contacts so far');
337 CRM_Core_Config::singleton()->userPermissionClass->permissions = array();
338 $this->setUpEntities($entity);
339 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
340 $result = $this->callAPISuccess($entity, 'get', array(
341 'check_permission' => 1,
342 ));
343 $this->assertEquals(0, $result['count']);
344 }
345
346 /**
347 * @return array
348 */
349 public static function entities() {
6c6e6187 350 return array(array('contribution'), array('participant'));// @todo array('pledge' => 'pledge')
ae4bb4c9
EM
351 }
352
353 /**
354 * Create 2 entities
1e1fdcf6 355 * @param $entity
ae4bb4c9
EM
356 */
357 public function setUpEntities($entity) {
358 $baoObj = new CRM_Core_DAO();
5896d037 359 $baoObj->createTestObject(_civicrm_api3_get_BAO($entity), array(), 2, 0);
ae4bb4c9
EM
360 CRM_Core_Config::singleton()->userPermissionClass->permissions = array(
361 'access CiviCRM',
362 'access CiviContribute',
363 'access CiviEvent',
364 'view event participants',
365 );
366 }
367
6a488035 368 /**
eceb18cc 369 * No results returned.
1e1fdcf6
EM
370 * @param $type
371 * @param $tables
372 * @param $whereTables
373 * @param $contactID
374 * @param $where
6a488035 375 */
00be9182 376 public function aclWhereHookNoResults($type, &$tables, &$whereTables, &$contactID, &$where) {
6a488035 377 }
7884d958 378
6a488035 379 /**
eceb18cc 380 * All results returned.
f5052d4d 381 * @implements CRM_Utils_Hook::aclWhereClause
1e1fdcf6
EM
382 * @param $type
383 * @param $tables
384 * @param $whereTables
385 * @param $contactID
386 * @param $where
7884d958 387 */
00be9182 388 public function aclWhereHookAllResults($type, &$tables, &$whereTables, &$contactID, &$where) {
6a488035
TO
389 $where = " (1) ";
390 }
7884d958 391
6a488035 392 /**
eceb18cc 393 * Full results returned.
f5052d4d 394 * @implements CRM_Utils_Hook::aclWhereClause
1e1fdcf6
EM
395 * @param $type
396 * @param $tables
397 * @param $whereTables
398 * @param $contactID
399 * @param $where
7884d958 400 */
00be9182 401 public function aclWhereOnlySecond($type, &$tables, &$whereTables, &$contactID, &$where) {
6a488035
TO
402 $where = " contact_a.id > 1";
403 }
96025800 404
6a488035 405}