testing_api_cmd_post_otp_devices.c (8213B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2022 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_post_otp_devices.c 21 * @brief command to test POST /otp-devices 22 * @author Christian Grothoff 23 */ 24 #include "platform.h" 25 struct PostOtpDevicesState; 26 #define TALER_MERCHANT_POST_PRIVATE_OTP_DEVICES_RESULT_CLOSURE struct PostOtpDevicesState 27 #include <taler/taler_exchange_service.h> 28 #include <taler/taler_testing_lib.h> 29 #include "taler/taler_merchant_service.h" 30 #include "taler/taler_merchant_testing_lib.h" 31 #include <taler/merchant/post-private-otp-devices.h> 32 33 34 /** 35 * State of a "POST /otp-devices" CMD. 36 */ 37 struct PostOtpDevicesState 38 { 39 40 /** 41 * Handle for a "GET otp_device" request. 42 */ 43 struct TALER_MERCHANT_PostPrivateOtpDevicesHandle *iph; 44 45 /** 46 * The interpreter state. 47 */ 48 struct TALER_TESTING_Interpreter *is; 49 50 /** 51 * Base URL of the merchant serving the request. 52 */ 53 const char *merchant_url; 54 55 /** 56 * ID of the otp_device to run POST for. 57 */ 58 const char *otp_device_id; 59 60 /** 61 * description of the otp_device 62 */ 63 const char *otp_device_description; 64 65 /** 66 * base64-encoded key 67 */ 68 char *otp_key; 69 70 /** 71 * Option that add amount of the order 72 */ 73 enum TALER_MerchantConfirmationAlgorithm otp_alg; 74 75 /** 76 * Public key the backend generated for a challenge-signature 77 * device, NULL for the TOTP algorithms. 78 */ 79 char *otp_device_pub; 80 81 /** 82 * Counter at the OTP device. 83 */ 84 uint64_t otp_ctr; 85 86 /** 87 * Expected HTTP response code. 88 */ 89 unsigned int http_status; 90 91 }; 92 93 94 /** 95 * Callback for a POST /otp-devices operation. 96 * 97 * @param cls closure for this function 98 * @param odr response being processed 99 */ 100 static void 101 post_otp_devices_cb (struct PostOtpDevicesState *tis, 102 const struct TALER_MERCHANT_PostPrivateOtpDevicesResponse * 103 odr) 104 { 105 106 tis->iph = NULL; 107 if (tis->http_status != odr->hr.http_status) 108 { 109 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 110 "Unexpected response code %u (%d) to command %s\n", 111 odr->hr.http_status, 112 (int) odr->hr.ec, 113 TALER_TESTING_interpreter_get_current_label (tis->is)); 114 TALER_TESTING_interpreter_fail (tis->is); 115 return; 116 } 117 /* whatever the status, the key the backend keeps must not come back 118 out: for TOTP it is the shared secret, for the challenge-signature 119 algorithms it is the private key */ 120 if ( (NULL != odr->hr.reply) && 121 (NULL != json_object_get (odr->hr.reply, 122 "otp_key")) ) 123 { 124 GNUNET_break (0); 125 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 126 "POST /otp-devices returned an otp_key to command %s\n", 127 TALER_TESTING_interpreter_get_current_label (tis->is)); 128 TALER_TESTING_interpreter_fail (tis->is); 129 return; 130 } 131 switch (odr->hr.http_status) 132 { 133 case MHD_HTTP_NO_CONTENT: 134 break; 135 case MHD_HTTP_OK: 136 /* the backend generated the key pair and hands us the public 137 half; this is the only time it is returned for a new device */ 138 tis->otp_device_pub 139 = GNUNET_strdup (odr->details.ok.otp_device_pub); 140 break; 141 case MHD_HTTP_BAD_REQUEST: 142 case MHD_HTTP_UNAUTHORIZED: 143 break; 144 case MHD_HTTP_FORBIDDEN: 145 break; 146 case MHD_HTTP_NOT_FOUND: 147 break; 148 case MHD_HTTP_CONFLICT: 149 break; 150 default: 151 GNUNET_break (0); 152 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 153 "Unhandled HTTP status %u for POST /otp-devices.\n", 154 odr->hr.http_status); 155 } 156 TALER_TESTING_interpreter_next (tis->is); 157 } 158 159 160 /** 161 * Run the "POST /otp-devices" CMD. 162 * 163 * 164 * @param cls closure. 165 * @param cmd command being run now. 166 * @param is interpreter state. 167 */ 168 static void 169 post_otp_devices_run (void *cls, 170 const struct TALER_TESTING_Command *cmd, 171 struct TALER_TESTING_Interpreter *is) 172 { 173 struct PostOtpDevicesState *tis = cls; 174 175 tis->is = is; 176 tis->iph = TALER_MERCHANT_post_private_otp_devices_create ( 177 TALER_TESTING_interpreter_get_context (is), 178 tis->merchant_url, 179 tis->otp_device_id, 180 tis->otp_device_description, 181 tis->otp_key, 182 tis->otp_alg); 183 GNUNET_assert (GNUNET_OK == 184 TALER_MERCHANT_post_private_otp_devices_set_options ( 185 tis->iph, 186 TALER_MERCHANT_post_private_otp_devices_option_otp_ctr ( 187 tis->otp_ctr))); 188 { 189 enum TALER_ErrorCode ec; 190 191 ec = TALER_MERCHANT_post_private_otp_devices_start ( 192 tis->iph, 193 &post_otp_devices_cb, 194 tis); 195 if (TALER_EC_NONE != ec) 196 { 197 GNUNET_break (0); 198 TALER_TESTING_interpreter_fail (tis->is); 199 return; 200 } 201 } 202 } 203 204 205 /** 206 * Offers information from the POST /otp-devices CMD state to other 207 * commands. 208 * 209 * @param cls closure 210 * @param[out] ret result (could be anything) 211 * @param trait name of the trait 212 * @param index index number of the object to extract. 213 * @return #GNUNET_OK on success 214 */ 215 static enum GNUNET_GenericReturnValue 216 post_otp_devices_traits (void *cls, 217 const void **ret, 218 const char *trait, 219 unsigned int index) 220 { 221 struct PostOtpDevicesState *pts = cls; 222 struct TALER_TESTING_Trait traits[] = { 223 TALER_TESTING_make_trait_otp_device_description (pts->otp_device_description 224 ), 225 TALER_TESTING_make_trait_otp_key (pts->otp_key), 226 TALER_TESTING_make_trait_otp_alg (&pts->otp_alg), 227 TALER_TESTING_make_trait_otp_device_pub (pts->otp_device_pub), 228 TALER_TESTING_make_trait_otp_id (pts->otp_device_id), 229 TALER_TESTING_trait_end (), 230 }; 231 232 return TALER_TESTING_get_trait (traits, 233 ret, 234 trait, 235 index); 236 } 237 238 239 /** 240 * Free the state of a "POST otp_device" CMD, and possibly 241 * cancel a pending operation thereof. 242 * 243 * @param cls closure. 244 * @param cmd command being run. 245 */ 246 static void 247 post_otp_devices_cleanup (void *cls, 248 const struct TALER_TESTING_Command *cmd) 249 { 250 struct PostOtpDevicesState *tis = cls; 251 252 if (NULL != tis->iph) 253 { 254 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 255 "POST /otp-devices operation did not complete\n"); 256 TALER_MERCHANT_post_private_otp_devices_cancel (tis->iph); 257 } 258 GNUNET_free (tis->otp_key); 259 GNUNET_free (tis->otp_device_pub); 260 GNUNET_free (tis); 261 } 262 263 264 struct TALER_TESTING_Command 265 TALER_TESTING_cmd_merchant_post_otp_devices ( 266 const char *label, 267 const char *merchant_url, 268 const char *otp_device_id, 269 const char *otp_device_description, 270 const char *otp_key, 271 const enum TALER_MerchantConfirmationAlgorithm otp_alg, 272 uint64_t otp_ctr, 273 unsigned int http_status) 274 { 275 struct PostOtpDevicesState *tis; 276 277 tis = GNUNET_new (struct PostOtpDevicesState); 278 tis->merchant_url = merchant_url; 279 tis->otp_device_id = otp_device_id; 280 tis->http_status = http_status; 281 tis->otp_device_description = otp_device_description; 282 /* NULL for the challenge-signature algorithms: there the backend 283 generates the key pair and the client never supplies one */ 284 tis->otp_key = (NULL != otp_key) 285 ? GNUNET_strdup (otp_key) 286 : NULL; 287 tis->otp_alg = otp_alg; 288 tis->otp_ctr = otp_ctr; 289 { 290 struct TALER_TESTING_Command cmd = { 291 .cls = tis, 292 .label = label, 293 .run = &post_otp_devices_run, 294 .cleanup = &post_otp_devices_cleanup, 295 .traits = &post_otp_devices_traits 296 }; 297 298 return cmd; 299 } 300 } 301 302 303 /* end of testing_api_cmd_post_otp_devices.c */