merchant_api_post-management-instances-INSTANCE-auth.c (7840B)
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 const char *auth_password) 159 { 160 struct TALER_MERCHANT_PostManagementInstancesAuthHandle *piah; 161 162 piah = GNUNET_new (struct TALER_MERCHANT_PostManagementInstancesAuthHandle); 163 piah->ctx = ctx; 164 piah->base_url = GNUNET_strdup (url); 165 if (NULL != instance_id) 166 piah->instance_id = GNUNET_strdup (instance_id); 167 if (NULL != auth_password) 168 piah->auth_password = GNUNET_strdup (auth_password); 169 return piah; 170 } 171 172 173 enum TALER_ErrorCode 174 TALER_MERCHANT_post_management_instances_auth_start ( 175 struct TALER_MERCHANT_PostManagementInstancesAuthHandle *piah, 176 TALER_MERCHANT_PostManagementInstancesAuthCallback cb, 177 TALER_MERCHANT_POST_MANAGEMENT_INSTANCES_AUTH_RESULT_CLOSURE *cb_cls) 178 { 179 json_t *req_obj; 180 CURL *eh; 181 182 piah->cb = cb; 183 piah->cb_cls = cb_cls; 184 if (NULL != piah->instance_id) 185 { 186 char *path; 187 188 GNUNET_asprintf (&path, 189 "management/instances/%s/auth", 190 piah->instance_id); 191 piah->url = TALER_url_join (piah->base_url, 192 path, 193 NULL); 194 GNUNET_free (path); 195 } 196 else 197 { 198 /* backend_url is already identifying the instance */ 199 piah->url = TALER_url_join (piah->base_url, 200 "private/auth", 201 NULL); 202 } 203 if (NULL == piah->url) 204 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 205 206 if (NULL == piah->auth_password) 207 { 208 req_obj = GNUNET_JSON_PACK ( 209 GNUNET_JSON_pack_string ("method", 210 "external")); 211 } 212 else 213 { 214 req_obj = GNUNET_JSON_PACK ( 215 GNUNET_JSON_pack_string ("method", 216 "token"), 217 GNUNET_JSON_pack_string ("password", 218 piah->auth_password)); 219 } 220 eh = TALER_MERCHANT_curl_easy_get_ (piah->url); 221 if ( (NULL == eh) || 222 (GNUNET_OK != 223 TALER_curl_easy_post (&piah->post_ctx, 224 eh, 225 req_obj)) ) 226 { 227 GNUNET_break (0); 228 json_decref (req_obj); 229 if (NULL != eh) 230 curl_easy_cleanup (eh); 231 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 232 } 233 json_decref (req_obj); 234 GNUNET_assert (CURLE_OK == 235 curl_easy_setopt (eh, 236 CURLOPT_CUSTOMREQUEST, 237 MHD_HTTP_METHOD_POST)); 238 piah->job = GNUNET_CURL_job_add2 (piah->ctx, 239 eh, 240 piah->post_ctx.headers, 241 & 242 handle_post_management_instances_auth_finished, 243 piah); 244 if (NULL == piah->job) 245 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 246 return TALER_EC_NONE; 247 } 248 249 250 void 251 TALER_MERCHANT_post_management_instances_auth_cancel ( 252 struct TALER_MERCHANT_PostManagementInstancesAuthHandle *piah) 253 { 254 if (NULL != piah->job) 255 { 256 GNUNET_CURL_job_cancel (piah->job); 257 piah->job = NULL; 258 } 259 TALER_curl_easy_post_finished (&piah->post_ctx); 260 GNUNET_free (piah->instance_id); 261 GNUNET_free (piah->auth_password); 262 GNUNET_free (piah->url); 263 GNUNET_free (piah->base_url); 264 GNUNET_free (piah); 265 } 266 267 268 /* end of merchant_api_post-management-instances-INSTANCE-auth-new.c */