4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC. All rights reserved. |
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 +--------------------------------------------------------------------+
16 * @copyright CiviCRM LLC https://civicrm.org/licensing
20 namespace api\v
4\Action
;
22 use Civi\Api4\Contact
;
28 class ContactApiKeyTest
extends \api\v
4\UnitTestCase
{
30 public function testGetApiKey() {
31 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'add contacts', 'edit api keys', 'view all contacts', 'edit all contacts'];
32 $key = \CRM_Utils_String
::createRandom(16, \CRM_Utils_String
::ALPHANUMERIC
);
33 $isSafe = function ($mixed) use ($key) {
34 return strpos(json_encode($mixed), $key) === FALSE;
37 $contact = Contact
::create()
38 ->addValue('first_name', 'Api')
39 ->addValue('last_name', 'Key0')
40 ->addValue('api_key', $key)
41 ->addChain('email', Email
::create()
42 ->addValue('contact_id', '$id')
43 ->addValue('email', 'test@key.get'),
49 // With sufficient permission we should see the key
50 $result = Contact
::get()
51 ->addWhere('id', '=', $contact['id'])
52 ->addSelect('api_key')
55 $this->assertEquals($key, $result['api_key']);
56 $this->assertFalse($isSafe($result), "Should reveal secret details ($key): " . var_export($result, 1));
58 // Can also be fetched via join
60 ->addSelect('contact.api_key')
61 ->addWhere('id', '=', $contact['email']['id'])
63 $this->assertEquals($key, $email['contact.api_key']);
64 $this->assertFalse($isSafe($email), "Should reveal secret details ($key): " . var_export($email, 1));
66 // Remove permission and we should not see the key
67 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'view debug output', 'view all contacts'];
68 $result = Contact
::get()
69 ->addWhere('id', '=', $contact['id'])
70 ->addSelect('api_key')
73 $this->assertContains('api_key', $result->debug
['undefined_fields']);
74 $this->assertArrayNotHasKey('api_key', $result[0]);
75 $this->assertTrue($isSafe($result[0]), "Should NOT reveal secret details ($key): " . var_export($result[0], 1));
77 // Also not available via join
79 ->addSelect('contact.api_key')
80 ->addWhere('id', '=', $contact['email']['id'])
83 $this->assertContains('contact.api_key', $email->debug
['undefined_fields']);
84 $this->assertArrayNotHasKey('contact.api_key', $email[0]);
85 $this->assertTrue($isSafe($email[0]), "Should NOT reveal secret details ($key): " . var_export($email[0], 1));
87 $result = Contact
::get()
88 ->addWhere('id', '=', $contact['id'])
91 $this->assertArrayNotHasKey('api_key', $result);
92 $this->assertTrue($isSafe($result), "Should NOT reveal secret details ($key): " . var_export($result, 1));
95 public function testCreateWithInsufficientPermissions() {
96 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'add contacts'];
102 ->addValue('first_name', 'Api')
103 ->addValue('last_name', 'Key1')
104 ->addValue('api_key', $key)
108 catch (\Exception
$e) {
109 $error = $e->getMessage();
111 $this->assertContains('key', $error);
114 public function testGetApiKeyViaJoin() {
115 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'view all contacts'];
116 $key = \CRM_Utils_String
::createRandom(16, \CRM_Utils_String
::ALPHANUMERIC
);
117 $isSafe = function ($mixed) use ($key) {
118 if ($mixed instanceof Result
) {
119 $mixed = $mixed->getArrayCopy();
121 return strpos(json_encode($mixed), $key) === FALSE;
124 $contact = Contact
::create(FALSE)
125 ->addValue('first_name', 'Api')
126 ->addValue('last_name', 'Key0')
127 ->addValue('api_key', $key)
130 $this->assertFalse($isSafe($contact), "Should reveal secret details ($key): " . var_export($contact, 1));
133 ->addValue('email', 'foo@example.org')
134 ->addValue('contact_id', $contact['id'])
137 $result = Email
::get(FALSE)
138 ->addWhere('contact_id', '=', $contact['id'])
140 ->addSelect('contact.api_key')
143 $this->assertFalse($isSafe($result), "Should reveal secret details ($key): " . var_export($result, 1));
145 $result = Email
::get(TRUE)
146 ->addWhere('contact_id', '=', $contact['id'])
147 ->addSelect('contact.api_key')
150 $this->assertTrue($isSafe($result), "Should NOT reveal secret details ($key): " . var_export($result, 1));
153 public function testUpdateApiKey() {
154 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'edit all contacts'];
157 $contact = Contact
::create(FALSE)
158 ->addValue('first_name', 'Api')
159 ->addValue('last_name', 'Key2')
160 ->addValue('api_key', $key)
166 // Try to update the key without permissions; nothing should happen
168 ->addWhere('id', '=', $contact['id'])
169 ->addValue('api_key', "NotAllowed")
172 catch (\Exception
$e) {
173 $error = $e->getMessage();
176 $result = Contact
::get(FALSE)
177 ->addWhere('id', '=', $contact['id'])
178 ->addSelect('api_key')
182 $this->assertContains('key', $error);
184 // Assert key is still the same
185 $this->assertEquals($result['api_key'], $key);
187 // Now we can update the key
188 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'administer CiviCRM', 'edit all contacts'];
191 ->addWhere('id', '=', $contact['id'])
192 ->addValue('api_key', "IGotThePower!")
195 $result = Contact
::get()
196 ->addWhere('id', '=', $contact['id'])
197 ->addSelect('api_key')
201 // Assert key was updated
202 $this->assertEquals($result['api_key'], "IGotThePower!");
205 public function testUpdateOwnApiKey() {
206 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'edit own api keys', 'edit all contacts'];
209 $contact = Contact
::create(FALSE)
210 ->addValue('first_name', 'Api')
211 ->addValue('last_name', 'Key3')
212 ->addValue('api_key', $key)
218 // Try to update the key without permissions; nothing should happen
220 ->addWhere('id', '=', $contact['id'])
221 ->addValue('api_key', "NotAllowed")
224 catch (\Exception
$e) {
225 $error = $e->getMessage();
228 $this->assertContains('key', $error);
230 $result = Contact
::get(FALSE)
231 ->addWhere('id', '=', $contact['id'])
232 ->addSelect('api_key')
236 // Assert key is still the same
237 $this->assertEquals($result['api_key'], $key);
239 // Now we can update the key
240 \CRM_Core_Session
::singleton()->set('userID', $contact['id']);
243 ->addWhere('id', '=', $contact['id'])
244 ->addValue('api_key', "MyId!")
247 $result = Contact
::get(FALSE)
248 ->addWhere('id', '=', $contact['id'])
249 ->addSelect('api_key')
253 // Assert key was updated
254 $this->assertEquals($result['api_key'], "MyId!");
257 public function testApiKeyWithGetFields() {
258 // With sufficient permissions the field should exist
259 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'edit api keys'];
260 $this->assertArrayHasKey('api_key', \
civicrm_api4('Contact', 'getFields', [], 'name'));
261 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'administer CiviCRM'];
262 $this->assertArrayHasKey('api_key', \
civicrm_api4('Contact', 'getFields', [], 'name'));
264 // Field hidden from non-privileged users...
265 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'edit own api keys'];
266 $this->assertArrayNotHasKey('api_key', \
civicrm_api4('Contact', 'getFields', [], 'name'));
268 // ...unless you disable 'checkPermissions'
269 $this->assertArrayHasKey('api_key', \
civicrm_api4('Contact', 'getFields', ['checkPermissions' => FALSE], 'name'));