merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

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 */