merchant_api_post-management-instances-INSTANCE-auth.c (9044B)
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 src/lib/merchant_api_post-management-instances-INSTANCE-auth.c 19 * @brief Implementation of the POST /management/instances/$INSTANCE/auth request 20 * @author Christian Grothoff 21 */ 22 #include "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/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 * Current authentication password for self-service changes. 87 */ 88 char *old_password; 89 }; 90 91 92 /** 93 * Function called when we're done processing the 94 * HTTP POST /management/instances/$INSTANCE/auth request. 95 * 96 * @param cls the `struct TALER_MERCHANT_PostManagementInstancesAuthHandle` 97 * @param response_code HTTP response code, 0 on error 98 * @param response response body, NULL if not in JSON 99 */ 100 static void 101 handle_post_management_instances_auth_finished (void *cls, 102 long response_code, 103 const void *response) 104 { 105 struct TALER_MERCHANT_PostManagementInstancesAuthHandle *piah = cls; 106 const json_t *json = response; 107 struct TALER_MERCHANT_PostManagementInstancesAuthResponse iar = { 108 .hr.http_status = (unsigned int) response_code, 109 .hr.reply = json 110 }; 111 112 piah->job = NULL; 113 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 114 "POST /management/instances/$INSTANCE/auth completed with " 115 "response code %u\n", 116 (unsigned int) response_code); 117 switch (response_code) 118 { 119 case MHD_HTTP_NO_CONTENT: 120 break; 121 case MHD_HTTP_ACCEPTED: 122 if (GNUNET_OK != 123 TALER_MERCHANT_parse_mfa_challenge_response_ ( 124 json, 125 &iar.details.accepted)) 126 { 127 GNUNET_break_op (0); 128 iar.hr.http_status = 0; 129 iar.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 130 } 131 break; 132 case MHD_HTTP_BAD_REQUEST: 133 iar.hr.ec = TALER_JSON_get_error_code (json); 134 iar.hr.hint = TALER_JSON_get_error_hint (json); 135 break; 136 case MHD_HTTP_UNAUTHORIZED: 137 iar.hr.ec = TALER_JSON_get_error_code (json); 138 iar.hr.hint = TALER_JSON_get_error_hint (json); 139 break; 140 default: 141 iar.hr.ec = TALER_JSON_get_error_code (json); 142 iar.hr.hint = TALER_JSON_get_error_hint (json); 143 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 144 "Unexpected response code %u/%d\n", 145 (unsigned int) response_code, 146 (int) iar.hr.ec); 147 break; 148 } 149 piah->cb (piah->cb_cls, 150 &iar); 151 if (MHD_HTTP_ACCEPTED == response_code) 152 TALER_MERCHANT_mfa_challenge_response_free ( 153 &iar.details.accepted); 154 TALER_MERCHANT_post_management_instances_auth_cancel (piah); 155 } 156 157 158 struct TALER_MERCHANT_PostManagementInstancesAuthHandle * 159 TALER_MERCHANT_post_management_instances_auth_create ( 160 struct GNUNET_CURL_Context *ctx, 161 const char *url, 162 const char *instance_id) 163 { 164 struct TALER_MERCHANT_PostManagementInstancesAuthHandle *piah; 165 166 piah = GNUNET_new (struct TALER_MERCHANT_PostManagementInstancesAuthHandle); 167 piah->ctx = ctx; 168 piah->base_url = GNUNET_strdup (url); 169 if (NULL != instance_id) 170 piah->instance_id = GNUNET_strdup (instance_id); 171 return piah; 172 } 173 174 175 void 176 TALER_MERCHANT_post_management_instances_auth_set_options_ ( 177 struct TALER_MERCHANT_PostManagementInstancesAuthHandle *piah, 178 unsigned int num_options, 179 const struct TALER_MERCHANT_PostManagementInstancesAuthOptionValue options[]) 180 { 181 for (unsigned int i = 0; i < num_options; i++) 182 { 183 switch (options[i].option) 184 { 185 case TALER_MERCHANT_POST_MANAGEMENT_INSTANCES_AUTH_OPTION_END: 186 return; 187 case TALER_MERCHANT_POST_MANAGEMENT_INSTANCES_AUTH_OPTION_PASSWORD: 188 GNUNET_free (piah->auth_password); 189 if (NULL != options[i].details.password) 190 piah->auth_password = GNUNET_strdup ( 191 options[i].details.password); 192 break; 193 case TALER_MERCHANT_POST_MANAGEMENT_INSTANCES_AUTH_OPTION_OLD_PASSWORD: 194 GNUNET_free (piah->old_password); 195 if (NULL != options[i].details.old_password) 196 piah->old_password = GNUNET_strdup ( 197 options[i].details.old_password); 198 break; 199 } 200 } 201 } 202 203 204 enum TALER_ErrorCode 205 TALER_MERCHANT_post_management_instances_auth_start ( 206 struct TALER_MERCHANT_PostManagementInstancesAuthHandle *piah, 207 TALER_MERCHANT_PostManagementInstancesAuthCallback cb, 208 TALER_MERCHANT_POST_MANAGEMENT_INSTANCES_AUTH_RESULT_CLOSURE *cb_cls) 209 { 210 json_t *req_obj; 211 CURL *eh; 212 213 piah->cb = cb; 214 piah->cb_cls = cb_cls; 215 if (NULL != piah->instance_id) 216 { 217 char *path; 218 219 GNUNET_asprintf (&path, 220 "management/instances/%s/auth", 221 piah->instance_id); 222 piah->url = TALER_url_join (piah->base_url, 223 path, 224 NULL); 225 GNUNET_free (path); 226 } 227 else 228 { 229 /* backend_url is already identifying the instance */ 230 piah->url = TALER_url_join (piah->base_url, 231 "private/auth", 232 NULL); 233 } 234 if (NULL == piah->url) 235 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 236 237 if (NULL == piah->auth_password) 238 { 239 req_obj = GNUNET_JSON_PACK ( 240 GNUNET_JSON_pack_string ("method", 241 "external")); 242 } 243 else 244 { 245 req_obj = GNUNET_JSON_PACK ( 246 GNUNET_JSON_pack_string ("method", 247 "token"), 248 GNUNET_JSON_pack_string ("password", 249 piah->auth_password)); 250 } 251 if (NULL != piah->old_password) 252 GNUNET_assert (0 == 253 json_object_set_new (req_obj, 254 "old_password", 255 json_string (piah->old_password))); 256 eh = TALER_MERCHANT_curl_easy_get_ (piah->url); 257 if ( (NULL == eh) || 258 (GNUNET_OK != 259 TALER_curl_easy_post (&piah->post_ctx, 260 eh, 261 req_obj)) ) 262 { 263 GNUNET_break (0); 264 json_decref (req_obj); 265 if (NULL != eh) 266 curl_easy_cleanup (eh); 267 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 268 } 269 json_decref (req_obj); 270 GNUNET_assert (CURLE_OK == 271 curl_easy_setopt (eh, 272 CURLOPT_CUSTOMREQUEST, 273 MHD_HTTP_METHOD_POST)); 274 piah->job = GNUNET_CURL_job_add2 (piah->ctx, 275 eh, 276 piah->post_ctx.headers, 277 & 278 handle_post_management_instances_auth_finished, 279 piah); 280 if (NULL == piah->job) 281 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 282 return TALER_EC_NONE; 283 } 284 285 286 void 287 TALER_MERCHANT_post_management_instances_auth_cancel ( 288 struct TALER_MERCHANT_PostManagementInstancesAuthHandle *piah) 289 { 290 if (NULL != piah->job) 291 { 292 GNUNET_CURL_job_cancel (piah->job); 293 piah->job = NULL; 294 } 295 TALER_curl_easy_post_finished (&piah->post_ctx); 296 GNUNET_free (piah->instance_id); 297 GNUNET_free (piah->auth_password); 298 GNUNET_free (piah->old_password); 299 GNUNET_free (piah->url); 300 GNUNET_free (piah->base_url); 301 GNUNET_free (piah); 302 } 303 304 305 /* end of merchant_api_post-management-instances-INSTANCE-auth-new.c */