testing_api_cmd_instance_token.c (11458B)
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 src/testing/testing_api_cmd_instance_token.c 21 * @brief command to test /private/token POSTing 22 * @author Martin Schanzenbach 23 */ 24 #include "platform.h" 25 struct TokenInstanceState; 26 #define TALER_MERCHANT_DELETE_PRIVATE_TOKEN_RESULT_CLOSURE struct TokenInstanceState 27 #define TALER_MERCHANT_POST_PRIVATE_TOKEN_RESULT_CLOSURE struct TokenInstanceState 28 #include <taler/taler_exchange_service.h> 29 #include <taler/taler_testing_lib.h> 30 #include "taler/taler_merchant_service.h" 31 #include "taler/taler_merchant_testing_lib.h" 32 #include <taler/merchant/delete-private-tokens-SERIAL.h> 33 #include <taler/merchant/post-private-token.h> 34 35 36 /** 37 * State of a "POST /instances/$ID/private/token" CMD. 38 */ 39 struct TokenInstanceState 40 { 41 42 /** 43 * Handle for a "POST token" request. 44 */ 45 struct TALER_MERCHANT_PostPrivateTokenHandle *itph; 46 47 /** 48 * Handle for a "DELETE token" request. 49 */ 50 struct TALER_MERCHANT_DeletePrivateTokenHandle *itdh; 51 52 /** 53 * The interpreter state. 54 */ 55 struct TALER_TESTING_Interpreter *is; 56 57 /** 58 * Base URL of the merchant serving the request. 59 */ 60 const char *merchant_url; 61 62 /** 63 * ID of the instance to run GET for. 64 */ 65 const char *instance_id; 66 67 /** 68 * The received token (if any). 69 */ 70 char *token; 71 72 /** 73 * Desired scope. Can be NULL 74 */ 75 const char *scope; 76 77 /** 78 * Desired duration. 79 */ 80 struct GNUNET_TIME_Relative duration; 81 82 /** 83 * Refreshable? 84 */ 85 bool refreshable; 86 87 /** 88 * Expected HTTP response code. 89 */ 90 unsigned int http_status; 91 92 /** 93 * DELETE or POST. 94 */ 95 unsigned int is_delete; 96 97 }; 98 99 /** 100 * Callback for a POST /instances/$ID/private/token operation. 101 * 102 * @param cls closure for this function 103 * @param ptr response being processed 104 */ 105 static void 106 token_instance_post_cb (struct TokenInstanceState *tis, 107 const struct TALER_MERCHANT_PostPrivateTokenResponse * 108 ptr) 109 { 110 111 tis->itph = NULL; 112 if (tis->http_status != ptr->hr.http_status) 113 { 114 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 115 "Unexpected response code %u (%d) to command %s\n", 116 ptr->hr.http_status, 117 (int) ptr->hr.ec, 118 TALER_TESTING_interpreter_get_current_label (tis->is)); 119 TALER_TESTING_interpreter_fail (tis->is); 120 return; 121 } 122 switch (ptr->hr.http_status) 123 { 124 case MHD_HTTP_OK: 125 if (NULL != ptr->details.ok.access_token) 126 tis->token = GNUNET_strdup (ptr->details.ok.access_token); 127 break; 128 case MHD_HTTP_BAD_REQUEST: 129 /* likely invalid auth value, we do not check client-side */ 130 break; 131 case MHD_HTTP_FORBIDDEN: 132 break; 133 default: 134 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 135 "Unhandled HTTP status %u (%d) returned from /private/token operation.\n", 136 ptr->hr.http_status, 137 ptr->hr.ec); 138 } 139 TALER_TESTING_interpreter_next (tis->is); 140 } 141 142 143 /** 144 * Callback for a DELETE /private/tokens/$SERIAL operation. 145 * 146 * @param cls closure for this function 147 * @param dtr response being processed 148 */ 149 static void 150 token_instance_delete_cb ( 151 struct TokenInstanceState *tis, 152 const struct TALER_MERCHANT_DeletePrivateTokenResponse *dtr) 153 { 154 155 tis->itdh = NULL; 156 if (tis->http_status != dtr->hr.http_status) 157 { 158 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 159 "Unexpected response code %u (%d) to command %s\n", 160 dtr->hr.http_status, 161 (int) dtr->hr.ec, 162 TALER_TESTING_interpreter_get_current_label (tis->is)); 163 TALER_TESTING_interpreter_fail (tis->is); 164 return; 165 } 166 switch (dtr->hr.http_status) 167 { 168 case MHD_HTTP_NO_CONTENT: 169 break; 170 case MHD_HTTP_FORBIDDEN: 171 break; 172 default: 173 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 174 "Unhandled HTTP status %u (%d) returned from DELETE /private/tokens operation.\n", 175 dtr->hr.http_status, 176 dtr->hr.ec); 177 } 178 TALER_TESTING_interpreter_next (tis->is); 179 } 180 181 182 /** 183 * set a token 184 * 185 * 186 * @param cls closure. 187 * @param cmd command being run now. 188 * @param is interpreter state. 189 */ 190 static void 191 set_token_instance_run (void *cls, 192 const struct TALER_TESTING_Command *cmd, 193 struct TALER_TESTING_Interpreter *is) 194 { 195 const char *token_job_label = cls; 196 const char *token; 197 const struct TALER_TESTING_Command *tok_cmd; 198 struct GNUNET_CURL_Context *cctx; 199 char *authorization; 200 201 cctx = TALER_TESTING_interpreter_get_context (is); 202 GNUNET_assert (NULL != cctx); 203 tok_cmd = TALER_TESTING_interpreter_lookup_command ( 204 is, 205 token_job_label); 206 if (NULL == tok_cmd) 207 { 208 GNUNET_break (0); 209 TALER_TESTING_interpreter_fail (is); 210 return; 211 } 212 if (GNUNET_OK != 213 TALER_TESTING_get_trait_bearer_token (tok_cmd, 214 &token)) 215 { 216 GNUNET_break (0); 217 TALER_TESTING_interpreter_fail (is); 218 return; 219 } 220 GNUNET_assert (NULL != token); 221 222 GNUNET_asprintf (&authorization, 223 "%s: Bearer %s", 224 MHD_HTTP_HEADER_AUTHORIZATION, 225 token); 226 GNUNET_assert (GNUNET_OK == 227 GNUNET_CURL_append_header (cctx, 228 authorization)); 229 GNUNET_free (authorization); 230 TALER_TESTING_interpreter_next (is); 231 } 232 233 234 /** 235 * Run the "token /instances/$ID" CMD. 236 * 237 * @param cls closure. 238 * @param cmd command being run now. 239 * @param is interpreter state. 240 */ 241 static void 242 token_instance_run (void *cls, 243 const struct TALER_TESTING_Command *cmd, 244 struct TALER_TESTING_Interpreter *is) 245 { 246 struct TokenInstanceState *tis = cls; 247 248 tis->is = is; 249 if (GNUNET_NO == tis->is_delete) 250 { 251 tis->itph = TALER_MERCHANT_post_private_token_create ( 252 TALER_TESTING_interpreter_get_context (is), 253 tis->merchant_url, 254 tis->instance_id, 255 tis->scope); 256 GNUNET_assert (GNUNET_OK == 257 TALER_MERCHANT_post_private_token_set_options ( 258 tis->itph, 259 TALER_MERCHANT_post_private_token_option_duration ( 260 tis->duration), 261 TALER_MERCHANT_post_private_token_option_refreshable ( 262 tis->refreshable))); 263 { 264 enum TALER_ErrorCode ec; 265 266 ec = TALER_MERCHANT_post_private_token_start ( 267 tis->itph, 268 &token_instance_post_cb, 269 tis); 270 GNUNET_assert (TALER_EC_NONE == ec); 271 } 272 } 273 else 274 { 275 tis->itdh = TALER_MERCHANT_delete_private_token_create ( 276 TALER_TESTING_interpreter_get_context (is), 277 tis->merchant_url, 278 tis->instance_id); 279 { 280 enum TALER_ErrorCode ec; 281 282 ec = TALER_MERCHANT_delete_private_token_start ( 283 tis->itdh, 284 &token_instance_delete_cb, 285 tis); 286 GNUNET_assert (TALER_EC_NONE == ec); 287 } 288 } 289 } 290 291 292 /** 293 * Free the state of a "POST instance token" CMD, and possibly 294 * cancel a pending operation thereof. 295 * 296 * @param cls closure. 297 * @param cmd command being run. 298 */ 299 static void 300 token_instance_cleanup (void *cls, 301 const struct TALER_TESTING_Command *cmd) 302 { 303 struct TokenInstanceState *tis = cls; 304 305 if (NULL != tis->itph) 306 { 307 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 308 "POST /instance/$ID/token operation did not complete\n"); 309 TALER_MERCHANT_post_private_token_cancel (tis->itph); 310 } 311 if (NULL != tis->itdh) 312 { 313 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 314 "DELETE /instance/$ID/token operation did not complete\n"); 315 TALER_MERCHANT_delete_private_token_cancel (tis->itdh); 316 } 317 GNUNET_free (tis->token); 318 GNUNET_free (tis); 319 } 320 321 322 /** 323 * Offer internal data to other commands. 324 * 325 * @param cls closure 326 * @param[out] ret result (could be anything) 327 * @param trait name of the trait 328 * @param index index number of the object to extract. 329 * @return #GNUNET_OK on success 330 */ 331 static enum GNUNET_GenericReturnValue 332 token_instance_traits (void *cls, 333 const void **ret, 334 const char *trait, 335 unsigned int index) 336 { 337 struct TokenInstanceState *ais = cls; 338 struct TALER_TESTING_Trait traits[] = { 339 TALER_TESTING_make_trait_bearer_token (ais->token), 340 TALER_TESTING_trait_end () 341 }; 342 343 return TALER_TESTING_get_trait (traits, 344 ret, 345 trait, 346 index); 347 } 348 349 350 struct TALER_TESTING_Command 351 TALER_TESTING_cmd_merchant_delete_instance_token (const char *label, 352 const char *merchant_url, 353 const char *instance_id, 354 unsigned int http_status) 355 { 356 struct TokenInstanceState *tis; 357 358 tis = GNUNET_new (struct TokenInstanceState); 359 tis->merchant_url = merchant_url; 360 tis->instance_id = instance_id; 361 tis->is_delete = GNUNET_YES; 362 tis->http_status = http_status; 363 364 { 365 struct TALER_TESTING_Command cmd = { 366 .cls = tis, 367 .label = label, 368 .run = &token_instance_run, 369 .cleanup = &token_instance_cleanup, 370 .traits = &token_instance_traits 371 }; 372 373 return cmd; 374 } 375 } 376 377 378 struct TALER_TESTING_Command 379 TALER_TESTING_cmd_merchant_set_instance_token (const char *label, 380 const char *token_job_label) 381 { 382 { 383 struct TALER_TESTING_Command cmd = { 384 .cls = (void*) token_job_label, // FIXME scope 385 .label = label, 386 .run = &set_token_instance_run, 387 .cleanup = NULL, 388 .traits = NULL 389 }; 390 391 return cmd; 392 } 393 } 394 395 396 struct TALER_TESTING_Command 397 TALER_TESTING_cmd_merchant_post_instance_token (const char *label, 398 const char *merchant_url, 399 const char *instance_id, 400 const char *scope, 401 struct GNUNET_TIME_Relative 402 duration, 403 bool refreshable, 404 unsigned int http_status) 405 { 406 struct TokenInstanceState *tis; 407 408 tis = GNUNET_new (struct TokenInstanceState); 409 tis->merchant_url = merchant_url; 410 tis->instance_id = instance_id; 411 tis->scope = scope; 412 tis->duration = duration; 413 tis->refreshable = refreshable; 414 tis->is_delete = GNUNET_NO; 415 tis->http_status = http_status; 416 417 { 418 struct TALER_TESTING_Command cmd = { 419 .cls = tis, 420 .label = label, 421 .run = &token_instance_run, 422 .cleanup = &token_instance_cleanup, 423 .traits = &token_instance_traits 424 }; 425 426 return cmd; 427 } 428 } 429 430 431 /* end of testing_api_cmd_token_instance.c */