Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2025 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as
7 : published by the Free Software Foundation; either version 3, or
8 : (at your option) any later version.
9 :
10 : TALER is distributed in the hope that it will be useful, but
11 : WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public
16 : License along with TALER; see the file COPYING. If not, see
17 : <http://www.gnu.org/licenses/>
18 : */
19 : /**
20 : * @file testing_api_cmd_instance_token.c
21 : * @brief command to test /private/token POSTing
22 : * @author Martin Schanzenbach
23 : */
24 : #include "platform.h"
25 : #include <taler/taler_exchange_service.h>
26 : #include <taler/taler_testing_lib.h>
27 : #include "taler_merchant_service.h"
28 : #include "taler_merchant_testing_lib.h"
29 :
30 :
31 : /**
32 : * State of a "POST /instances/$ID/private/token" CMD.
33 : */
34 : struct TokenInstanceState
35 : {
36 :
37 : /**
38 : * Handle for a "POST token" request.
39 : */
40 : struct TALER_MERCHANT_InstanceTokenPostHandle *itph;
41 :
42 : /**
43 : * Handle for a "DELETE token" request.
44 : */
45 : struct TALER_MERCHANT_InstanceTokenDeleteHandle *itdh;
46 :
47 : /**
48 : * The interpreter state.
49 : */
50 : struct TALER_TESTING_Interpreter *is;
51 :
52 : /**
53 : * Base URL of the merchant serving the request.
54 : */
55 : const char *merchant_url;
56 :
57 : /**
58 : * ID of the instance to run GET for.
59 : */
60 : const char *instance_id;
61 :
62 : /**
63 : * The received token (if any).
64 : */
65 : char *token;
66 :
67 : /**
68 : * Desired scope. Can be NULL
69 : */
70 : const char *scope;
71 :
72 : /**
73 : * Desired duration.
74 : */
75 : struct GNUNET_TIME_Relative duration;
76 :
77 : /**
78 : * Refreshable?
79 : */
80 : bool refreshable;
81 :
82 : /**
83 : * Expected HTTP response code.
84 : */
85 : unsigned int http_status;
86 :
87 : /**
88 : * DELETE or POST.
89 : */
90 : unsigned int is_delete;
91 :
92 : };
93 :
94 : /**
95 : * Callback for a POST /instances/$ID/private/token operation.
96 : *
97 : * @param cls closure for this function
98 : * @param hr response being processed
99 : */
100 : static void
101 6 : token_instance_cb (void *cls,
102 : const struct TALER_MERCHANT_HttpResponse *hr)
103 : {
104 6 : struct TokenInstanceState *tis = cls;
105 : const char *scope;
106 : struct GNUNET_TIME_Timestamp duration;
107 : bool refreshable;
108 : const char *error_name;
109 : unsigned int error_line;
110 :
111 :
112 6 : tis->itph = NULL;
113 6 : if (tis->http_status != hr->http_status)
114 : {
115 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
116 : "Unexpected response code %u (%d) to command %s\n",
117 : hr->http_status,
118 : (int) hr->ec,
119 : TALER_TESTING_interpreter_get_current_label (tis->is));
120 0 : TALER_TESTING_interpreter_fail (tis->is);
121 0 : return;
122 : }
123 6 : switch (hr->http_status)
124 : {
125 2 : case MHD_HTTP_NO_CONTENT:
126 2 : GNUNET_assert (GNUNET_YES == tis->is_delete);
127 2 : break;
128 4 : case MHD_HTTP_OK:
129 : {
130 : /* Get token */
131 : struct GNUNET_JSON_Specification spec[] = {
132 4 : GNUNET_JSON_spec_string_copy ("access_token",
133 : &tis->token),
134 4 : GNUNET_JSON_spec_string ("scope",
135 : &scope),
136 4 : GNUNET_JSON_spec_bool ("refreshable",
137 : &refreshable),
138 4 : GNUNET_JSON_spec_timestamp ("expiration",
139 : &duration),
140 4 : GNUNET_JSON_spec_end ()
141 : };
142 :
143 4 : GNUNET_assert (GNUNET_NO == tis->is_delete);
144 4 : if (GNUNET_OK !=
145 4 : GNUNET_JSON_parse (hr->reply,
146 : spec,
147 : &error_name,
148 : &error_line))
149 : {
150 : char *js;
151 :
152 0 : js = json_dumps (hr->reply,
153 : JSON_INDENT (1));
154 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
155 : "Parser failed on %s:%u for input `%s'\n",
156 : error_name,
157 : error_line,
158 : js);
159 0 : free (js);
160 0 : TALER_TESTING_FAIL (tis->is);
161 : }
162 4 : break;
163 : }
164 0 : case MHD_HTTP_BAD_REQUEST:
165 : /* likely invalid auth value, we do not check client-side */
166 0 : break;
167 0 : case MHD_HTTP_FORBIDDEN:
168 0 : break;
169 0 : default:
170 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
171 : "Unhandled HTTP status %u (%d) returned from /private/token operation.\n",
172 : hr->http_status,
173 : hr->ec);
174 : }
175 :
176 :
177 6 : TALER_TESTING_interpreter_next (tis->is);
178 : }
179 :
180 :
181 : /**
182 : * set a token
183 : *
184 : *
185 : * @param cls closure.
186 : * @param cmd command being run now.
187 : * @param is interpreter state.
188 : */
189 : static void
190 4 : set_token_instance_run (void *cls,
191 : const struct TALER_TESTING_Command *cmd,
192 : struct TALER_TESTING_Interpreter *is)
193 : {
194 4 : const char *token_job_label = cls;
195 : const char *token;
196 : const struct TALER_TESTING_Command *tok_cmd;
197 : struct GNUNET_CURL_Context *cctx;
198 : char *authorization;
199 :
200 4 : cctx = TALER_TESTING_interpreter_get_context (is);
201 4 : GNUNET_assert (NULL != cctx);
202 4 : tok_cmd = TALER_TESTING_interpreter_lookup_command (
203 : is,
204 : token_job_label);
205 4 : TALER_TESTING_get_trait_bearer_token (tok_cmd,
206 : &token);
207 4 : GNUNET_assert (NULL != token);
208 :
209 4 : GNUNET_asprintf (&authorization,
210 : "%s: Bearer %s",
211 : MHD_HTTP_HEADER_AUTHORIZATION,
212 : token);
213 4 : GNUNET_assert (GNUNET_OK ==
214 : GNUNET_CURL_append_header (cctx,
215 : authorization));
216 4 : GNUNET_free (authorization);
217 4 : TALER_TESTING_interpreter_next (is);
218 4 : }
219 :
220 :
221 : /**
222 : * Run the "token /instances/$ID" CMD.
223 : *
224 : *
225 : * @param cls closure.
226 : * @param cmd command being run now.
227 : * @param is interpreter state.
228 : */
229 : static void
230 6 : token_instance_run (void *cls,
231 : const struct TALER_TESTING_Command *cmd,
232 : struct TALER_TESTING_Interpreter *is)
233 : {
234 6 : struct TokenInstanceState *tis = cls;
235 :
236 6 : tis->is = is;
237 6 : if (GNUNET_NO == tis->is_delete)
238 4 : tis->itph = TALER_MERCHANT_instance_token_post (
239 : TALER_TESTING_interpreter_get_context (is),
240 : tis->merchant_url,
241 : tis->instance_id,
242 : tis->scope,
243 : tis->duration,
244 4 : tis->refreshable,
245 : &token_instance_cb,
246 : tis);
247 : else
248 2 : tis->itdh = TALER_MERCHANT_instance_token_delete (
249 : TALER_TESTING_interpreter_get_context (is),
250 : tis->merchant_url,
251 : tis->instance_id,
252 : &token_instance_cb,
253 : tis);
254 6 : GNUNET_assert ((NULL != tis->itph) || (NULL != tis->itdh));
255 6 : }
256 :
257 :
258 : /**
259 : * Free the state of a "POST instance token" CMD, and possibly
260 : * cancel a pending operation thereof.
261 : *
262 : * @param cls closure.
263 : * @param cmd command being run.
264 : */
265 : static void
266 6 : token_instance_cleanup (void *cls,
267 : const struct TALER_TESTING_Command *cmd)
268 : {
269 6 : struct TokenInstanceState *tis = cls;
270 :
271 6 : if (NULL != tis->itph)
272 : {
273 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
274 : "%s /instance/$ID/token operation did not complete\n",
275 : (GNUNET_NO == tis->is_delete) ? "DELETE" : "POST");
276 0 : if (GNUNET_NO == tis->is_delete)
277 0 : TALER_MERCHANT_instance_token_post_cancel (tis->itph);
278 : else
279 0 : TALER_MERCHANT_instance_token_delete_cancel (tis->itdh);
280 : }
281 6 : GNUNET_free (tis);
282 6 : }
283 :
284 :
285 : /**
286 : * Offer internal data to other commands.
287 : *
288 : * @param cls closure
289 : * @param[out] ret result (could be anything)
290 : * @param trait name of the trait
291 : * @param index index number of the object to extract.
292 : * @return #GNUNET_OK on success
293 : */
294 : static enum GNUNET_GenericReturnValue
295 4 : token_instance_traits (void *cls,
296 : const void **ret,
297 : const char *trait,
298 : unsigned int index)
299 : {
300 4 : struct TokenInstanceState *ais = cls;
301 : struct TALER_TESTING_Trait traits[] = {
302 4 : TALER_TESTING_make_trait_bearer_token (ais->token),
303 4 : TALER_TESTING_trait_end ()
304 : };
305 :
306 4 : return TALER_TESTING_get_trait (traits,
307 : ret,
308 : trait,
309 : index);
310 : }
311 :
312 :
313 : struct TALER_TESTING_Command
314 2 : TALER_TESTING_cmd_merchant_delete_instance_token (const char *label,
315 : const char *merchant_url,
316 : const char *instance_id,
317 : unsigned int http_status)
318 : {
319 : struct TokenInstanceState *tis;
320 :
321 2 : tis = GNUNET_new (struct TokenInstanceState);
322 2 : tis->merchant_url = merchant_url;
323 2 : tis->instance_id = instance_id;
324 2 : tis->is_delete = GNUNET_YES;
325 2 : tis->http_status = http_status;
326 :
327 : {
328 2 : struct TALER_TESTING_Command cmd = {
329 : .cls = tis,
330 : .label = label,
331 : .run = &token_instance_run,
332 : .cleanup = &token_instance_cleanup,
333 : .traits = &token_instance_traits
334 : };
335 :
336 2 : return cmd;
337 : }
338 : }
339 :
340 :
341 : struct TALER_TESTING_Command
342 4 : TALER_TESTING_cmd_merchant_set_instance_token (const char *label,
343 : const char *token_job_label)
344 : {
345 : {
346 4 : struct TALER_TESTING_Command cmd = {
347 : .cls = (void*) token_job_label, // FIXME scope
348 : .label = label,
349 : .run = &set_token_instance_run,
350 : .cleanup = NULL,
351 : .traits = NULL
352 : };
353 :
354 4 : return cmd;
355 : }
356 : }
357 :
358 :
359 : struct TALER_TESTING_Command
360 4 : TALER_TESTING_cmd_merchant_post_instance_token (const char *label,
361 : const char *merchant_url,
362 : const char *instance_id,
363 : const char *scope,
364 : struct GNUNET_TIME_Relative
365 : duration,
366 : bool refreshable,
367 : unsigned int http_status)
368 : {
369 : struct TokenInstanceState *tis;
370 :
371 4 : tis = GNUNET_new (struct TokenInstanceState);
372 4 : tis->merchant_url = merchant_url;
373 4 : tis->instance_id = instance_id;
374 4 : tis->scope = scope;
375 4 : tis->duration = duration;
376 4 : tis->refreshable = refreshable;
377 4 : tis->is_delete = GNUNET_NO;
378 4 : tis->http_status = http_status;
379 :
380 : {
381 4 : struct TALER_TESTING_Command cmd = {
382 : .cls = tis,
383 : .label = label,
384 : .run = &token_instance_run,
385 : .cleanup = &token_instance_cleanup,
386 : .traits = &token_instance_traits
387 : };
388 :
389 4 : return cmd;
390 : }
391 : }
392 :
393 :
394 : /* end of testing_api_cmd_token_instance.c */
|