merchant_api_post-management-instances-INSTANCE-auth.c (8410B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-2026 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Lesser General Public License as published by the Free Software 7 Foundation; either version 2.1, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 12 13 You should have received a copy of the GNU Lesser General Public License along with 14 TALER; see the file COPYING.LGPL. If not, see 15 <http://www.gnu.org/licenses/> 16 */ 17 /** 18 * @file merchant_api_post-management-instances-INSTANCE-auth-new.c 19 * @brief Implementation of the POST /management/instances/$INSTANCE/auth request 20 * @author Christian Grothoff 21 */ 22 #include "taler/platform.h" 23 #include <curl/curl.h> 24 #include <jansson.h> 25 #include <microhttpd.h> /* just for HTTP status codes */ 26 #include <gnunet/gnunet_util_lib.h> 27 #include <gnunet/gnunet_curl_lib.h> 28 #include <taler/taler-merchant/post-management-instances-INSTANCE-auth.h> 29 #include "merchant_api_curl_defaults.h" 30 #include "merchant_api_common.h" 31 #include <taler/taler_json_lib.h> 32 #include <taler/taler_curl_lib.h> 33 34 35 /** 36 * Handle for a POST /management/instances/$INSTANCE/auth operation. 37 */ 38 struct TALER_MERCHANT_PostManagementInstancesAuthHandle 39 { 40 /** 41 * Base URL of the merchant backend. 42 */ 43 char *base_url; 44 45 /** 46 * The full URL for this request. 47 */ 48 char *url; 49 50 /** 51 * Handle for the request. 52 */ 53 struct GNUNET_CURL_Job *job; 54 55 /** 56 * Function to call with the result. 57 */ 58 TALER_MERCHANT_PostManagementInstancesAuthCallback cb; 59 60 /** 61 * Closure for @a cb. 62 */ 63 TALER_MERCHANT_POST_MANAGEMENT_INSTANCES_AUTH_RESULT_CLOSURE *cb_cls; 64 65 /** 66 * Reference to the execution context. 67 */ 68 struct GNUNET_CURL_Context *ctx; 69 70 /** 71 * Minor context that holds body and headers. 72 */ 73 struct TALER_CURL_PostContext post_ctx; 74 75 /** 76 * Instance identifier. 77 */ 78 char *instance_id; 79 80 /** 81 * New authentication password. 82 */ 83 char *auth_password; 84 }; 85 86 87 /** 88 * Function called when we're done processing the 89 * HTTP POST /management/instances/$INSTANCE/auth request. 90 * 91 * @param cls the `struct TALER_MERCHANT_PostManagementInstancesAuthHandle` 92 * @param response_code HTTP response code, 0 on error 93 * @param response response body, NULL if not in JSON 94 */ 95 static void 96 handle_post_management_instances_auth_finished (void *cls, 97 long response_code, 98 const void *response) 99 { 100 struct TALER_MERCHANT_PostManagementInstancesAuthHandle *piah = cls; 101 const json_t *json = response; 102 struct TALER_MERCHANT_PostManagementInstancesAuthResponse iar = { 103 .hr.http_status = (unsigned int) response_code, 104 .hr.reply = json 105 }; 106 107 piah->job = NULL; 108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 109 "POST /management/instances/$INSTANCE/auth completed with " 110 "response code %u\n", 111 (unsigned int) response_code); 112 switch (response_code) 113 { 114 case MHD_HTTP_NO_CONTENT: 115 break; 116 case MHD_HTTP_ACCEPTED: 117 if (GNUNET_OK != 118 TALER_MERCHANT_parse_mfa_challenge_response_ ( 119 json, 120 &iar.details.accepted)) 121 { 122 GNUNET_break_op (0); 123 iar.hr.http_status = 0; 124 iar.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 125 } 126 break; 127 case MHD_HTTP_BAD_REQUEST: 128 iar.hr.ec = TALER_JSON_get_error_code (json); 129 iar.hr.hint = TALER_JSON_get_error_hint (json); 130 break; 131 case MHD_HTTP_UNAUTHORIZED: 132 iar.hr.ec = TALER_JSON_get_error_code (json); 133 iar.hr.hint = TALER_JSON_get_error_hint (json); 134 break; 135 default: 136 iar.hr.ec = TALER_JSON_get_error_code (json); 137 iar.hr.hint = TALER_JSON_get_error_hint (json); 138 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 139 "Unexpected response code %u/%d\n", 140 (unsigned int) response_code, 141 (int) iar.hr.ec); 142 break; 143 } 144 piah->cb (piah->cb_cls, 145 &iar); 146 if (MHD_HTTP_ACCEPTED == response_code) 147 TALER_MERCHANT_mfa_challenge_response_free ( 148 &iar.details.accepted); 149 TALER_MERCHANT_post_management_instances_auth_cancel (piah); 150 } 151 152 153 struct TALER_MERCHANT_PostManagementInstancesAuthHandle * 154 TALER_MERCHANT_post_management_instances_auth_create ( 155 struct GNUNET_CURL_Context *ctx, 156 const char *url, 157 const char *instance_id) 158 { 159 struct TALER_MERCHANT_PostManagementInstancesAuthHandle *piah; 160 161 piah = GNUNET_new (struct TALER_MERCHANT_PostManagementInstancesAuthHandle); 162 piah->ctx = ctx; 163 piah->base_url = GNUNET_strdup (url); 164 if (NULL != instance_id) 165 piah->instance_id = GNUNET_strdup (instance_id); 166 return piah; 167 } 168 169 170 void 171 TALER_MERCHANT_post_management_instances_auth_set_options_ ( 172 struct TALER_MERCHANT_PostManagementInstancesAuthHandle *piah, 173 unsigned int num_options, 174 const struct TALER_MERCHANT_PostManagementInstancesAuthOptionValue options[]) 175 { 176 for (unsigned int i = 0; i < num_options; i++) 177 { 178 switch (options[i].option) 179 { 180 case TALER_MERCHANT_POST_MANAGEMENT_INSTANCES_AUTH_OPTION_END: 181 return; 182 case TALER_MERCHANT_POST_MANAGEMENT_INSTANCES_AUTH_OPTION_PASSWORD: 183 GNUNET_free (piah->auth_password); 184 if (NULL != options[i].details.password) 185 piah->auth_password = GNUNET_strdup ( 186 options[i].details.password); 187 break; 188 } 189 } 190 } 191 192 193 enum TALER_ErrorCode 194 TALER_MERCHANT_post_management_instances_auth_start ( 195 struct TALER_MERCHANT_PostManagementInstancesAuthHandle *piah, 196 TALER_MERCHANT_PostManagementInstancesAuthCallback cb, 197 TALER_MERCHANT_POST_MANAGEMENT_INSTANCES_AUTH_RESULT_CLOSURE *cb_cls) 198 { 199 json_t *req_obj; 200 CURL *eh; 201 202 piah->cb = cb; 203 piah->cb_cls = cb_cls; 204 if (NULL != piah->instance_id) 205 { 206 char *path; 207 208 GNUNET_asprintf (&path, 209 "management/instances/%s/auth", 210 piah->instance_id); 211 piah->url = TALER_url_join (piah->base_url, 212 path, 213 NULL); 214 GNUNET_free (path); 215 } 216 else 217 { 218 /* backend_url is already identifying the instance */ 219 piah->url = TALER_url_join (piah->base_url, 220 "private/auth", 221 NULL); 222 } 223 if (NULL == piah->url) 224 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 225 226 if (NULL == piah->auth_password) 227 { 228 req_obj = GNUNET_JSON_PACK ( 229 GNUNET_JSON_pack_string ("method", 230 "external")); 231 } 232 else 233 { 234 req_obj = GNUNET_JSON_PACK ( 235 GNUNET_JSON_pack_string ("method", 236 "token"), 237 GNUNET_JSON_pack_string ("password", 238 piah->auth_password)); 239 } 240 eh = TALER_MERCHANT_curl_easy_get_ (piah->url); 241 if ( (NULL == eh) || 242 (GNUNET_OK != 243 TALER_curl_easy_post (&piah->post_ctx, 244 eh, 245 req_obj)) ) 246 { 247 GNUNET_break (0); 248 json_decref (req_obj); 249 if (NULL != eh) 250 curl_easy_cleanup (eh); 251 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 252 } 253 json_decref (req_obj); 254 GNUNET_assert (CURLE_OK == 255 curl_easy_setopt (eh, 256 CURLOPT_CUSTOMREQUEST, 257 MHD_HTTP_METHOD_POST)); 258 piah->job = GNUNET_CURL_job_add2 (piah->ctx, 259 eh, 260 piah->post_ctx.headers, 261 & 262 handle_post_management_instances_auth_finished, 263 piah); 264 if (NULL == piah->job) 265 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 266 return TALER_EC_NONE; 267 } 268 269 270 void 271 TALER_MERCHANT_post_management_instances_auth_cancel ( 272 struct TALER_MERCHANT_PostManagementInstancesAuthHandle *piah) 273 { 274 if (NULL != piah->job) 275 { 276 GNUNET_CURL_job_cancel (piah->job); 277 piah->job = NULL; 278 } 279 TALER_curl_easy_post_finished (&piah->post_ctx); 280 GNUNET_free (piah->instance_id); 281 GNUNET_free (piah->auth_password); 282 GNUNET_free (piah->url); 283 GNUNET_free (piah->base_url); 284 GNUNET_free (piah); 285 } 286 287 288 /* end of merchant_api_post-management-instances-INSTANCE-auth-new.c */