Merge pull request #17473 from eileenmcnaughton/anet
[civicrm-core.git] / tests / phpunit / E2E / Extern / RestTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 * Verify that the REST API bindings correctly parse and authenticate requests.
14 *
15 * @group e2e
16 */
17 class E2E_Extern_RestTest extends CiviEndToEndTestCase {
18 protected $url;
19 protected static $api_key;
20 protected $session_id;
21 protected $nocms_contact_id;
22 protected $old_api_keys;
23 protected $adminContactId;
24
25 /**
26 * @param $apiResult
27 * @param $cmpvar
28 * @param string $prefix
29 */
30 protected function assertAPIErrorCode($apiResult, $cmpvar, $prefix = '') {
31 if (!empty($prefix)) {
32 $prefix .= ': ';
33 }
34 $this->assertEquals($cmpvar, $apiResult['is_error'],
35 $prefix . (empty($apiResult['error_message']) ? '' : $apiResult['error_message']));
36 //$this->assertEquals($cmpvar, $apiResult['is_error'], $prefix . print_r($apiResult, TRUE));
37 }
38
39 protected function setUp() {
40 parent::setUp();
41
42 if (empty($GLOBALS['_CV']['CIVI_SITE_KEY'])) {
43 $this->markTestSkipped('Missing siteKey');
44 }
45
46 $this->old_api_keys = [];
47 }
48
49 protected function getRestUrl() {
50 return CRM_Core_Resources::singleton()
51 ->getUrl('civicrm', 'extern/rest.php');
52 }
53
54 protected function tearDown() {
55 if (!empty($this->old_api_keys)) {
56 foreach ($this->old_api_keys as $cid => $apiKey) {
57 civicrm_api3('Contact', 'create', array(
58 'id' => $cid,
59 'api_key' => $apiKey,
60 ));
61 }
62 }
63 parent::tearDown();
64 if (isset($this->nocms_contact_id)) {
65 $deleteParams = array(
66 "id" => $this->nocms_contact_id,
67 "skip_undelete" => 1,
68 );
69 $res = civicrm_api3("Contact", "delete", $deleteParams);
70 unset($this->nocms_contact_id);
71 }
72 }
73
74 /**
75 * Build a list of test cases. Each test case defines a set of REST query
76 * parameters and an expected outcome for the REST request (eg is_error=>1 or is_error=>0).
77 *
78 * @return array; each item is a list of parameters for testAPICalls
79 */
80 public function apiTestCases() {
81 $cases = [];
82
83 // entity,action: omit apiKey, valid entity+action
84 $cases[] = array(
85 // query
86 array(
87 "entity" => "Contact",
88 "action" => "get",
89 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
90 "json" => "1",
91 ),
92 // is_error
93 1,
94 );
95
96 // entity,action: valid apiKey, valid entity+action
97 $cases[] = array(
98 // query
99 array(
100 "entity" => "Contact",
101 "action" => "get",
102 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
103 "json" => "1",
104 "api_key" => self::getApiKey(),
105 ),
106 // is_error
107 0,
108 );
109
110 // entity,action: bad apiKey, valid entity+action
111 $cases[] = array(
112 // query
113 array(
114 "entity" => "Contact",
115 "action" => "get",
116 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
117 "json" => "1",
118 "api_key" => 'garbage_' . self::getApiKey(),
119 ),
120 // is_error
121 1,
122 );
123
124 // entity,action: valid apiKey, invalid entity+action
125 $cases[] = array(
126 // query
127 array(
128 "entity" => "Contactses",
129 "action" => "get",
130 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
131 "json" => "1",
132 "api_key" => self::getApiKey(),
133 ),
134 // is_error
135 1,
136 );
137
138 // q=civicrm/entity/action: omit apiKey, valid entity+action
139 $cases[] = array(
140 // query
141 array(
142 "q" => "civicrm/contact/get",
143 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
144 "json" => "1",
145 ),
146 // is_error
147 1,
148 );
149
150 // q=civicrm/entity/action: valid apiKey, valid entity+action
151 $cases[] = array(
152 // query
153 array(
154 "q" => "civicrm/contact/get",
155 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
156 "json" => "1",
157 "api_key" => self::getApiKey(),
158 ),
159 // is_error
160 0,
161 );
162
163 // q=civicrm/entity/action: invalid apiKey, valid entity+action
164 $cases[] = array(
165 // query
166 array(
167 "q" => "civicrm/contact/get",
168 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
169 "json" => "1",
170 "api_key" => 'garbage_' . self::getApiKey(),
171 ),
172 // is_error
173 1,
174 );
175
176 // q=civicrm/entity/action: valid apiKey, invalid entity+action
177 $cases[] = array(
178 // query
179 array(
180 "q" => "civicrm/contactses/get",
181 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
182 "json" => "1",
183 "api_key" => self::getApiKey(),
184 ),
185 // is_error
186 1,
187 );
188
189 // q=civicrm/entity/action: valid apiKey, invalid entity+action
190 // XXX Actually Ping is valid, no?
191 $cases[] = array(
192 // query
193 array(
194 "q" => "civicrm/ping",
195 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
196 "json" => "1",
197 "api_key" => self::getApiKey(),
198 ),
199 // is_error
200 0,
201 );
202
203 return $cases;
204 }
205
206 /**
207 * @dataProvider apiTestCases
208 * @param $query
209 * @param $is_error
210 */
211 public function testAPICalls($query, $is_error) {
212 $this->updateAdminApiKey();
213
214 $client = CRM_Utils_HttpClient::singleton();
215 list($status, $data) = $client->post($this->getRestUrl(), $query);
216 $this->assertEquals(CRM_Utils_HttpClient::STATUS_OK, $status);
217 $result = json_decode($data, TRUE);
218 if ($result === NULL) {
219 $msg = print_r(array(
220 'restUrl' => $this->getRestUrl(),
221 'query' => $query,
222 'response data' => $data,
223 ), TRUE);
224 $this->assertNotNull($result, $msg);
225 }
226 $this->assertAPIErrorCode($result, $is_error);
227 }
228
229 /**
230 * Submit a request with an API key that exists but does not correspond to.
231 * a real user. Submit in "?entity=X&action=X" notation
232 */
233 public function testNotCMSUser_entityAction() {
234 $client = CRM_Utils_HttpClient::singleton();
235
236 //Create contact with api_key
237 $test_key = "testing1234";
238 $contactParams = array(
239 "api_key" => $test_key,
240 "contact_type" => "Individual",
241 "first_name" => "RestTester1",
242 );
243 $contact = civicrm_api3("Contact", "create", $contactParams);
244 $this->nocms_contact_id = $contact["id"];
245
246 // The key associates with a real contact but not a real user
247 $params = array(
248 "entity" => "Contact",
249 "action" => "get",
250 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
251 "json" => "1",
252 "api_key" => $test_key,
253 );
254 list($status, $data) = $client->post($this->getRestUrl(), $params);
255 $this->assertEquals(CRM_Utils_HttpClient::STATUS_OK, $status);
256 $result = json_decode($data, TRUE);
257 $this->assertNotNull($result);
258 $this->assertAPIErrorCode($result, 1);
259 }
260
261 /**
262 * Submit a request with an API key that exists but does not correspond to.
263 * a real user. Submit in "?entity=X&action=X" notation
264 */
265 public function testGetCorrectUserBack() {
266 $this->updateAdminApiKey();
267 $client = CRM_Utils_HttpClient::singleton();
268
269 //Create contact with api_key
270 // The key associates with a real contact but not a real user
271 $params = array(
272 "entity" => "Contact",
273 "action" => "get",
274 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
275 "json" => "1",
276 "api_key" => self::getApiKey(),
277 "id" => "user_contact_id",
278 );
279 list($status, $data) = $client->post($this->getRestUrl(), $params);
280 $this->assertEquals(CRM_Utils_HttpClient::STATUS_OK, $status);
281 $result = json_decode($data, TRUE);
282 $this->assertNotNull($result);
283 $this->assertEquals($result['id'], $this->adminContactId);
284 }
285
286 /**
287 * Submit a request with an API key that exists but does not correspond to
288 * a real user. Submit in "?q=civicrm/$entity/$action" notation
289 */
290 public function testNotCMSUser_q() {
291 $client = CRM_Utils_HttpClient::singleton();
292
293 //Create contact with api_key
294 $test_key = "testing1234";
295 $contactParams = array(
296 "api_key" => $test_key,
297 "contact_type" => "Individual",
298 "first_name" => "RestTester1",
299 );
300 $contact = civicrm_api3("Contact", "create", $contactParams);
301 $this->nocms_contact_id = $contact["id"];
302
303 // The key associates with a real contact but not a real user
304 $params = array(
305 "q" => "civicrm/contact/get",
306 "key" => $GLOBALS['_CV']['CIVI_SITE_KEY'],
307 "json" => "1",
308 "api_key" => $test_key,
309 );
310 list($status, $data) = $client->post($this->getRestUrl(), $params);
311 $this->assertEquals(CRM_Utils_HttpClient::STATUS_OK, $status);
312 $result = json_decode($data, TRUE);
313 $this->assertNotNull($result);
314 $this->assertAPIErrorCode($result, 1);
315 }
316
317 protected function updateAdminApiKey() {
318 /** @var int $adminContactId */
319 $this->adminContactId = civicrm_api3('contact', 'getvalue', array(
320 'id' => '@user:' . $GLOBALS['_CV']['ADMIN_USER'],
321 'return' => 'id',
322 ));
323
324 $this->old_api_keys[$this->adminContactId] = CRM_Core_DAO::singleValueQuery('SELECT api_key FROM civicrm_contact WHERE id = %1', [
325 1 => [$this->adminContactId, 'Positive'],
326 ]);
327
328 //$this->old_admin_api_key = civicrm_api3('Contact', 'get', array(
329 // 'id' => $adminContactId,
330 // 'return' => 'api_key',
331 //));
332
333 civicrm_api3('Contact', 'create', array(
334 'id' => $this->adminContactId,
335 'api_key' => self::getApiKey(),
336 ));
337 }
338
339 protected static function getApiKey() {
340 if (empty(self::$api_key)) {
341 self::$api_key = mt_rand() . mt_rand();
342 }
343 return self::$api_key;
344 }
345
346 }