ea8011f6 |
1 | <?php |
2 | |
3 | /** |
4 | * Class CRM_ACL_Test |
5 | * |
6 | * This test focuses on testing the (new) ID list-based functions: |
7 | * CRM_Contact_BAO_Contact_Permission::allowList() |
8 | * CRM_Contact_BAO_Contact_Permission::relationshipList() |
9 | * @group headless |
10 | */ |
11 | class CRM_ACL_ListTest extends CiviUnitTestCase { |
12 | |
13 | /** |
14 | * Set up function. |
15 | */ |
16 | public function setUp() { |
17 | parent::setUp(); |
18 | $this->useTransaction(TRUE); |
c1ebd31f |
19 | $this->allowedContactsACL = array(); |
ea8011f6 |
20 | } |
21 | |
22 | /** |
23 | * general test for the 'view all contacts' permission |
24 | */ |
25 | public function testViewAllPermission() { |
26 | // create test contacts |
134b2b64 |
27 | $contacts = $this->createScenarioPlain(); |
ea8011f6 |
28 | |
134b2b64 |
29 | // test WITH all permissions |
30 | CRM_Core_Config::singleton()->userPermissionClass->permissions = NULL; |
ea8011f6 |
31 | $result = CRM_Contact_BAO_Contact_Permission::allowList($contacts); |
134b2b64 |
32 | sort($result); |
33 | $this->assertEquals($result, $contacts, "Contacts should be viewable when 'view all contacts'"); |
ea8011f6 |
34 | |
35 | |
36 | // test WITH explicit permission |
37 | CRM_Core_Config::singleton()->userPermissionClass->permissions = array('view all contacts'); |
38 | $result = CRM_Contact_BAO_Contact_Permission::allowList($contacts, CRM_Core_Permission::VIEW); |
134b2b64 |
39 | sort($result); |
40 | $this->assertEquals($result, $contacts, "Contacts should be viewable when 'view all contacts'"); |
ea8011f6 |
41 | |
42 | |
43 | // test WITHOUT permission |
44 | CRM_Core_Config::singleton()->userPermissionClass->permissions = array(); |
45 | $result = CRM_Contact_BAO_Contact_Permission::allowList($contacts); |
134b2b64 |
46 | sort($result); |
ea8011f6 |
47 | $this->assertEmpty($result, "Contacts should NOT be viewable when 'view all contacts' is not set"); |
48 | } |
49 | |
50 | |
51 | /** |
52 | * general test for the 'view all contacts' permission |
53 | */ |
54 | public function testEditAllPermission() { |
55 | // create test contacts |
134b2b64 |
56 | $contacts = $this->createScenarioPlain(); |
ea8011f6 |
57 | |
58 | // test WITH explicit permission |
59 | CRM_Core_Config::singleton()->userPermissionClass->permissions = array('edit all contacts'); |
60 | $result = CRM_Contact_BAO_Contact_Permission::allowList($contacts, CRM_Core_Permission::EDIT); |
134b2b64 |
61 | sort($result); |
62 | $this->assertEquals($result, $contacts, "Contacts should be viewable when 'edit all contacts'"); |
ea8011f6 |
63 | |
64 | |
65 | // test WITHOUT permission |
66 | CRM_Core_Config::singleton()->userPermissionClass->permissions = array(); |
67 | $result = CRM_Contact_BAO_Contact_Permission::allowList($contacts); |
134b2b64 |
68 | sort($result); |
ea8011f6 |
69 | $this->assertEmpty($result, "Contacts should NOT be viewable when 'edit all contacts' is not set"); |
70 | } |
71 | |
72 | |
73 | /** |
134b2b64 |
74 | * Test access related to the 'access deleted contact' permission |
ea8011f6 |
75 | */ |
76 | public function testViewEditDeleted() { |
134b2b64 |
77 | // create test contacts |
78 | $contacts = $this->createScenarioPlain(); |
79 | |
80 | // delete one contact |
81 | $deleted_contact_id = $contacts[2]; |
82 | $this->callAPISuccess('Contact', 'create', array('id' => $deleted_contact_id, 'contact_is_deleted' => 1)); |
83 | $deleted_contact = $this->callAPISuccess('Contact', 'getsingle', array('id' => $deleted_contact_id)); |
84 | $this->assertEquals($deleted_contact['contact_is_deleted'], 1, "Contact should've been deleted"); |
85 | |
86 | // test WITH explicit permission |
ea8011f6 |
87 | CRM_Core_Config::singleton()->userPermissionClass->permissions = array('edit all contacts', 'view all contacts'); |
134b2b64 |
88 | $result = CRM_Contact_BAO_Contact_Permission::allowList($contacts, CRM_Core_Permission::EDIT); |
89 | sort($result); |
90 | $this->assertNotContains($deleted_contact_id, $result, "Deleted contacts should be excluded"); |
91 | $this->assertEquals(count($result), count($contacts)-1, "Only deleted contacts should be excluded"); |
92 | |
93 | } |
94 | |
ea8011f6 |
95 | |
134b2b64 |
96 | /** |
c1ebd31f |
97 | * Test access based on relations |
134b2b64 |
98 | * |
99 | * There should be the following permission-relationship |
100 | * contact[0] -> contact[1] -> contact[2] |
101 | */ |
102 | public function testPermissionByRelation() { |
103 | // create test scenario |
c1ebd31f |
104 | $contacts = $this->createScenarioRelations(); |
134b2b64 |
105 | |
106 | // remove all permissions |
107 | $config = CRM_Core_Config::singleton(); |
108 | $config->userPermissionClass->permissions = array(); |
109 | $permissions_to_check = array(CRM_Core_Permission::VIEW => 'View', CRM_Core_Permission::EDIT => 'Edit'); |
110 | |
111 | // run this for SIMPLE relations |
112 | $config->secondDegRelPermissions = FALSE; |
113 | $this->assertFalse($config->secondDegRelPermissions); |
114 | foreach ($permissions_to_check as $permission => $permission_label) { |
115 | $result = CRM_Contact_BAO_Contact_Permission::allowList($contacts, $permission); |
116 | sort($result); |
117 | |
118 | |
c1ebd31f |
119 | $this->assertNotContains($contacts[0], $result, "User[0] should NOT have $permission_label permission on contact[0]."); |
120 | $this->assertContains( $contacts[1], $result, "User[0] should have $permission_label permission on contact[1]."); |
121 | $this->assertNotContains($contacts[2], $result, "User[0] should NOT have $permission_label permission on contact[2]."); |
122 | $this->assertNotContains($contacts[3], $result, "User[0] should NOT have $permission_label permission on contact[3]."); |
123 | $this->assertNotContains($contacts[4], $result, "User[0] should NOT have $permission_label permission on contact[4]."); |
134b2b64 |
124 | } |
ea8011f6 |
125 | |
134b2b64 |
126 | // run this for SECOND DEGREE relations |
127 | $config->secondDegRelPermissions = TRUE; |
128 | $this->assertTrue($config->secondDegRelPermissions); |
129 | foreach ($permissions_to_check as $permission => $permission_label) { |
130 | $result = CRM_Contact_BAO_Contact_Permission::allowList($contacts, $permission); |
131 | sort($result); |
132 | |
c1ebd31f |
133 | $this->assertNotContains($contacts[0], $result, "User[0] should NOT have $permission_label permission on contact[0]."); |
134 | $this->assertContains( $contacts[1], $result, "User[0] should have $permission_label permission on contact[1]."); |
135 | $this->assertContains( $contacts[2], $result, "User[0] should have second degree $permission_label permission on contact[2]."); |
136 | $this->assertNotContains($contacts[3], $result, "User[0] should NOT have $permission_label permission on contact[3]."); |
137 | $this->assertNotContains($contacts[4], $result, "User[0] should NOT have $permission_label permission on contact[4]."); |
134b2b64 |
138 | } |
ea8011f6 |
139 | } |
140 | |
141 | |
134b2b64 |
142 | /** |
c1ebd31f |
143 | * Test access based on ACL |
134b2b64 |
144 | */ |
c1ebd31f |
145 | public function testPermissionByACL() { |
146 | $contacts = $this->createScenarioPlain(); |
147 | |
148 | // set custom hook |
149 | $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'hook_civicrm_aclWhereClause')); |
150 | |
151 | // run simple test |
152 | $permissions_to_check = array(CRM_Core_Permission::VIEW => 'View', CRM_Core_Permission::EDIT => 'Edit'); |
153 | |
154 | $this->allowedContactsACL = array($contacts[0], $contacts[1], $contacts[4]); |
155 | CRM_Core_Config::singleton()->userPermissionClass->permissions = array(); |
156 | $result = CRM_Contact_BAO_Contact_Permission::allowList($contacts); |
157 | sort($result); |
158 | |
159 | $this->assertContains( $contacts[0], $result, "User[0] should NOT have an ACL permission on contact[0]."); |
160 | $this->assertContains( $contacts[1], $result, "User[0] should have an ACL permission on contact[1]."); |
161 | $this->assertNotContains($contacts[2], $result, "User[0] should NOT have an ACL permission on contact[2]."); |
162 | $this->assertNotContains($contacts[3], $result, "User[0] should NOT have an RELATION permission on contact[3]."); |
163 | $this->assertContains( $contacts[4], $result, "User[0] should NOT have an ACL permission on contact[4]."); |
134b2b64 |
164 | } |
ea8011f6 |
165 | |
c1ebd31f |
166 | |
134b2b64 |
167 | /** |
c1ebd31f |
168 | * Test access with a mix of ACL and relationship |
134b2b64 |
169 | */ |
c1ebd31f |
170 | public function testPermissionACLvsRelationship() { |
171 | $contacts = $this->createScenarioRelations(); |
172 | |
173 | // set custom hook |
174 | $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'hook_civicrm_aclWhereClause')); |
175 | |
176 | $config = CRM_Core_Config::singleton(); |
177 | $config->userPermissionClass->permissions = array(); |
178 | $config->secondDegRelPermissions = TRUE; |
179 | |
180 | $this->allowedContactsACL = array($contacts[0], $contacts[1], $contacts[4]); |
181 | CRM_Core_Config::singleton()->userPermissionClass->permissions = array(); |
182 | $result = CRM_Contact_BAO_Contact_Permission::allowList($contacts); |
183 | sort($result); |
184 | |
185 | $this->assertContains( $contacts[0], $result, "User[0] should have an ACL permission on contact[0]."); |
186 | $this->assertContains( $contacts[1], $result, "User[0] should have an ACL permission on contact[1]."); |
187 | $this->assertContains( $contacts[2], $result, "User[0] should have second degree an relation permission on contact[2]."); |
188 | $this->assertNotContains($contacts[3], $result, "User[0] should NOT have an ACL permission on contact[3]."); |
189 | $this->assertContains( $contacts[4], $result, "User[0] should have an ACL permission on contact[4]."); |
134b2b64 |
190 | } |
ea8011f6 |
191 | |
134b2b64 |
192 | /** |
193 | * Test access related to the 'access deleted contact' permission |
194 | */ |
195 | public function _testPermissionCompare() { |
196 | // CRM_Core_Config::singleton()->userPermissionClass->permissions = array('edit all contacts', 'view all contacts'); |
197 | // $contacts = $this->createScenarioPlain(); |
198 | } |
ea8011f6 |
199 | |
200 | |
134b2b64 |
201 | /**************************************************** |
202 | * Scenario Builders * |
203 | ***************************************************/ |
ea8011f6 |
204 | |
205 | /** |
134b2b64 |
206 | * create plain test scenario, no relationships/ACLs |
ea8011f6 |
207 | */ |
134b2b64 |
208 | protected function createScenarioPlain() { |
ea8011f6 |
209 | // get logged in user |
210 | $user_id = $this->createLoggedInUser(); |
211 | $this->assertNotEmpty($user_id); |
212 | |
213 | // create test contacts |
214 | $bush_sr_id = $this->individualCreate(array('first_name' => 'George', 'middle_name' => 'W.', 'last_name' => 'Bush')); |
215 | $bush_jr_id = $this->individualCreate(array('first_name' => 'George', 'middle_name' => 'H. W.', 'last_name' => 'Bush')); |
216 | $bush_laura_id = $this->individualCreate(array('first_name' => 'Laura Lane', 'last_name' => 'Bush')); |
217 | $bush_brbra_id = $this->individualCreate(array('first_name' => 'Barbara', 'last_name' => 'Bush')); |
218 | |
134b2b64 |
219 | $contacts = array($user_id, $bush_sr_id, $bush_jr_id, $bush_laura_id, $bush_brbra_id); |
220 | sort($contacts); |
221 | return $contacts; |
222 | } |
223 | |
224 | /** |
225 | * create plain test scenario, no relationships/ACLs |
226 | */ |
c1ebd31f |
227 | protected function createScenarioRelations() { |
134b2b64 |
228 | $contacts = $this->createScenarioPlain(); |
229 | |
ea8011f6 |
230 | // create some relationships |
231 | $this->callAPISuccess('Relationship', 'create', array( |
232 | 'relationship_type_id' => 1, // CHILD OF |
134b2b64 |
233 | 'contact_id_a' => $contacts[1], |
234 | 'contact_id_b' => $contacts[0], |
235 | 'is_permission_b_a' => 1, |
236 | 'is_active' => 1, |
ea8011f6 |
237 | )); |
238 | |
239 | $this->callAPISuccess('Relationship', 'create', array( |
240 | 'relationship_type_id' => 1, // CHILD OF |
134b2b64 |
241 | 'contact_id_a' => $contacts[2], |
242 | 'contact_id_b' => $contacts[1], |
243 | 'is_permission_b_a' => 1, |
244 | 'is_active' => 1, |
ea8011f6 |
245 | )); |
246 | |
247 | // create some relationships |
248 | $this->callAPISuccess('Relationship', 'create', array( |
249 | 'relationship_type_id' => 1, // CHILD OF |
134b2b64 |
250 | 'contact_id_a' => $contacts[4], |
251 | 'contact_id_b' => $contacts[2], |
252 | 'is_permission_b_a' => 1, |
253 | 'is_active' => 1, |
ea8011f6 |
254 | )); |
255 | |
134b2b64 |
256 | return $contacts; |
ea8011f6 |
257 | } |
c1ebd31f |
258 | |
259 | /** |
260 | * ACL HOOK implementation for various tests |
261 | */ |
262 | public function hook_civicrm_aclWhereClause($type, &$tables, &$whereTables, &$contactID, &$where ) { |
263 | if (!empty($this->allowedContactsACL)) { |
264 | $contact_id_list = implode(',', $this->allowedContactsACL); |
265 | $where = " contact_a.id IN ($contact_id_list)"; |
266 | } |
267 | } |
ea8011f6 |
268 | } |