tests/phpunit/** - Remove unnecessary "require_once" statements
[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
6a488035
TO
28/**
29 * This class is intended to test ACL permission using the multisite module
30 *
7884d958 31 * @package CiviCRM_APIv3
32 * @subpackage API_Contact
6a488035 33 */
6a488035 34class api_v3_ACLPermissionTest extends CiviUnitTestCase {
4e420887 35 protected $_apiversion = 3;
4e420887 36 public $DBResetRequired = FALSE;
430ae6dd 37 protected $_entity;
c16ed19b 38 protected $allowedContactId = 0;
430ae6dd 39
00be9182 40 public function setUp() {
6a488035
TO
41 parent::setUp();
42 $baoObj = new CRM_Core_DAO();
43 $baoObj->createTestObject('CRM_Pledge_BAO_Pledge', array(), 1, 0);
44 $baoObj->createTestObject('CRM_Core_BAO_Phone', array(), 1, 0);
6a488035
TO
45 $config = CRM_Core_Config::singleton();
46 $config->userPermissionClass->permissions = array();
47 }
7884d958 48
49 /**
50 * (non-PHPdoc)
51 * @see CiviUnitTestCase::tearDown()
52 */
00be9182 53 public function tearDown() {
e182b859 54 CRM_Utils_Hook::singleton()->reset();
6a488035 55 $tablesToTruncate = array(
7884d958 56 'civicrm_contact',
ae4bb4c9
EM
57 'civicrm_group_contact',
58 'civicrm_group',
59 'civicrm_acl',
60 'civicrm_acl_cache',
61 'civicrm_acl_entity_role',
62 'civicrm_acl_contact_cache',
63 'civicrm_contribution',
64 'civicrm_participant',
225d474b 65 'civicrm_uf_match',
6a488035
TO
66 );
67 $this->quickCleanup($tablesToTruncate);
68 $config = CRM_Core_Config::singleton();
69 unset($config->userPermissionClass->permissions);
70 }
7884d958 71
72 /**
eceb18cc 73 * Function tests that an empty where hook returns no results.
7884d958 74 */
00be9182 75 public function testContactGetNoResultsHook() {
6a488035 76 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
4e420887 77 $result = $this->callAPISuccess('contact', 'get', array(
6a488035
TO
78 'check_permissions' => 1,
79 'return' => 'display_name',
80 ));
6a488035
TO
81 $this->assertEquals(0, $result['count']);
82 }
83
1028f75e 84 /**
1a4651ba 85 * Function tests that an empty where hook returns exactly 1 result with "view my contact".
1028f75e 86 *
87 * CRM-16512 caused contacts with Edit my contact to be able to view all records.
88 */
1a4651ba 89 public function testContactGetOneResultHookWithViewMyContact() {
1028f75e 90 $this->createLoggedInUser();
91 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
92 CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM', 'view my contact');
93 $result = $this->callAPISuccess('contact', 'get', array(
94 'check_permissions' => 1,
95 'return' => 'display_name',
96 ));
1a4651ba
CW
97 $this->assertEquals(1, $result['count']);
98 }
99
100 /**
101 * Function tests that a user with "edit my contact" can edit themselves.
102 */
103 public function testContactEditHookWithEditMyContact() {
1a4651ba
CW
104 $cid = $this->createLoggedInUser();
105 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
106 CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM', 'edit my contact');
107 $this->callAPISuccess('contact', 'create', array(
108 'check_permissions' => 1,
109 'id' => $cid,
110 ));
1028f75e 111 }
112
c16ed19b
CW
113 /**
114 * Ensure contact permissions extend to related entities like email
115 */
116 public function testRelatedEntityPermissions() {
0a61b6e2 117 $this->createLoggedInUser();
c16ed19b
CW
118 $disallowedContact = $this->individualCreate(array(), 0);
119 $this->allowedContactId = $this->individualCreate(array(), 1);
120 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlyOne'));
121 CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM');
122 $testEntities = array(
0a61b6e2
CW
123 'Email' => array('email' => 'null@nothing', 'location_type_id' => 1),
124 'Phone' => array('phone' => '123456', 'location_type_id' => 1),
125 'IM' => array('name' => 'hello', 'location_type_id' => 1),
c16ed19b 126 'Website' => array('url' => 'http://test'),
0a61b6e2 127 'Address' => array('street_address' => '123 Sesame St.', 'location_type_id' => 1),
c16ed19b
CW
128 );
129 foreach ($testEntities as $entity => $params) {
130 $params += array(
131 'contact_id' => $disallowedContact,
132 'check_permissions' => 1,
133 );
134 // We should be prevented from getting or creating entities for a contact we don't have permission for
135 $this->callAPIFailure($entity, 'create', $params);
136 $results = $this->callAPISuccess($entity, 'get', array('contact_id' => $disallowedContact, 'check_permissions' => 1));
137 $this->assertEquals(0, $results['count']);
138
139 // We should be allowed to create and get for contacts we do have permission on
140 $params['contact_id'] = $this->allowedContactId;
141 $this->callAPISuccess($entity, 'create', $params);
142 $results = $this->callAPISuccess($entity, 'get', array('contact_id' => $this->allowedContactId, 'check_permissions' => 1));
143 $this->assertGreaterThan(0, $results['count']);
144 }
145 }
146
6a488035 147 /**
eceb18cc 148 * Function tests all results are returned.
7884d958 149 */
00be9182 150 public function testContactGetAllResultsHook() {
6a488035 151 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
4e420887 152 $result = $this->callAPISuccess('contact', 'get', array(
7884d958 153 'check_permissions' => 1,
154 'return' => 'display_name',
6a488035
TO
155 ));
156
6a488035
TO
157 $this->assertEquals(2, $result['count']);
158 }
7884d958 159
6a488035 160 /**
eceb18cc 161 * Function tests that deleted contacts are not returned.
7884d958 162 */
00be9182 163 public function testContactGetPermissionHookNoDeleted() {
f5052d4d 164 $this->callAPISuccess('contact', 'create', array('id' => 2, 'is_deleted' => 1));
6a488035 165 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
4e420887 166 $result = $this->callAPISuccess('contact', 'get', array(
7884d958 167 'check_permissions' => 1,
168 'return' => 'display_name',
6a488035 169 ));
6a488035
TO
170 $this->assertEquals(1, $result['count']);
171 }
172
173 /**
eceb18cc 174 * Test permissions limited by hook.
6a488035 175 */
00be9182 176 public function testContactGetHookLimitingHook() {
6a488035
TO
177 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlySecond'));
178
4e420887 179 $result = $this->callAPISuccess('contact', 'get', array(
6a488035
TO
180 'check_permissions' => 1,
181 'return' => 'display_name',
7884d958 182 ));
6a488035
TO
183 $this->assertEquals(1, $result['count']);
184 }
185
7884d958 186 /**
1028f75e 187 * Confirm that without check permissions we still get 2 contacts returned.
7884d958 188 */
00be9182 189 public function testContactGetHookLimitingHookDontCheck() {
4e420887 190 $result = $this->callAPISuccess('contact', 'get', array(
191 'check_permissions' => 0,
192 'return' => 'display_name',
6a488035 193 ));
6a488035
TO
194 $this->assertEquals(2, $result['count']);
195 }
7884d958 196
6a488035 197 /**
eceb18cc 198 * Check that id works as a filter.
6a488035 199 */
00be9182 200 public function testContactGetIDFilter() {
6a488035 201 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
4e420887 202 $result = $this->callAPISuccess('contact', 'get', array(
6a488035
TO
203 'sequential' => 1,
204 'id' => 2,
205 'check_permissions' => 1,
206 ));
207
6a488035
TO
208 $this->assertEquals(1, $result['count']);
209 $this->assertEquals(2, $result['id']);
210 }
211
7884d958 212 /**
eceb18cc 213 * Check that address IS returned.
7884d958 214 */
00be9182 215 public function testContactGetAddressReturned() {
7884d958 216 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlySecond'));
217 $fullresult = $this->callAPISuccess('contact', 'get', array(
218 'sequential' => 1,
219 ));
220 //return doesn't work for all keys - can't fix that here so let's skip ...
221 //prefix & suffix are inconsistent due to CRM-7929
222 // unsure about others but return doesn't work on them
223 $elementsReturnDoesntSupport = array(
7884d958 224 'prefix',
7884d958 225 'suffix',
7884d958 226 'gender',
227 'current_employer',
228 'phone_id',
229 'phone_type_id',
230 'phone',
231 'worldregion_id',
21dfd5f5 232 'world_region',
7884d958 233 );
234 $expectedReturnElements = array_diff(array_keys($fullresult['values'][0]), $elementsReturnDoesntSupport);
235 $result = $this->callAPISuccess('contact', 'get', array(
236 'check_permissions' => 1,
237 'return' => $expectedReturnElements,
238 'sequential' => 1,
239 ));
240 $this->assertEquals(1, $result['count']);
241 foreach ($expectedReturnElements as $element) {
242 $this->assertArrayHasKey($element, $result['values'][0]);
6a488035 243 }
7884d958 244 }
245
246 /**
eceb18cc 247 * Check that pledge IS not returned.
7884d958 248 */
00be9182 249 public function testContactGetPledgeIDNotReturned() {
7884d958 250 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
f5052d4d 251 $this->callAPISuccess('contact', 'get', array(
7884d958 252 'sequential' => 1,
253 ));
254 $result = $this->callAPISuccess('contact', 'get', array(
255 'check_permissions' => 1,
256 'return' => 'pledge_id',
257 'sequential' => 1,
258 ));
259 $this->assertArrayNotHasKey('pledge_id', $result['values'][0]);
260 }
6a488035 261
7884d958 262 /**
eceb18cc 263 * Check that pledge IS not an allowable filter.
7884d958 264 */
00be9182 265 public function testContactGetPledgeIDNotFiltered() {
7884d958 266 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
f5052d4d 267 $this->callAPISuccess('contact', 'get', array(
7884d958 268 'sequential' => 1,
269 ));
270 $result = $this->callAPISuccess('contact', 'get', array(
271 'check_permissions' => 1,
272 'pledge_id' => 1,
273 'sequential' => 1,
274 ));
275 $this->assertEquals(2, $result['count']);
276 }
277
278 /**
279 * Check that chaining doesn't bypass permissions
280 */
00be9182 281 public function testContactGetPledgeNotChainable() {
7884d958 282 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlySecond'));
f5052d4d 283 $this->callAPISuccess('contact', 'get', array(
7884d958 284 'sequential' => 1,
285 ));
f5052d4d 286 $this->callAPIFailure('contact', 'get', array(
6a488035 287 'check_permissions' => 1,
7884d958 288 'api.pledge.get' => 1,
6a488035 289 'sequential' => 1,
4e420887 290 ),
291 'Error in call to pledge_get : API permission check failed for pledge/get call; missing permission: access CiviCRM.'
7884d958 292 );
293 }
6a488035 294
00be9182 295 public function setupCoreACL() {
ae4bb4c9 296 $this->createLoggedInUser();
5896d037 297 $this->_permissionedDisabledGroup = $this->groupCreate(array(
92915c55
TO
298 'title' => 'pick-me-disabled',
299 'is_active' => 0,
300 'name' => 'pick-me-disabled',
301 ));
5896d037 302 $this->_permissionedGroup = $this->groupCreate(array(
92915c55
TO
303 'title' => 'pick-me-active',
304 'is_active' => 1,
305 'name' => 'pick-me-active',
306 ));
ae4bb4c9
EM
307 $this->setupACL();
308 }
5896d037 309
ae4bb4c9
EM
310 /**
311 * @dataProvider entities
312 * confirm that without check permissions we still get 2 contacts returned
1e1fdcf6 313 * @param $entity
ae4bb4c9 314 */
00be9182 315 public function testEntitiesGetHookLimitingHookNoCheck($entity) {
ae4bb4c9
EM
316 CRM_Core_Config::singleton()->userPermissionClass->permissions = array();
317 $this->setUpEntities($entity);
318 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
319 $result = $this->callAPISuccess($entity, 'get', array(
320 'check_permissions' => 0,
321 'return' => 'contact_id',
322 ));
323 $this->assertEquals(2, $result['count']);
324 }
325
326 /**
327 * @dataProvider entities
328 * confirm that without check permissions we still get 2 entities returned
1e1fdcf6 329 * @param $entity
ae4bb4c9 330 */
00be9182 331 public function testEntitiesGetCoreACLLimitingHookNoCheck($entity) {
ae4bb4c9
EM
332 $this->setupCoreACL();
333 //CRM_Core_Config::singleton()->userPermissionClass->permissions = array();
334 $this->setUpEntities($entity);
335 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
336 $result = $this->callAPISuccess($entity, 'get', array(
337 'check_permissions' => 0,
338 'return' => 'contact_id',
339 ));
340 $this->assertEquals(2, $result['count']);
341 }
5896d037 342
ae4bb4c9
EM
343 /**
344 * @dataProvider entities
345 * confirm that with check permissions we don't get entities
1e1fdcf6
EM
346 * @param $entity
347 * @throws \PHPUnit_Framework_IncompleteTestError
ae4bb4c9 348 */
00be9182 349 public function testEntitiesGetCoreACLLimitingCheck($entity) {
9730e9e3 350 $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
351 $this->setupCoreACL();
352 $this->setUpEntities($entity);
ae4bb4c9
EM
353 $result = $this->callAPISuccess($entity, 'get', array(
354 'check_permissions' => 1,
355 'return' => 'contact_id',
356 ));
357 $this->assertEquals(0, $result['count']);
358 }
359
ae4bb4c9
EM
360 /**
361 * @dataProvider entities
362 * Function tests that an empty where hook returns no results
1028f75e 363 * @param string $entity
1e1fdcf6 364 * @throws \PHPUnit_Framework_IncompleteTestError
ae4bb4c9 365 */
00be9182 366 public function testEntityGetNoResultsHook($entity) {
ae4bb4c9
EM
367 $this->markTestIncomplete('hook acls only work with contacts so far');
368 CRM_Core_Config::singleton()->userPermissionClass->permissions = array();
369 $this->setUpEntities($entity);
370 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
371 $result = $this->callAPISuccess($entity, 'get', array(
372 'check_permission' => 1,
373 ));
374 $this->assertEquals(0, $result['count']);
375 }
376
377 /**
378 * @return array
379 */
380 public static function entities() {
6c6e6187 381 return array(array('contribution'), array('participant'));// @todo array('pledge' => 'pledge')
ae4bb4c9
EM
382 }
383
384 /**
385 * Create 2 entities
1e1fdcf6 386 * @param $entity
ae4bb4c9
EM
387 */
388 public function setUpEntities($entity) {
389 $baoObj = new CRM_Core_DAO();
5896d037 390 $baoObj->createTestObject(_civicrm_api3_get_BAO($entity), array(), 2, 0);
ae4bb4c9
EM
391 CRM_Core_Config::singleton()->userPermissionClass->permissions = array(
392 'access CiviCRM',
393 'access CiviContribute',
394 'access CiviEvent',
395 'view event participants',
396 );
397 }
398
6a488035 399 /**
eceb18cc 400 * No results returned.
24602943 401 *
c16ed19b 402 * @implements CRM_Utils_Hook::aclWhereClause
24602943 403 *
404 * @param string $type
405 * @param array $tables
406 * @param array $whereTables
407 * @param int $contactID
408 * @param string $where
6a488035 409 */
00be9182 410 public function aclWhereHookNoResults($type, &$tables, &$whereTables, &$contactID, &$where) {
6a488035 411 }
7884d958 412
6a488035 413 /**
eceb18cc 414 * All results returned.
24602943 415 *
f5052d4d 416 * @implements CRM_Utils_Hook::aclWhereClause
24602943 417 *
418 * @param string $type
419 * @param array $tables
420 * @param array $whereTables
421 * @param int $contactID
422 * @param string $where
7884d958 423 */
00be9182 424 public function aclWhereHookAllResults($type, &$tables, &$whereTables, &$contactID, &$where) {
6a488035
TO
425 $where = " (1) ";
426 }
7884d958 427
6a488035 428 /**
c16ed19b 429 * All but first results returned.
f5052d4d 430 * @implements CRM_Utils_Hook::aclWhereClause
1e1fdcf6
EM
431 * @param $type
432 * @param $tables
433 * @param $whereTables
434 * @param $contactID
435 * @param $where
7884d958 436 */
00be9182 437 public function aclWhereOnlySecond($type, &$tables, &$whereTables, &$contactID, &$where) {
6a488035
TO
438 $where = " contact_a.id > 1";
439 }
96025800 440
c16ed19b
CW
441 /**
442 * Only specified contact returned.
443 * @implements CRM_Utils_Hook::aclWhereClause
444 * @param $type
445 * @param $tables
446 * @param $whereTables
447 * @param $contactID
448 * @param $where
449 */
450 public function aclWhereOnlyOne($type, &$tables, &$whereTables, &$contactID, &$where) {
451 $where = " contact_a.id = " . $this->allowedContactId;
452 }
453
6a488035 454}