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