Merge pull request #17163 from jitendrapurohit/core-1731
[civicrm-core.git] / tests / phpunit / api / v4 / Action / ContactApiKeyTest.php
1 <?php
2
3 /*
4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC. All rights reserved. |
6 | |
7 | This work is published under the GNU AGPLv3 license with some |
8 | permitted exceptions and without any warranty. For full license |
9 | and copyright information, see https://civicrm.org/licensing |
10 +--------------------------------------------------------------------+
11 */
12
13 /**
14 *
15 * @package CRM
16 * @copyright CiviCRM LLC https://civicrm.org/licensing
17 * $Id$
18 *
19 */
20
21
22 namespace api\v4\Action;
23
24 use Civi\Api4\Contact;
25 use Civi\Api4\Email;
26
27 /**
28 * @group headless
29 */
30 class ContactApiKeyTest extends \api\v4\UnitTestCase {
31
32 public function testGetApiKey() {
33 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'add contacts', 'edit api keys', 'view all contacts', 'edit all contacts'];
34 $key = \CRM_Utils_String::createRandom(16, \CRM_Utils_String::ALPHANUMERIC);
35 $isSafe = function ($mixed) use ($key) {
36 return strpos(json_encode($mixed), $key) === FALSE;
37 };
38
39 $contact = Contact::create()
40 ->addValue('first_name', 'Api')
41 ->addValue('last_name', 'Key0')
42 ->addValue('api_key', $key)
43 ->addChain('email', Email::create()
44 ->addValue('contact_id', '$id')
45 ->addValue('email', 'test@key.get'),
46 0
47 )
48 ->execute()
49 ->first();
50
51 // With sufficient permission we should see the key
52 $result = Contact::get()
53 ->addWhere('id', '=', $contact['id'])
54 ->addSelect('api_key')
55 ->execute()
56 ->first();
57 $this->assertEquals($key, $result['api_key']);
58 $this->assertFalse($isSafe($result), "Should reveal secret details ($key): " . var_export($result, 1));
59
60 // Can also be fetched via join
61 $email = Email::get()
62 ->addSelect('contact.api_key')
63 ->addWhere('id', '=', $contact['email']['id'])
64 ->execute()->first();
65 $this->assertEquals($key, $email['contact.api_key']);
66 $this->assertFalse($isSafe($email), "Should reveal secret details ($key): " . var_export($email, 1));
67
68 // Remove permission and we should not see the key
69 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'view debug output', 'view all contacts'];
70 $result = Contact::get()
71 ->addWhere('id', '=', $contact['id'])
72 ->addSelect('api_key')
73 ->setDebug(TRUE)
74 ->execute();
75 $this->assertContains('api_key', $result->debug['undefined_fields']);
76 $this->assertArrayNotHasKey('api_key', $result[0]);
77 $this->assertTrue($isSafe($result[0]), "Should NOT reveal secret details ($key): " . var_export($result[0], 1));
78
79 // Also not available via join
80 $email = Email::get()
81 ->addSelect('contact.api_key')
82 ->addWhere('id', '=', $contact['email']['id'])
83 ->setDebug(TRUE)
84 ->execute();
85 $this->assertContains('contact.api_key', $email->debug['undefined_fields']);
86 $this->assertArrayNotHasKey('contact.api_key', $email[0]);
87 $this->assertTrue($isSafe($email[0]), "Should NOT reveal secret details ($key): " . var_export($email[0], 1));
88
89 $result = Contact::get()
90 ->addWhere('id', '=', $contact['id'])
91 ->execute()
92 ->first();
93 $this->assertArrayNotHasKey('api_key', $result);
94 $this->assertTrue($isSafe($result), "Should NOT reveal secret details ($key): " . var_export($result, 1));
95 }
96
97 public function testCreateWithInsufficientPermissions() {
98 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'add contacts'];
99 $key = uniqid();
100
101 $error = '';
102 try {
103 Contact::create()
104 ->addValue('first_name', 'Api')
105 ->addValue('last_name', 'Key1')
106 ->addValue('api_key', $key)
107 ->execute()
108 ->first();
109 }
110 catch (\Exception $e) {
111 $error = $e->getMessage();
112 }
113 $this->assertContains('key', $error);
114 }
115
116 public function testGetApiKeyViaJoin() {
117 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'view all contacts'];
118 $key = \CRM_Utils_String::createRandom(16, \CRM_Utils_String::ALPHANUMERIC);
119 $isSafe = function ($mixed) use ($key) {
120 if ($mixed instanceof Result) {
121 $mixed = $mixed->getArrayCopy();
122 }
123 return strpos(json_encode($mixed), $key) === FALSE;
124 };
125
126 $contact = Contact::create()
127 ->setCheckPermissions(FALSE)
128 ->addValue('first_name', 'Api')
129 ->addValue('last_name', 'Key0')
130 ->addValue('api_key', $key)
131 ->execute()
132 ->first();
133 $this->assertFalse($isSafe($contact), "Should reveal secret details ($key): " . var_export($contact, 1));
134
135 Email::create()
136 ->setCheckPermissions(FALSE)
137 ->addValue('email', 'foo@example.org')
138 ->addValue('contact_id', $contact['id'])
139 ->execute();
140
141 $result = Email::get()
142 ->setCheckPermissions(FALSE)
143 ->addWhere('contact_id', '=', $contact['id'])
144 ->addSelect('email')
145 ->addSelect('contact.api_key')
146 ->execute()
147 ->first();
148 $this->assertFalse($isSafe($result), "Should reveal secret details ($key): " . var_export($result, 1));
149
150 $result = Email::get()
151 ->setCheckPermissions(TRUE)
152 ->addWhere('contact_id', '=', $contact['id'])
153 ->addSelect('contact.api_key')
154 ->execute()
155 ->first();
156 $this->assertTrue($isSafe($result), "Should NOT reveal secret details ($key): " . var_export($result, 1));
157 }
158
159 public function testUpdateApiKey() {
160 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'edit all contacts'];
161 $key = uniqid();
162
163 $contact = Contact::create()
164 ->setCheckPermissions(FALSE)
165 ->addValue('first_name', 'Api')
166 ->addValue('last_name', 'Key2')
167 ->addValue('api_key', $key)
168 ->execute()
169 ->first();
170
171 $error = '';
172 try {
173 // Try to update the key without permissions; nothing should happen
174 Contact::update()
175 ->addWhere('id', '=', $contact['id'])
176 ->addValue('api_key', "NotAllowed")
177 ->execute();
178 }
179 catch (\Exception $e) {
180 $error = $e->getMessage();
181 }
182
183 $result = Contact::get()
184 ->setCheckPermissions(FALSE)
185 ->addWhere('id', '=', $contact['id'])
186 ->addSelect('api_key')
187 ->execute()
188 ->first();
189
190 $this->assertContains('key', $error);
191
192 // Assert key is still the same
193 $this->assertEquals($result['api_key'], $key);
194
195 // Now we can update the key
196 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'administer CiviCRM', 'edit all contacts'];
197
198 Contact::update()
199 ->addWhere('id', '=', $contact['id'])
200 ->addValue('api_key', "IGotThePower!")
201 ->execute();
202
203 $result = Contact::get()
204 ->addWhere('id', '=', $contact['id'])
205 ->addSelect('api_key')
206 ->execute()
207 ->first();
208
209 // Assert key was updated
210 $this->assertEquals($result['api_key'], "IGotThePower!");
211 }
212
213 public function testUpdateOwnApiKey() {
214 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'edit own api keys', 'edit all contacts'];
215 $key = uniqid();
216
217 $contact = Contact::create()
218 ->setCheckPermissions(FALSE)
219 ->addValue('first_name', 'Api')
220 ->addValue('last_name', 'Key3')
221 ->addValue('api_key', $key)
222 ->execute()
223 ->first();
224
225 $error = '';
226 try {
227 // Try to update the key without permissions; nothing should happen
228 Contact::update()
229 ->addWhere('id', '=', $contact['id'])
230 ->addValue('api_key', "NotAllowed")
231 ->execute();
232 }
233 catch (\Exception $e) {
234 $error = $e->getMessage();
235 }
236
237 $this->assertContains('key', $error);
238
239 $result = Contact::get()
240 ->setCheckPermissions(FALSE)
241 ->addWhere('id', '=', $contact['id'])
242 ->addSelect('api_key')
243 ->execute()
244 ->first();
245
246 // Assert key is still the same
247 $this->assertEquals($result['api_key'], $key);
248
249 // Now we can update the key
250 \CRM_Core_Session::singleton()->set('userID', $contact['id']);
251
252 Contact::update()
253 ->addWhere('id', '=', $contact['id'])
254 ->addValue('api_key', "MyId!")
255 ->execute();
256
257 $result = Contact::get()
258 ->setCheckPermissions(FALSE)
259 ->addWhere('id', '=', $contact['id'])
260 ->addSelect('api_key')
261 ->execute()
262 ->first();
263
264 // Assert key was updated
265 $this->assertEquals($result['api_key'], "MyId!");
266 }
267
268 public function testApiKeyWithGetFields() {
269 // With sufficient permissions the field should exist
270 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'edit api keys'];
271 $this->assertArrayHasKey('api_key', \civicrm_api4('Contact', 'getFields', [], 'name'));
272 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'administer CiviCRM'];
273 $this->assertArrayHasKey('api_key', \civicrm_api4('Contact', 'getFields', [], 'name'));
274
275 // Field hidden from non-privileged users...
276 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'edit own api keys'];
277 $this->assertArrayNotHasKey('api_key', \civicrm_api4('Contact', 'getFields', [], 'name'));
278
279 // ...unless you disable 'checkPermissions'
280 $this->assertArrayHasKey('api_key', \civicrm_api4('Contact', 'getFields', ['checkPermissions' => FALSE], 'name'));
281 }
282
283 }