Merge pull request #6289 from yashodha/CRM-16879
[civicrm-core.git] / tests / phpunit / api / v3 / ACLPermissionTest.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
39de6fd5 4 | CiviCRM version 4.6 |
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
85 /**
eceb18cc 86 * Function tests all results are returned.
7884d958 87 */
00be9182 88 public function testContactGetAllResultsHook() {
6a488035 89 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
4e420887 90 $result = $this->callAPISuccess('contact', 'get', array(
7884d958 91 'check_permissions' => 1,
92 'return' => 'display_name',
6a488035
TO
93 ));
94
6a488035
TO
95 $this->assertEquals(2, $result['count']);
96 }
7884d958 97
6a488035 98 /**
eceb18cc 99 * Function tests that deleted contacts are not returned.
7884d958 100 */
00be9182 101 public function testContactGetPermissionHookNoDeleted() {
f5052d4d 102 $this->callAPISuccess('contact', 'create', array('id' => 2, 'is_deleted' => 1));
6a488035 103 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
4e420887 104 $result = $this->callAPISuccess('contact', 'get', array(
7884d958 105 'check_permissions' => 1,
106 'return' => 'display_name',
6a488035 107 ));
6a488035
TO
108 $this->assertEquals(1, $result['count']);
109 }
110
111 /**
eceb18cc 112 * Test permissions limited by hook.
6a488035 113 */
00be9182 114 public function testContactGetHookLimitingHook() {
6a488035
TO
115 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlySecond'));
116
4e420887 117 $result = $this->callAPISuccess('contact', 'get', array(
6a488035
TO
118 'check_permissions' => 1,
119 'return' => 'display_name',
7884d958 120 ));
6a488035
TO
121 $this->assertEquals(1, $result['count']);
122 }
123
7884d958 124 /**
100fef9d 125 * Confirm that without check permissions we still get 2 contacts returned
7884d958 126 */
00be9182 127 public function testContactGetHookLimitingHookDontCheck() {
4e420887 128 $result = $this->callAPISuccess('contact', 'get', array(
129 'check_permissions' => 0,
130 'return' => 'display_name',
6a488035 131 ));
6a488035
TO
132 $this->assertEquals(2, $result['count']);
133 }
7884d958 134
6a488035 135 /**
eceb18cc 136 * Check that id works as a filter.
6a488035 137 */
00be9182 138 public function testContactGetIDFilter() {
6a488035 139 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
4e420887 140 $result = $this->callAPISuccess('contact', 'get', array(
6a488035
TO
141 'sequential' => 1,
142 'id' => 2,
143 'check_permissions' => 1,
144 ));
145
6a488035
TO
146 $this->assertEquals(1, $result['count']);
147 $this->assertEquals(2, $result['id']);
148 }
149
7884d958 150 /**
eceb18cc 151 * Check that address IS returned.
7884d958 152 */
00be9182 153 public function testContactGetAddressReturned() {
7884d958 154 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlySecond'));
155 $fullresult = $this->callAPISuccess('contact', 'get', array(
156 'sequential' => 1,
157 ));
158 //return doesn't work for all keys - can't fix that here so let's skip ...
159 //prefix & suffix are inconsistent due to CRM-7929
160 // unsure about others but return doesn't work on them
161 $elementsReturnDoesntSupport = array(
7884d958 162 'prefix',
7884d958 163 'suffix',
7884d958 164 'gender',
165 'current_employer',
166 'phone_id',
167 'phone_type_id',
168 'phone',
169 'worldregion_id',
21dfd5f5 170 'world_region',
7884d958 171 );
172 $expectedReturnElements = array_diff(array_keys($fullresult['values'][0]), $elementsReturnDoesntSupport);
173 $result = $this->callAPISuccess('contact', 'get', array(
174 'check_permissions' => 1,
175 'return' => $expectedReturnElements,
176 'sequential' => 1,
177 ));
178 $this->assertEquals(1, $result['count']);
179 foreach ($expectedReturnElements as $element) {
180 $this->assertArrayHasKey($element, $result['values'][0]);
6a488035 181 }
7884d958 182 }
183
184 /**
eceb18cc 185 * Check that pledge IS not returned.
7884d958 186 */
00be9182 187 public function testContactGetPledgeIDNotReturned() {
7884d958 188 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
f5052d4d 189 $this->callAPISuccess('contact', 'get', array(
7884d958 190 'sequential' => 1,
191 ));
192 $result = $this->callAPISuccess('contact', 'get', array(
193 'check_permissions' => 1,
194 'return' => 'pledge_id',
195 'sequential' => 1,
196 ));
197 $this->assertArrayNotHasKey('pledge_id', $result['values'][0]);
198 }
6a488035 199
7884d958 200 /**
eceb18cc 201 * Check that pledge IS not an allowable filter.
7884d958 202 */
00be9182 203 public function testContactGetPledgeIDNotFiltered() {
7884d958 204 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
f5052d4d 205 $this->callAPISuccess('contact', 'get', array(
7884d958 206 'sequential' => 1,
207 ));
208 $result = $this->callAPISuccess('contact', 'get', array(
209 'check_permissions' => 1,
210 'pledge_id' => 1,
211 'sequential' => 1,
212 ));
213 $this->assertEquals(2, $result['count']);
214 }
215
216 /**
217 * Check that chaining doesn't bypass permissions
218 */
00be9182 219 public function testContactGetPledgeNotChainable() {
7884d958 220 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlySecond'));
f5052d4d 221 $this->callAPISuccess('contact', 'get', array(
7884d958 222 'sequential' => 1,
223 ));
f5052d4d 224 $this->callAPIFailure('contact', 'get', array(
6a488035 225 'check_permissions' => 1,
7884d958 226 'api.pledge.get' => 1,
6a488035 227 'sequential' => 1,
4e420887 228 ),
229 'Error in call to pledge_get : API permission check failed for pledge/get call; missing permission: access CiviCRM.'
7884d958 230 );
231 }
6a488035 232
00be9182 233 public function setupCoreACL() {
ae4bb4c9 234 $this->createLoggedInUser();
5896d037 235 $this->_permissionedDisabledGroup = $this->groupCreate(array(
92915c55
TO
236 'title' => 'pick-me-disabled',
237 'is_active' => 0,
238 'name' => 'pick-me-disabled',
239 ));
5896d037 240 $this->_permissionedGroup = $this->groupCreate(array(
92915c55
TO
241 'title' => 'pick-me-active',
242 'is_active' => 1,
243 'name' => 'pick-me-active',
244 ));
ae4bb4c9
EM
245 $this->setupACL();
246 }
5896d037 247
ae4bb4c9
EM
248 /**
249 * @dataProvider entities
250 * confirm that without check permissions we still get 2 contacts returned
1e1fdcf6 251 * @param $entity
ae4bb4c9 252 */
00be9182 253 public function testEntitiesGetHookLimitingHookNoCheck($entity) {
ae4bb4c9
EM
254 CRM_Core_Config::singleton()->userPermissionClass->permissions = array();
255 $this->setUpEntities($entity);
256 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
257 $result = $this->callAPISuccess($entity, 'get', array(
258 'check_permissions' => 0,
259 'return' => 'contact_id',
260 ));
261 $this->assertEquals(2, $result['count']);
262 }
263
264 /**
265 * @dataProvider entities
266 * confirm that without check permissions we still get 2 entities returned
1e1fdcf6 267 * @param $entity
ae4bb4c9 268 */
00be9182 269 public function testEntitiesGetCoreACLLimitingHookNoCheck($entity) {
ae4bb4c9
EM
270 $this->setupCoreACL();
271 //CRM_Core_Config::singleton()->userPermissionClass->permissions = array();
272 $this->setUpEntities($entity);
273 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
274 $result = $this->callAPISuccess($entity, 'get', array(
275 'check_permissions' => 0,
276 'return' => 'contact_id',
277 ));
278 $this->assertEquals(2, $result['count']);
279 }
5896d037 280
ae4bb4c9
EM
281 /**
282 * @dataProvider entities
283 * confirm that with check permissions we don't get entities
1e1fdcf6
EM
284 * @param $entity
285 * @throws \PHPUnit_Framework_IncompleteTestError
ae4bb4c9 286 */
00be9182 287 public function testEntitiesGetCoreACLLimitingCheck($entity) {
9730e9e3 288 $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
289 $this->setupCoreACL();
290 $this->setUpEntities($entity);
ae4bb4c9
EM
291 $result = $this->callAPISuccess($entity, 'get', array(
292 'check_permissions' => 1,
293 'return' => 'contact_id',
294 ));
295 $this->assertEquals(0, $result['count']);
296 }
297
298
299 /**
300 * @dataProvider entities
301 * Function tests that an empty where hook returns no results
1e1fdcf6
EM
302 * @param $entity
303 * @throws \PHPUnit_Framework_IncompleteTestError
ae4bb4c9 304 */
00be9182 305 public function testEntityGetNoResultsHook($entity) {
ae4bb4c9
EM
306 $this->markTestIncomplete('hook acls only work with contacts so far');
307 CRM_Core_Config::singleton()->userPermissionClass->permissions = array();
308 $this->setUpEntities($entity);
309 $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults'));
310 $result = $this->callAPISuccess($entity, 'get', array(
311 'check_permission' => 1,
312 ));
313 $this->assertEquals(0, $result['count']);
314 }
315
316 /**
317 * @return array
318 */
319 public static function entities() {
6c6e6187 320 return array(array('contribution'), array('participant'));// @todo array('pledge' => 'pledge')
ae4bb4c9
EM
321 }
322
323 /**
324 * Create 2 entities
1e1fdcf6 325 * @param $entity
ae4bb4c9
EM
326 */
327 public function setUpEntities($entity) {
328 $baoObj = new CRM_Core_DAO();
5896d037 329 $baoObj->createTestObject(_civicrm_api3_get_BAO($entity), array(), 2, 0);
ae4bb4c9
EM
330 CRM_Core_Config::singleton()->userPermissionClass->permissions = array(
331 'access CiviCRM',
332 'access CiviContribute',
333 'access CiviEvent',
334 'view event participants',
335 );
336 }
337
6a488035 338 /**
eceb18cc 339 * No results returned.
1e1fdcf6
EM
340 * @param $type
341 * @param $tables
342 * @param $whereTables
343 * @param $contactID
344 * @param $where
6a488035 345 */
00be9182 346 public function aclWhereHookNoResults($type, &$tables, &$whereTables, &$contactID, &$where) {
6a488035 347 }
7884d958 348
6a488035 349 /**
eceb18cc 350 * All results returned.
f5052d4d 351 * @implements CRM_Utils_Hook::aclWhereClause
1e1fdcf6
EM
352 * @param $type
353 * @param $tables
354 * @param $whereTables
355 * @param $contactID
356 * @param $where
7884d958 357 */
00be9182 358 public function aclWhereHookAllResults($type, &$tables, &$whereTables, &$contactID, &$where) {
6a488035
TO
359 $where = " (1) ";
360 }
7884d958 361
6a488035 362 /**
eceb18cc 363 * Full results returned.
f5052d4d 364 * @implements CRM_Utils_Hook::aclWhereClause
1e1fdcf6
EM
365 * @param $type
366 * @param $tables
367 * @param $whereTables
368 * @param $contactID
369 * @param $where
7884d958 370 */
00be9182 371 public function aclWhereOnlySecond($type, &$tables, &$whereTables, &$contactID, &$where) {
6a488035
TO
372 $where = " contact_a.id > 1";
373 }
96025800 374
6a488035 375}