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
22 namespace api\v
4\Action
;
24 use Civi\Api4\Contact
;
30 class ContactApiKeyTest
extends \api\v
4\UnitTestCase
{
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;
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'),
51 // With sufficient permission we should see the key
52 $result = Contact
::get()
53 ->addWhere('id', '=', $contact['id'])
54 ->addSelect('api_key')
57 $this->assertEquals($key, $result['api_key']);
58 $this->assertFalse($isSafe($result), "Should reveal secret details ($key): " . var_export($result, 1));
60 // Can also be fetched via join
62 ->addSelect('contact.api_key')
63 ->addWhere('id', '=', $contact['email']['id'])
65 $this->assertEquals($key, $email['contact.api_key']);
66 $this->assertFalse($isSafe($email), "Should reveal secret details ($key): " . var_export($email, 1));
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')
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));
79 // Also not available via join
81 ->addSelect('contact.api_key')
82 ->addWhere('id', '=', $contact['email']['id'])
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));
89 $result = Contact
::get()
90 ->addWhere('id', '=', $contact['id'])
93 $this->assertArrayNotHasKey('api_key', $result);
94 $this->assertTrue($isSafe($result), "Should NOT reveal secret details ($key): " . var_export($result, 1));
97 public function testCreateWithInsufficientPermissions() {
98 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'add contacts'];
104 ->addValue('first_name', 'Api')
105 ->addValue('last_name', 'Key1')
106 ->addValue('api_key', $key)
110 catch (\Exception
$e) {
111 $error = $e->getMessage();
113 $this->assertContains('key', $error);
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();
123 return strpos(json_encode($mixed), $key) === FALSE;
126 $contact = Contact
::create()
127 ->setCheckPermissions(FALSE)
128 ->addValue('first_name', 'Api')
129 ->addValue('last_name', 'Key0')
130 ->addValue('api_key', $key)
133 $this->assertFalse($isSafe($contact), "Should reveal secret details ($key): " . var_export($contact, 1));
136 ->setCheckPermissions(FALSE)
137 ->addValue('email', 'foo@example.org')
138 ->addValue('contact_id', $contact['id'])
141 $result = Email
::get()
142 ->setCheckPermissions(FALSE)
143 ->addWhere('contact_id', '=', $contact['id'])
145 ->addSelect('contact.api_key')
148 $this->assertFalse($isSafe($result), "Should reveal secret details ($key): " . var_export($result, 1));
150 $result = Email
::get()
151 ->setCheckPermissions(TRUE)
152 ->addWhere('contact_id', '=', $contact['id'])
153 ->addSelect('contact.api_key')
156 $this->assertTrue($isSafe($result), "Should NOT reveal secret details ($key): " . var_export($result, 1));
159 public function testUpdateApiKey() {
160 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'edit all contacts'];
163 $contact = Contact
::create()
164 ->setCheckPermissions(FALSE)
165 ->addValue('first_name', 'Api')
166 ->addValue('last_name', 'Key2')
167 ->addValue('api_key', $key)
173 // Try to update the key without permissions; nothing should happen
175 ->addWhere('id', '=', $contact['id'])
176 ->addValue('api_key', "NotAllowed")
179 catch (\Exception
$e) {
180 $error = $e->getMessage();
183 $result = Contact
::get()
184 ->setCheckPermissions(FALSE)
185 ->addWhere('id', '=', $contact['id'])
186 ->addSelect('api_key')
190 $this->assertContains('key', $error);
192 // Assert key is still the same
193 $this->assertEquals($result['api_key'], $key);
195 // Now we can update the key
196 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'administer CiviCRM', 'edit all contacts'];
199 ->addWhere('id', '=', $contact['id'])
200 ->addValue('api_key', "IGotThePower!")
203 $result = Contact
::get()
204 ->addWhere('id', '=', $contact['id'])
205 ->addSelect('api_key')
209 // Assert key was updated
210 $this->assertEquals($result['api_key'], "IGotThePower!");
213 public function testUpdateOwnApiKey() {
214 \CRM_Core_Config
::singleton()->userPermissionClass
->permissions
= ['access CiviCRM', 'edit own api keys', 'edit all contacts'];
217 $contact = Contact
::create()
218 ->setCheckPermissions(FALSE)
219 ->addValue('first_name', 'Api')
220 ->addValue('last_name', 'Key3')
221 ->addValue('api_key', $key)
227 // Try to update the key without permissions; nothing should happen
229 ->addWhere('id', '=', $contact['id'])
230 ->addValue('api_key', "NotAllowed")
233 catch (\Exception
$e) {
234 $error = $e->getMessage();
237 $this->assertContains('key', $error);
239 $result = Contact
::get()
240 ->setCheckPermissions(FALSE)
241 ->addWhere('id', '=', $contact['id'])
242 ->addSelect('api_key')
246 // Assert key is still the same
247 $this->assertEquals($result['api_key'], $key);
249 // Now we can update the key
250 \CRM_Core_Session
::singleton()->set('userID', $contact['id']);
253 ->addWhere('id', '=', $contact['id'])
254 ->addValue('api_key', "MyId!")
257 $result = Contact
::get()
258 ->setCheckPermissions(FALSE)
259 ->addWhere('id', '=', $contact['id'])
260 ->addSelect('api_key')
264 // Assert key was updated
265 $this->assertEquals($result['api_key'], "MyId!");
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'));
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'));
279 // ...unless you disable 'checkPermissions'
280 $this->assertArrayHasKey('api_key', \
civicrm_api4('Contact', 'getFields', ['checkPermissions' => FALSE], 'name'));