testing_api_cmd_instance_token.c (11214B)
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 TALER_TESTING_get_trait_bearer_token (tok_cmd, 207 &token); 208 GNUNET_assert (NULL != token); 209 210 GNUNET_asprintf (&authorization, 211 "%s: Bearer %s", 212 MHD_HTTP_HEADER_AUTHORIZATION, 213 token); 214 GNUNET_assert (GNUNET_OK == 215 GNUNET_CURL_append_header (cctx, 216 authorization)); 217 GNUNET_free (authorization); 218 TALER_TESTING_interpreter_next (is); 219 } 220 221 222 /** 223 * Run the "token /instances/$ID" CMD. 224 * 225 * @param cls closure. 226 * @param cmd command being run now. 227 * @param is interpreter state. 228 */ 229 static void 230 token_instance_run (void *cls, 231 const struct TALER_TESTING_Command *cmd, 232 struct TALER_TESTING_Interpreter *is) 233 { 234 struct TokenInstanceState *tis = cls; 235 236 tis->is = is; 237 if (GNUNET_NO == tis->is_delete) 238 { 239 tis->itph = TALER_MERCHANT_post_private_token_create ( 240 TALER_TESTING_interpreter_get_context (is), 241 tis->merchant_url, 242 tis->instance_id, 243 tis->scope); 244 GNUNET_assert (GNUNET_OK == 245 TALER_MERCHANT_post_private_token_set_options ( 246 tis->itph, 247 TALER_MERCHANT_post_private_token_option_duration ( 248 tis->duration), 249 TALER_MERCHANT_post_private_token_option_refreshable ( 250 tis->refreshable))); 251 { 252 enum TALER_ErrorCode ec; 253 254 ec = TALER_MERCHANT_post_private_token_start ( 255 tis->itph, 256 &token_instance_post_cb, 257 tis); 258 GNUNET_assert (TALER_EC_NONE == ec); 259 } 260 } 261 else 262 { 263 tis->itdh = TALER_MERCHANT_delete_private_token_create ( 264 TALER_TESTING_interpreter_get_context (is), 265 tis->merchant_url, 266 tis->instance_id); 267 { 268 enum TALER_ErrorCode ec; 269 270 ec = TALER_MERCHANT_delete_private_token_start ( 271 tis->itdh, 272 &token_instance_delete_cb, 273 tis); 274 GNUNET_assert (TALER_EC_NONE == ec); 275 } 276 } 277 } 278 279 280 /** 281 * Free the state of a "POST instance token" CMD, and possibly 282 * cancel a pending operation thereof. 283 * 284 * @param cls closure. 285 * @param cmd command being run. 286 */ 287 static void 288 token_instance_cleanup (void *cls, 289 const struct TALER_TESTING_Command *cmd) 290 { 291 struct TokenInstanceState *tis = cls; 292 293 if (NULL != tis->itph) 294 { 295 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 296 "POST /instance/$ID/token operation did not complete\n"); 297 TALER_MERCHANT_post_private_token_cancel (tis->itph); 298 } 299 if (NULL != tis->itdh) 300 { 301 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 302 "DELETE /instance/$ID/token operation did not complete\n"); 303 TALER_MERCHANT_delete_private_token_cancel (tis->itdh); 304 } 305 GNUNET_free (tis); 306 } 307 308 309 /** 310 * Offer internal data to other commands. 311 * 312 * @param cls closure 313 * @param[out] ret result (could be anything) 314 * @param trait name of the trait 315 * @param index index number of the object to extract. 316 * @return #GNUNET_OK on success 317 */ 318 static enum GNUNET_GenericReturnValue 319 token_instance_traits (void *cls, 320 const void **ret, 321 const char *trait, 322 unsigned int index) 323 { 324 struct TokenInstanceState *ais = cls; 325 struct TALER_TESTING_Trait traits[] = { 326 TALER_TESTING_make_trait_bearer_token (ais->token), 327 TALER_TESTING_trait_end () 328 }; 329 330 return TALER_TESTING_get_trait (traits, 331 ret, 332 trait, 333 index); 334 } 335 336 337 struct TALER_TESTING_Command 338 TALER_TESTING_cmd_merchant_delete_instance_token (const char *label, 339 const char *merchant_url, 340 const char *instance_id, 341 unsigned int http_status) 342 { 343 struct TokenInstanceState *tis; 344 345 tis = GNUNET_new (struct TokenInstanceState); 346 tis->merchant_url = merchant_url; 347 tis->instance_id = instance_id; 348 tis->is_delete = GNUNET_YES; 349 tis->http_status = http_status; 350 351 { 352 struct TALER_TESTING_Command cmd = { 353 .cls = tis, 354 .label = label, 355 .run = &token_instance_run, 356 .cleanup = &token_instance_cleanup, 357 .traits = &token_instance_traits 358 }; 359 360 return cmd; 361 } 362 } 363 364 365 struct TALER_TESTING_Command 366 TALER_TESTING_cmd_merchant_set_instance_token (const char *label, 367 const char *token_job_label) 368 { 369 { 370 struct TALER_TESTING_Command cmd = { 371 .cls = (void*) token_job_label, // FIXME scope 372 .label = label, 373 .run = &set_token_instance_run, 374 .cleanup = NULL, 375 .traits = NULL 376 }; 377 378 return cmd; 379 } 380 } 381 382 383 struct TALER_TESTING_Command 384 TALER_TESTING_cmd_merchant_post_instance_token (const char *label, 385 const char *merchant_url, 386 const char *instance_id, 387 const char *scope, 388 struct GNUNET_TIME_Relative 389 duration, 390 bool refreshable, 391 unsigned int http_status) 392 { 393 struct TokenInstanceState *tis; 394 395 tis = GNUNET_new (struct TokenInstanceState); 396 tis->merchant_url = merchant_url; 397 tis->instance_id = instance_id; 398 tis->scope = scope; 399 tis->duration = duration; 400 tis->refreshable = refreshable; 401 tis->is_delete = GNUNET_NO; 402 tis->http_status = http_status; 403 404 { 405 struct TALER_TESTING_Command cmd = { 406 .cls = tis, 407 .label = label, 408 .run = &token_instance_run, 409 .cleanup = &token_instance_cleanup, 410 .traits = &token_instance_traits 411 }; 412 413 return cmd; 414 } 415 } 416 417 418 /* end of testing_api_cmd_token_instance.c */