LCOV - code coverage report
Current view: top level - kyclogic - plugin_kyclogic_oauth2.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 53 369 14.4 %
Date: 2022-08-25 06:15:09 Functions: 2 17 11.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of GNU Taler
       3             :   Copyright (C) 2022 Taler Systems SA
       4             : 
       5             :   Taler is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Affero General Public License as published by the Free Software
       7             :   Foundation; either version 3, 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 Affero General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Affero General Public License along with
      14             :   Taler; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file plugin_kyclogic_oauth2.c
      18             :  * @brief oauth2.0 based authentication flow logic
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include "taler_kyclogic_plugin.h"
      23             : #include "taler_mhd_lib.h"
      24             : #include "taler_json_lib.h"
      25             : #include <regex.h>
      26             : #include "taler_util.h"
      27             : 
      28             : 
      29             : /**
      30             :  * Saves the state of a plugin.
      31             :  */
      32             : struct PluginState
      33             : {
      34             : 
      35             :   /**
      36             :    * Our global configuration.
      37             :    */
      38             :   const struct GNUNET_CONFIGURATION_Handle *cfg;
      39             : 
      40             :   /**
      41             :    * Our base URL.
      42             :    */
      43             :   char *exchange_base_url;
      44             : 
      45             :   /**
      46             :    * Context for CURL operations (useful to the event loop)
      47             :    */
      48             :   struct GNUNET_CURL_Context *curl_ctx;
      49             : 
      50             :   /**
      51             :    * Context for integrating @e curl_ctx with the
      52             :    * GNUnet event loop.
      53             :    */
      54             :   struct GNUNET_CURL_RescheduleContext *curl_rc;
      55             : 
      56             : };
      57             : 
      58             : 
      59             : /**
      60             :  * Keeps the plugin-specific state for
      61             :  * a given configuration section.
      62             :  */
      63             : struct TALER_KYCLOGIC_ProviderDetails
      64             : {
      65             : 
      66             :   /**
      67             :    * Overall plugin state.
      68             :    */
      69             :   struct PluginState *ps;
      70             : 
      71             :   /**
      72             :    * Configuration section that configured us.
      73             :    */
      74             :   char *section;
      75             : 
      76             :   /**
      77             :    * URL of the OAuth2.0 endpoint for KYC checks.
      78             :    * (token/auth)
      79             :    */
      80             :   char *auth_url;
      81             : 
      82             :   /**
      83             :    * URL of the OAuth2.0 endpoint for KYC checks.
      84             :    */
      85             :   char *login_url;
      86             : 
      87             :   /**
      88             :    * URL of the user info access endpoint.
      89             :    */
      90             :   char *info_url;
      91             : 
      92             :   /**
      93             :    * Our client ID for OAuth2.0.
      94             :    */
      95             :   char *client_id;
      96             : 
      97             :   /**
      98             :    * Our client secret for OAuth2.0.
      99             :    */
     100             :   char *client_secret;
     101             : 
     102             :   /**
     103             :    * Where to redirect clients after the
     104             :    * Web-based KYC process is done?
     105             :    */
     106             :   char *post_kyc_redirect_url;
     107             : 
     108             :   /**
     109             :    * Validity time for a successful KYC process.
     110             :    */
     111             :   struct GNUNET_TIME_Relative validity;
     112             : 
     113             : };
     114             : 
     115             : 
     116             : /**
     117             :  * Handle for an initiation operation.
     118             :  */
     119             : struct TALER_KYCLOGIC_InitiateHandle
     120             : {
     121             : 
     122             :   /**
     123             :    * Hash of the payto:// URI we are initiating
     124             :    * the KYC for.
     125             :    */
     126             :   struct TALER_PaytoHashP h_payto;
     127             : 
     128             :   /**
     129             :    * UUID being checked.
     130             :    */
     131             :   uint64_t legitimization_uuid;
     132             : 
     133             :   /**
     134             :    * Our configuration details.
     135             :    */
     136             :   const struct TALER_KYCLOGIC_ProviderDetails *pd;
     137             : 
     138             :   /**
     139             :    * The task for asynchronous response generation.
     140             :    */
     141             :   struct GNUNET_SCHEDULER_Task *task;
     142             : 
     143             :   /**
     144             :    * Continuation to call.
     145             :    */
     146             :   TALER_KYCLOGIC_InitiateCallback cb;
     147             : 
     148             :   /**
     149             :    * Closure for @a cb.
     150             :    */
     151             :   void *cb_cls;
     152             : 
     153             : };
     154             : 
     155             : 
     156             : /**
     157             :  * Handle for an KYC proof operation.
     158             :  */
     159             : struct TALER_KYCLOGIC_ProofHandle
     160             : {
     161             : 
     162             :   /**
     163             :    * Our configuration details.
     164             :    */
     165             :   const struct TALER_KYCLOGIC_ProviderDetails *pd;
     166             : 
     167             :   /**
     168             :    * HTTP connection we are processing.
     169             :    */
     170             :   struct MHD_Connection *connection;
     171             : 
     172             :   /**
     173             :    * Hash of the payto URI that this is about.
     174             :    */
     175             :   struct TALER_PaytoHashP h_payto;
     176             : 
     177             :   /**
     178             :    * Continuation to call.
     179             :    */
     180             :   TALER_KYCLOGIC_ProofCallback cb;
     181             : 
     182             :   /**
     183             :    * Closure for @e cb.
     184             :    */
     185             :   void *cb_cls;
     186             : 
     187             :   /**
     188             :    * Curl request we are running to the OAuth 2.0 service.
     189             :    */
     190             :   CURL *eh;
     191             : 
     192             :   /**
     193             :    * Body for the @e eh POST request.
     194             :    */
     195             :   char *post_body;
     196             : 
     197             :   /**
     198             :    * Response to return.
     199             :    */
     200             :   struct MHD_Response *response;
     201             : 
     202             :   /**
     203             :    * The task for asynchronous response generation.
     204             :    */
     205             :   struct GNUNET_SCHEDULER_Task *task;
     206             : 
     207             :   /**
     208             :    * Handle for the OAuth 2.0 CURL request.
     209             :    */
     210             :   struct GNUNET_CURL_Job *job;
     211             : 
     212             :   /**
     213             :    * User ID to return, the 'id' from OAuth.
     214             :    */
     215             :   char *provider_user_id;
     216             : 
     217             :   /**
     218             :    * Legitimization ID to return, the 64-bit row ID
     219             :    * as a string.
     220             :    */
     221             :   char provider_legitimization_id[32];
     222             : 
     223             :   /**
     224             :    * KYC status to return.
     225             :    */
     226             :   enum TALER_KYCLOGIC_KycStatus status;
     227             : 
     228             :   /**
     229             :    * HTTP status to return.
     230             :    */
     231             :   unsigned int http_status;
     232             : 
     233             : 
     234             : };
     235             : 
     236             : 
     237             : /**
     238             :  * Handle for an KYC Web hook operation.
     239             :  */
     240             : struct TALER_KYCLOGIC_WebhookHandle
     241             : {
     242             : 
     243             :   /**
     244             :    * Continuation to call when done.
     245             :    */
     246             :   TALER_KYCLOGIC_WebhookCallback cb;
     247             : 
     248             :   /**
     249             :    * Closure for @a cb.
     250             :    */
     251             :   void *cb_cls;
     252             : 
     253             :   /**
     254             :    * Task for asynchronous execution.
     255             :    */
     256             :   struct GNUNET_SCHEDULER_Task *task;
     257             : 
     258             :   /**
     259             :    * Overall plugin state.
     260             :    */
     261             :   struct PluginState *ps;
     262             : };
     263             : 
     264             : 
     265             : /**
     266             :  * Release configuration resources previously loaded
     267             :  *
     268             :  * @param[in] pd configuration to release
     269             :  */
     270             : static void
     271           0 : oauth2_unload_configuration (struct TALER_KYCLOGIC_ProviderDetails *pd)
     272             : {
     273           0 :   GNUNET_free (pd->section);
     274           0 :   GNUNET_free (pd->auth_url);
     275           0 :   GNUNET_free (pd->login_url);
     276           0 :   GNUNET_free (pd->info_url);
     277           0 :   GNUNET_free (pd->client_id);
     278           0 :   GNUNET_free (pd->client_secret);
     279           0 :   GNUNET_free (pd->post_kyc_redirect_url);
     280           0 :   GNUNET_free (pd);
     281           0 : }
     282             : 
     283             : 
     284             : /**
     285             :  * Load the configuration of the KYC provider.
     286             :  *
     287             :  * @param cls closure
     288             :  * @param provider_section_name configuration section to parse
     289             :  * @return NULL if configuration is invalid
     290             :  */
     291             : static struct TALER_KYCLOGIC_ProviderDetails *
     292           1 : oauth2_load_configuration (void *cls,
     293             :                            const char *provider_section_name)
     294             : {
     295           1 :   struct PluginState *ps = cls;
     296             :   struct TALER_KYCLOGIC_ProviderDetails *pd;
     297             :   char *s;
     298             : 
     299           1 :   pd = GNUNET_new (struct TALER_KYCLOGIC_ProviderDetails);
     300           1 :   pd->ps = ps;
     301           1 :   pd->section = GNUNET_strdup (provider_section_name);
     302           1 :   if (GNUNET_OK !=
     303           1 :       GNUNET_CONFIGURATION_get_value_time (ps->cfg,
     304             :                                            provider_section_name,
     305             :                                            "KYC_OAUTH2_VALIDITY",
     306             :                                            &pd->validity))
     307             :   {
     308           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     309             :                                provider_section_name,
     310             :                                "KYC_OAUTH2_VALIDITY");
     311           0 :     oauth2_unload_configuration (pd);
     312           0 :     return NULL;
     313             :   }
     314           1 :   if (GNUNET_OK !=
     315           1 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     316             :                                              provider_section_name,
     317             :                                              "KYC_OAUTH2_AUTH_URL",
     318             :                                              &s))
     319             :   {
     320           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     321             :                                provider_section_name,
     322             :                                "KYC_OAUTH2_AUTH_URL");
     323           0 :     oauth2_unload_configuration (pd);
     324           0 :     return NULL;
     325             :   }
     326           1 :   if ( (! TALER_url_valid_charset (s)) ||
     327           1 :        ( (0 != strncasecmp (s,
     328             :                             "http://",
     329           0 :                             strlen ("http://"))) &&
     330           0 :          (0 != strncasecmp (s,
     331             :                             "https://",
     332             :                             strlen ("https://"))) ) )
     333             :   {
     334           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     335             :                                provider_section_name,
     336             :                                "KYC_OAUTH2_AUTH_URL",
     337             :                                "not a valid URL");
     338           0 :     GNUNET_free (s);
     339           0 :     oauth2_unload_configuration (pd);
     340           0 :     return NULL;
     341             :   }
     342           1 :   pd->auth_url = s;
     343             : 
     344           1 :   if (GNUNET_OK !=
     345           1 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     346             :                                              provider_section_name,
     347             :                                              "KYC_OAUTH2_LOGIN_URL",
     348             :                                              &s))
     349             :   {
     350           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     351             :                                provider_section_name,
     352             :                                "KYC_OAUTH2_LOGIN_URL");
     353           0 :     oauth2_unload_configuration (pd);
     354           0 :     return NULL;
     355             :   }
     356           1 :   if ( (! TALER_url_valid_charset (s)) ||
     357           1 :        ( (0 != strncasecmp (s,
     358             :                             "http://",
     359           0 :                             strlen ("http://"))) &&
     360           0 :          (0 != strncasecmp (s,
     361             :                             "https://",
     362             :                             strlen ("https://"))) ) )
     363             :   {
     364           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     365             :                                provider_section_name,
     366             :                                "KYC_OAUTH2_LOGIN_URL",
     367             :                                "not a valid URL");
     368           0 :     oauth2_unload_configuration (pd);
     369           0 :     GNUNET_free (s);
     370           0 :     return NULL;
     371             :   }
     372           1 :   pd->login_url = s;
     373             : 
     374           1 :   if (GNUNET_OK !=
     375           1 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     376             :                                              provider_section_name,
     377             :                                              "KYC_OAUTH2_INFO_URL",
     378             :                                              &s))
     379             :   {
     380           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     381             :                                provider_section_name,
     382             :                                "KYC_OAUTH2_INFO_URL");
     383           0 :     oauth2_unload_configuration (pd);
     384           0 :     return NULL;
     385             :   }
     386           1 :   if ( (! TALER_url_valid_charset (s)) ||
     387           1 :        ( (0 != strncasecmp (s,
     388             :                             "http://",
     389           0 :                             strlen ("http://"))) &&
     390           0 :          (0 != strncasecmp (s,
     391             :                             "https://",
     392             :                             strlen ("https://"))) ) )
     393             :   {
     394           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     395             :                                provider_section_name,
     396             :                                "KYC_INFO_URL",
     397             :                                "not a valid URL");
     398           0 :     GNUNET_free (s);
     399           0 :     oauth2_unload_configuration (pd);
     400           0 :     return NULL;
     401             :   }
     402           1 :   pd->info_url = s;
     403             : 
     404           1 :   if (GNUNET_OK !=
     405           1 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     406             :                                              provider_section_name,
     407             :                                              "KYC_OAUTH2_CLIENT_ID",
     408             :                                              &s))
     409             :   {
     410           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     411             :                                provider_section_name,
     412             :                                "KYC_OAUTH2_CLIENT_ID");
     413           0 :     oauth2_unload_configuration (pd);
     414           0 :     return NULL;
     415             :   }
     416           1 :   pd->client_id = s;
     417             : 
     418           1 :   if (GNUNET_OK !=
     419           1 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     420             :                                              provider_section_name,
     421             :                                              "KYC_OAUTH2_CLIENT_SECRET",
     422             :                                              &s))
     423             :   {
     424           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     425             :                                provider_section_name,
     426             :                                "KYC_OAUTH2_CLIENT_SECRET");
     427           0 :     oauth2_unload_configuration (pd);
     428           0 :     return NULL;
     429             :   }
     430           1 :   pd->client_secret = s;
     431             : 
     432           1 :   if (GNUNET_OK !=
     433           1 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     434             :                                              provider_section_name,
     435             :                                              "KYC_OAUTH2_POST_URL",
     436             :                                              &s))
     437             :   {
     438           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     439             :                                provider_section_name,
     440             :                                "KYC_OAUTH2_POST_URL");
     441           0 :     oauth2_unload_configuration (pd);
     442           0 :     return NULL;
     443             :   }
     444           1 :   pd->post_kyc_redirect_url = s;
     445             : 
     446           1 :   return pd;
     447             : }
     448             : 
     449             : 
     450             : /**
     451             :  * Logic to asynchronously return the response for
     452             :  * how to begin the OAuth2.0 checking process to
     453             :  * the client.
     454             :  *
     455             :  * @param cls a `struct TALER_KYCLOGIC_InitiateHandle *`
     456             :  */
     457             : static void
     458           0 : initiate_task (void *cls)
     459             : {
     460           0 :   struct TALER_KYCLOGIC_InitiateHandle *ih = cls;
     461           0 :   const struct TALER_KYCLOGIC_ProviderDetails *pd = ih->pd;
     462           0 :   struct PluginState *ps = pd->ps;
     463             :   char *hps;
     464             :   char *url;
     465             :   char *redirect_uri;
     466             :   char *redirect_uri_encoded;
     467             :   char legi_s[42];
     468             : 
     469           0 :   ih->task = NULL;
     470           0 :   GNUNET_snprintf (legi_s,
     471             :                    sizeof (legi_s),
     472             :                    "%llu",
     473           0 :                    (unsigned long long) ih->legitimization_uuid);
     474           0 :   hps = GNUNET_STRINGS_data_to_string_alloc (&ih->h_payto,
     475             :                                              sizeof (ih->h_payto));
     476           0 :   GNUNET_asprintf (&redirect_uri,
     477             :                    "%s/kyc-proof/%s/%s/%s",
     478             :                    ps->exchange_base_url,
     479             :                    hps,
     480             :                    pd->section,
     481             :                    legi_s);
     482           0 :   redirect_uri_encoded = TALER_urlencode (redirect_uri);
     483           0 :   GNUNET_free (redirect_uri);
     484           0 :   GNUNET_asprintf (&url,
     485             :                    "%s?client_id=%s&redirect_uri=%s",
     486             :                    pd->login_url,
     487             :                    pd->client_id,
     488             :                    redirect_uri_encoded);
     489           0 :   GNUNET_free (redirect_uri_encoded);
     490           0 :   ih->cb (ih->cb_cls,
     491             :           TALER_EC_NONE,
     492             :           url,
     493             :           NULL /* unknown user_id here */,
     494             :           legi_s,
     495             :           NULL /* no error */);
     496           0 :   GNUNET_free (url);
     497           0 :   GNUNET_free (hps);
     498           0 :   GNUNET_free (ih);
     499           0 : }
     500             : 
     501             : 
     502             : /**
     503             :  * Initiate KYC check.
     504             :  *
     505             :  * @param cls the @e cls of this struct with the plugin-specific state
     506             :  * @param pd provider configuration details
     507             :  * @param account_id which account to trigger process for
     508             :  * @param legitimization_uuid unique ID for the legitimization process
     509             :  * @param cb function to call with the result
     510             :  * @param cb_cls closure for @a cb
     511             :  * @return handle to cancel operation early
     512             :  */
     513             : static struct TALER_KYCLOGIC_InitiateHandle *
     514           0 : oauth2_initiate (void *cls,
     515             :                  const struct TALER_KYCLOGIC_ProviderDetails *pd,
     516             :                  const struct TALER_PaytoHashP *account_id,
     517             :                  uint64_t legitimization_uuid,
     518             :                  TALER_KYCLOGIC_InitiateCallback cb,
     519             :                  void *cb_cls)
     520             : {
     521             :   struct TALER_KYCLOGIC_InitiateHandle *ih;
     522             : 
     523             :   (void) cls;
     524           0 :   ih = GNUNET_new (struct TALER_KYCLOGIC_InitiateHandle);
     525           0 :   ih->legitimization_uuid = legitimization_uuid;
     526           0 :   ih->cb = cb;
     527           0 :   ih->cb_cls = cb_cls;
     528           0 :   ih->h_payto = *account_id;
     529           0 :   ih->pd = pd;
     530           0 :   ih->task = GNUNET_SCHEDULER_add_now (&initiate_task,
     531             :                                        ih);
     532           0 :   return ih;
     533             : }
     534             : 
     535             : 
     536             : /**
     537             :  * Cancel KYC check initiation.
     538             :  *
     539             :  * @param[in] ih handle of operation to cancel
     540             :  */
     541             : static void
     542           0 : oauth2_initiate_cancel (struct TALER_KYCLOGIC_InitiateHandle *ih)
     543             : {
     544           0 :   if (NULL != ih->task)
     545             :   {
     546           0 :     GNUNET_SCHEDULER_cancel (ih->task);
     547           0 :     ih->task = NULL;
     548             :   }
     549           0 :   GNUNET_free (ih);
     550           0 : }
     551             : 
     552             : 
     553             : /**
     554             :  * Function called to asynchronously return the final
     555             :  * result to the callback.
     556             :  *
     557             :  * @param cls a `struct TALER_KYCLOGIC_ProofHandle`
     558             :  */
     559             : static void
     560           0 : return_proof_response (void *cls)
     561             : {
     562           0 :   struct TALER_KYCLOGIC_ProofHandle *ph = cls;
     563             : 
     564           0 :   ph->task = NULL;
     565           0 :   ph->cb (ph->cb_cls,
     566             :           ph->status,
     567           0 :           ph->provider_user_id,
     568           0 :           ph->provider_legitimization_id,
     569           0 :           GNUNET_TIME_relative_to_absolute (ph->pd->validity),
     570             :           ph->http_status,
     571             :           ph->response);
     572           0 :   GNUNET_free (ph->provider_user_id);
     573           0 :   GNUNET_free (ph);
     574           0 : }
     575             : 
     576             : 
     577             : /**
     578             :  * The request for @a ph failed. We may have gotten a useful error
     579             :  * message in @a j. Generate a failure response.
     580             :  *
     581             :  * @param[in,out] ph request that failed
     582             :  * @param j reply from the server (or NULL)
     583             :  */
     584             : static void
     585           0 : handle_proof_error (struct TALER_KYCLOGIC_ProofHandle *ph,
     586             :                     const json_t *j)
     587             : {
     588             :   const char *msg;
     589             :   const char *desc;
     590             :   struct GNUNET_JSON_Specification spec[] = {
     591           0 :     GNUNET_JSON_spec_string ("error",
     592             :                              &msg),
     593           0 :     GNUNET_JSON_spec_string ("error_description",
     594             :                              &desc),
     595           0 :     GNUNET_JSON_spec_end ()
     596             :   };
     597             : 
     598             :   {
     599             :     enum GNUNET_GenericReturnValue res;
     600             :     const char *emsg;
     601             :     unsigned int line;
     602             : 
     603           0 :     res = GNUNET_JSON_parse (j,
     604             :                              spec,
     605             :                              &emsg,
     606             :                              &line);
     607           0 :     if (GNUNET_OK != res)
     608             :     {
     609           0 :       GNUNET_break_op (0);
     610           0 :       ph->status = TALER_KYCLOGIC_STATUS_PROVIDER_FAILED;
     611             :       ph->response
     612           0 :         = TALER_MHD_make_error (
     613             :             TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
     614             :             "Unexpected response from KYC gateway");
     615             :       ph->http_status
     616           0 :         = MHD_HTTP_BAD_GATEWAY;
     617           0 :       return;
     618             :     }
     619             :   }
     620             :   /* case TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_AUTHORZATION_FAILED,
     621             :      we MAY want to in the future look at the requested content type
     622             :      and possibly respond in JSON if indicated. */
     623             :   {
     624             :     char *reply;
     625             : 
     626           0 :     GNUNET_asprintf (&reply,
     627             :                      "<html><head><title>%s</title></head><body><h1>%s</h1><p>%s</p></body></html>",
     628             :                      msg,
     629             :                      msg,
     630             :                      desc);
     631           0 :     ph->status = TALER_KYCLOGIC_STATUS_USER_ABORTED;
     632             :     ph->response
     633           0 :       = MHD_create_response_from_buffer (strlen (reply),
     634             :                                          reply,
     635             :                                          MHD_RESPMEM_MUST_COPY);
     636           0 :     GNUNET_assert (NULL != ph->response);
     637           0 :     GNUNET_free (reply);
     638             :   }
     639           0 :   ph->status = TALER_KYCLOGIC_STATUS_USER_ABORTED;
     640           0 :   ph->http_status = MHD_HTTP_FORBIDDEN;
     641             : }
     642             : 
     643             : 
     644             : /**
     645             :  * The request for @a ph succeeded (presumably).
     646             :  * Call continuation with the result.
     647             :  *
     648             :  * @param[in,out] ph request that succeeded
     649             :  * @param j reply from the server
     650             :  */
     651             : static void
     652           0 : parse_proof_success_reply (struct TALER_KYCLOGIC_ProofHandle *ph,
     653             :                            const json_t *j)
     654             : {
     655             :   const char *state;
     656             :   json_t *data;
     657             :   struct GNUNET_JSON_Specification spec[] = {
     658           0 :     GNUNET_JSON_spec_string ("status",
     659             :                              &state),
     660           0 :     GNUNET_JSON_spec_json ("data",
     661             :                            &data),
     662           0 :     GNUNET_JSON_spec_end ()
     663             :   };
     664             :   enum GNUNET_GenericReturnValue res;
     665             :   const char *emsg;
     666             :   unsigned int line;
     667             : 
     668           0 :   res = GNUNET_JSON_parse (j,
     669             :                            spec,
     670             :                            &emsg,
     671             :                            &line);
     672           0 :   if (GNUNET_OK != res)
     673             :   {
     674           0 :     GNUNET_break_op (0);
     675           0 :     json_dumpf (j,
     676             :                 stderr,
     677             :                 JSON_INDENT (2));
     678           0 :     ph->status = TALER_KYCLOGIC_STATUS_PROVIDER_FAILED;
     679             :     ph->response
     680           0 :       = TALER_MHD_make_error (
     681             :           TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
     682             :           "Unexpected response from KYC gateway");
     683             :     ph->http_status
     684           0 :       = MHD_HTTP_BAD_GATEWAY;
     685           0 :     return;
     686             :   }
     687           0 :   if (0 != strcasecmp (state,
     688             :                        "success"))
     689             :   {
     690           0 :     GNUNET_break_op (0);
     691           0 :     handle_proof_error (ph,
     692             :                         j);
     693           0 :     return;
     694             :   }
     695             :   {
     696             :     const char *id;
     697             :     struct GNUNET_JSON_Specification ispec[] = {
     698           0 :       GNUNET_JSON_spec_string ("id",
     699             :                                &id),
     700           0 :       GNUNET_JSON_spec_end ()
     701             :     };
     702             : 
     703           0 :     res = GNUNET_JSON_parse (data,
     704             :                              ispec,
     705             :                              &emsg,
     706             :                              &line);
     707           0 :     if (GNUNET_OK != res)
     708             :     {
     709           0 :       GNUNET_break_op (0);
     710           0 :       json_dumpf (data,
     711             :                   stderr,
     712             :                   JSON_INDENT (2));
     713           0 :       ph->status = TALER_KYCLOGIC_STATUS_PROVIDER_FAILED;
     714             :       ph->response
     715           0 :         = TALER_MHD_make_error (
     716             :             TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
     717             :             "Unexpected response from KYC gateway");
     718             :       ph->http_status
     719           0 :         = MHD_HTTP_BAD_GATEWAY;
     720           0 :       return;
     721             :     }
     722           0 :     ph->status = TALER_KYCLOGIC_STATUS_SUCCESS;
     723           0 :     ph->response = MHD_create_response_from_buffer (0,
     724             :                                                     "",
     725             :                                                     MHD_RESPMEM_PERSISTENT);
     726           0 :     GNUNET_assert (NULL != ph->response);
     727           0 :     GNUNET_break (MHD_YES ==
     728             :                   MHD_add_response_header (
     729             :                     ph->response,
     730             :                     MHD_HTTP_HEADER_LOCATION,
     731             :                     ph->pd->post_kyc_redirect_url));
     732           0 :     ph->http_status = MHD_HTTP_SEE_OTHER;
     733           0 :     ph->provider_user_id = GNUNET_strdup (id);
     734             :   }
     735             : }
     736             : 
     737             : 
     738             : /**
     739             :  * After we are done with the CURL interaction we
     740             :  * need to update our database state with the information
     741             :  * retrieved.
     742             :  *
     743             :  * @param cls our `struct TALER_KYCLOGIC_ProofHandle`
     744             :  * @param response_code HTTP response code from server, 0 on hard error
     745             :  * @param response in JSON, NULL if response was not in JSON format
     746             :  */
     747             : static void
     748           0 : handle_curl_proof_finished (void *cls,
     749             :                             long response_code,
     750             :                             const void *response)
     751             : {
     752           0 :   struct TALER_KYCLOGIC_ProofHandle *ph = cls;
     753           0 :   const json_t *j = response;
     754             : 
     755           0 :   ph->job = NULL;
     756           0 :   switch (response_code)
     757             :   {
     758           0 :   case MHD_HTTP_OK:
     759           0 :     parse_proof_success_reply (ph,
     760             :                                j);
     761           0 :     break;
     762           0 :   default:
     763           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     764             :                 "OAuth2.0 info URL returned HTTP status %u\n",
     765             :                 (unsigned int) response_code);
     766           0 :     handle_proof_error (ph,
     767             :                         j);
     768           0 :     break;
     769             :   }
     770           0 :   ph->task = GNUNET_SCHEDULER_add_now (&return_proof_response,
     771             :                                        ph);
     772           0 : }
     773             : 
     774             : 
     775             : /**
     776             :  * After we are done with the CURL interaction we
     777             :  * need to fetch the user's account details.
     778             :  *
     779             :  * @param cls our `struct KycProofContext`
     780             :  * @param response_code HTTP response code from server, 0 on hard error
     781             :  * @param response in JSON, NULL if response was not in JSON format
     782             :  */
     783             : static void
     784           0 : handle_curl_login_finished (void *cls,
     785             :                             long response_code,
     786             :                             const void *response)
     787             : {
     788           0 :   struct TALER_KYCLOGIC_ProofHandle *ph = cls;
     789           0 :   const json_t *j = response;
     790             : 
     791           0 :   ph->job = NULL;
     792           0 :   switch (response_code)
     793             :   {
     794           0 :   case MHD_HTTP_OK:
     795             :     {
     796             :       const char *access_token;
     797             :       const char *token_type;
     798             :       uint64_t expires_in_s;
     799             :       const char *refresh_token;
     800             :       struct GNUNET_JSON_Specification spec[] = {
     801           0 :         GNUNET_JSON_spec_string ("access_token",
     802             :                                  &access_token),
     803           0 :         GNUNET_JSON_spec_string ("token_type",
     804             :                                  &token_type),
     805           0 :         GNUNET_JSON_spec_uint64 ("expires_in",
     806             :                                  &expires_in_s),
     807           0 :         GNUNET_JSON_spec_string ("refresh_token",
     808             :                                  &refresh_token),
     809           0 :         GNUNET_JSON_spec_end ()
     810             :       };
     811             :       CURL *eh;
     812             : 
     813             :       {
     814             :         enum GNUNET_GenericReturnValue res;
     815             :         const char *emsg;
     816             :         unsigned int line;
     817             : 
     818           0 :         res = GNUNET_JSON_parse (j,
     819             :                                  spec,
     820             :                                  &emsg,
     821             :                                  &line);
     822           0 :         if (GNUNET_OK != res)
     823             :         {
     824           0 :           GNUNET_break_op (0);
     825             :           ph->response
     826           0 :             = TALER_MHD_make_error (
     827             :                 TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
     828             :                 "Unexpected response from KYC gateway");
     829             :           ph->http_status
     830           0 :             = MHD_HTTP_BAD_GATEWAY;
     831           0 :           break;
     832             :         }
     833             :       }
     834           0 :       if (0 != strcasecmp (token_type,
     835             :                            "bearer"))
     836             :       {
     837           0 :         GNUNET_break_op (0);
     838             :         ph->response
     839           0 :           = TALER_MHD_make_error (
     840             :               TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
     841             :               "Unexpected token type in response from KYC gateway");
     842             :         ph->http_status
     843           0 :           = MHD_HTTP_BAD_GATEWAY;
     844           0 :         break;
     845             :       }
     846             : 
     847             :       /* We guard against a few characters that could
     848             :          conceivably be abused to mess with the HTTP header */
     849           0 :       if ( (NULL != strchr (access_token,
     850           0 :                             '\n')) ||
     851           0 :            (NULL != strchr (access_token,
     852           0 :                             '\r')) ||
     853           0 :            (NULL != strchr (access_token,
     854           0 :                             ' ')) ||
     855           0 :            (NULL != strchr (access_token,
     856             :                             ';')) )
     857             :       {
     858           0 :         GNUNET_break_op (0);
     859             :         ph->response
     860           0 :           = TALER_MHD_make_error (
     861             :               TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
     862             :               "Illegal character in access token");
     863             :         ph->http_status
     864           0 :           = MHD_HTTP_BAD_GATEWAY;
     865           0 :         break;
     866             :       }
     867             : 
     868           0 :       eh = curl_easy_init ();
     869           0 :       if (NULL == eh)
     870             :       {
     871           0 :         GNUNET_break_op (0);
     872             :         ph->response
     873           0 :           = TALER_MHD_make_error (
     874             :               TALER_EC_GENERIC_ALLOCATION_FAILURE,
     875             :               "curl_easy_init");
     876             :         ph->http_status
     877           0 :           = MHD_HTTP_INTERNAL_SERVER_ERROR;
     878           0 :         break;
     879             :       }
     880           0 :       GNUNET_assert (CURLE_OK ==
     881             :                      curl_easy_setopt (eh,
     882             :                                        CURLOPT_URL,
     883             :                                        ph->pd->info_url));
     884             :       {
     885             :         char *hdr;
     886             :         struct curl_slist *slist;
     887             : 
     888           0 :         GNUNET_asprintf (&hdr,
     889             :                          "%s: Bearer %s",
     890             :                          MHD_HTTP_HEADER_AUTHORIZATION,
     891             :                          access_token);
     892           0 :         slist = curl_slist_append (NULL,
     893             :                                    hdr);
     894           0 :         ph->job = GNUNET_CURL_job_add2 (ph->pd->ps->curl_ctx,
     895             :                                         eh,
     896             :                                         slist,
     897             :                                         &handle_curl_proof_finished,
     898             :                                         ph);
     899           0 :         curl_slist_free_all (slist);
     900           0 :         GNUNET_free (hdr);
     901             :       }
     902           0 :       return;
     903             :     }
     904           0 :   default:
     905           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     906             :                 "OAuth2.0 login URL returned HTTP status %u\n",
     907             :                 (unsigned int) response_code);
     908           0 :     handle_proof_error (ph,
     909             :                         j);
     910           0 :     break;
     911             :   }
     912           0 :   return_proof_response (ph);
     913             : }
     914             : 
     915             : 
     916             : /**
     917             :  * Check KYC status and return status to human.
     918             :  *
     919             :  * @param cls the @e cls of this struct with the plugin-specific state
     920             :  * @param pd provider configuration details
     921             :  * @param url_path rest of the URL after `/kyc-webhook/`
     922             :  * @param connection MHD connection object (for HTTP headers)
     923             :  * @param account_id which account to trigger process for
     924             :  * @param process_row row in the legitimization processes table the legitimization is for
     925             :  * @param provider_user_id user ID (or NULL) the proof is for
     926             :  * @param provider_legitimization_id legitimization ID the proof is for
     927             :  * @param cb function to call with the result
     928             :  * @param cb_cls closure for @a cb
     929             :  * @return handle to cancel operation early
     930             :  */
     931             : static struct TALER_KYCLOGIC_ProofHandle *
     932           0 : oauth2_proof (void *cls,
     933             :               const struct TALER_KYCLOGIC_ProviderDetails *pd,
     934             :               const char *const url_path[],
     935             :               struct MHD_Connection *connection,
     936             :               const struct TALER_PaytoHashP *account_id,
     937             :               uint64_t process_row,
     938             :               const char *provider_user_id,
     939             :               const char *provider_legitimization_id,
     940             :               TALER_KYCLOGIC_ProofCallback cb,
     941             :               void *cb_cls)
     942             : {
     943           0 :   struct PluginState *ps = cls;
     944             :   struct TALER_KYCLOGIC_ProofHandle *ph;
     945             :   const char *code;
     946             : 
     947             :   (void) url_path;
     948           0 :   GNUNET_break (NULL == provider_user_id);
     949           0 :   ph = GNUNET_new (struct TALER_KYCLOGIC_ProofHandle);
     950           0 :   GNUNET_snprintf (ph->provider_legitimization_id,
     951             :                    sizeof (ph->provider_legitimization_id),
     952             :                    "%llu",
     953             :                    (unsigned long long) process_row);
     954           0 :   if ( (NULL != provider_legitimization_id) &&
     955           0 :        (0 != strcmp (provider_legitimization_id,
     956           0 :                      ph->provider_legitimization_id)))
     957             :   {
     958           0 :     GNUNET_break (0);
     959           0 :     GNUNET_free (ph);
     960           0 :     return NULL;
     961             :   }
     962           0 :   ph->pd = pd;
     963           0 :   ph->connection = connection;
     964           0 :   ph->h_payto = *account_id;
     965           0 :   ph->cb = cb;
     966           0 :   ph->cb_cls = cb_cls;
     967           0 :   code = MHD_lookup_connection_value (connection,
     968             :                                       MHD_GET_ARGUMENT_KIND,
     969             :                                       "code");
     970           0 :   if (NULL == code)
     971             :   {
     972           0 :     GNUNET_break_op (0);
     973           0 :     ph->status = TALER_KYCLOGIC_STATUS_USER_PENDING;
     974           0 :     ph->http_status = MHD_HTTP_BAD_REQUEST;
     975           0 :     ph->response = TALER_MHD_make_error (
     976             :       TALER_EC_GENERIC_PARAMETER_MALFORMED,
     977             :       "code");
     978           0 :     ph->task = GNUNET_SCHEDULER_add_now (&return_proof_response,
     979             :                                          ph);
     980           0 :     return ph;
     981             :   }
     982             : 
     983           0 :   ph->eh = curl_easy_init ();
     984           0 :   if (NULL == ph->eh)
     985             :   {
     986           0 :     GNUNET_break (0);
     987           0 :     ph->status = TALER_KYCLOGIC_STATUS_USER_PENDING;
     988           0 :     ph->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
     989           0 :     ph->response = TALER_MHD_make_error (
     990             :       TALER_EC_GENERIC_ALLOCATION_FAILURE,
     991             :       "curl_easy_init");
     992           0 :     ph->task = GNUNET_SCHEDULER_add_now (&return_proof_response,
     993             :                                          ph);
     994           0 :     return ph;
     995             :   }
     996             : 
     997           0 :   GNUNET_assert (CURLE_OK ==
     998             :                  curl_easy_setopt (ph->eh,
     999             :                                    CURLOPT_URL,
    1000             :                                    pd->auth_url));
    1001           0 :   GNUNET_assert (CURLE_OK ==
    1002             :                  curl_easy_setopt (ph->eh,
    1003             :                                    CURLOPT_POST,
    1004             :                                    1));
    1005             :   {
    1006             :     char *client_id;
    1007             :     char *redirect_uri;
    1008             :     char *client_secret;
    1009             :     char *authorization_code;
    1010             : 
    1011           0 :     client_id = curl_easy_escape (ph->eh,
    1012           0 :                                   pd->client_id,
    1013             :                                   0);
    1014           0 :     GNUNET_assert (NULL != client_id);
    1015             :     {
    1016             :       char *request_uri;
    1017             : 
    1018           0 :       GNUNET_asprintf (&request_uri,
    1019             :                        "%s?client_id=%s",
    1020             :                        pd->login_url,
    1021             :                        pd->client_id);
    1022           0 :       redirect_uri = curl_easy_escape (ph->eh,
    1023             :                                        request_uri,
    1024             :                                        0);
    1025           0 :       GNUNET_free (request_uri);
    1026             :     }
    1027           0 :     GNUNET_assert (NULL != redirect_uri);
    1028           0 :     client_secret = curl_easy_escape (ph->eh,
    1029           0 :                                       pd->client_secret,
    1030             :                                       0);
    1031           0 :     GNUNET_assert (NULL != client_secret);
    1032           0 :     authorization_code = curl_easy_escape (ph->eh,
    1033             :                                            code,
    1034             :                                            0);
    1035           0 :     GNUNET_assert (NULL != authorization_code);
    1036           0 :     GNUNET_asprintf (&ph->post_body,
    1037             :                      "client_id=%s&redirect_uri=%s&client_secret=%s&code=%s&grant_type=authorization_code",
    1038             :                      client_id,
    1039             :                      redirect_uri,
    1040             :                      client_secret,
    1041             :                      authorization_code);
    1042           0 :     curl_free (authorization_code);
    1043           0 :     curl_free (client_secret);
    1044           0 :     curl_free (redirect_uri);
    1045           0 :     curl_free (client_id);
    1046             :   }
    1047           0 :   GNUNET_assert (CURLE_OK ==
    1048             :                  curl_easy_setopt (ph->eh,
    1049             :                                    CURLOPT_POSTFIELDS,
    1050             :                                    ph->post_body));
    1051           0 :   GNUNET_assert (CURLE_OK ==
    1052             :                  curl_easy_setopt (ph->eh,
    1053             :                                    CURLOPT_FOLLOWLOCATION,
    1054             :                                    1L));
    1055             :   /* limit MAXREDIRS to 5 as a simple security measure against
    1056             :      a potential infinite loop caused by a malicious target */
    1057           0 :   GNUNET_assert (CURLE_OK ==
    1058             :                  curl_easy_setopt (ph->eh,
    1059             :                                    CURLOPT_MAXREDIRS,
    1060             :                                    5L));
    1061             : 
    1062           0 :   ph->job = GNUNET_CURL_job_add (ps->curl_ctx,
    1063             :                                  ph->eh,
    1064             :                                  &handle_curl_login_finished,
    1065             :                                  ph);
    1066           0 :   return ph;
    1067             : }
    1068             : 
    1069             : 
    1070             : /**
    1071             :  * Cancel KYC proof.
    1072             :  *
    1073             :  * @param[in] ph handle of operation to cancel
    1074             :  */
    1075             : static void
    1076           0 : oauth2_proof_cancel (struct TALER_KYCLOGIC_ProofHandle *ph)
    1077             : {
    1078           0 :   if (NULL != ph->task)
    1079             :   {
    1080           0 :     GNUNET_SCHEDULER_cancel (ph->task);
    1081           0 :     ph->task = NULL;
    1082             :   }
    1083           0 :   if (NULL != ph->job)
    1084             :   {
    1085           0 :     GNUNET_CURL_job_cancel (ph->job);
    1086           0 :     ph->job = NULL;
    1087             :   }
    1088           0 :   if (NULL != ph->response)
    1089             :   {
    1090           0 :     MHD_destroy_response (ph->response);
    1091           0 :     ph->response = NULL;
    1092             :   }
    1093           0 :   GNUNET_free (ph->post_body);
    1094           0 :   GNUNET_free (ph);
    1095           0 : }
    1096             : 
    1097             : 
    1098             : /**
    1099             :  * Function to asynchronously return the 404 not found
    1100             :  * page for the webhook.
    1101             :  *
    1102             :  * @param cls the `struct TALER_KYCLOGIC_WebhookHandle *`
    1103             :  */
    1104             : static void
    1105           0 : wh_return_not_found (void *cls)
    1106             : {
    1107           0 :   struct TALER_KYCLOGIC_WebhookHandle *wh = cls;
    1108             :   struct MHD_Response *response;
    1109             : 
    1110           0 :   wh->task = NULL;
    1111           0 :   response = MHD_create_response_from_buffer (0,
    1112             :                                               "",
    1113             :                                               MHD_RESPMEM_PERSISTENT);
    1114           0 :   wh->cb (wh->cb_cls,
    1115             :           0LLU,
    1116             :           NULL,
    1117             :           NULL,
    1118             :           NULL,
    1119             :           NULL,
    1120             :           TALER_KYCLOGIC_STATUS_KEEP,
    1121           0 :           GNUNET_TIME_UNIT_ZERO_ABS,
    1122             :           MHD_HTTP_NOT_FOUND,
    1123             :           response);
    1124           0 :   GNUNET_free (wh);
    1125           0 : }
    1126             : 
    1127             : 
    1128             : /**
    1129             :  * Check KYC status and return result for Webhook.
    1130             :  *
    1131             :  * @param cls the @e cls of this struct with the plugin-specific state
    1132             :  * @param pd provider configuration details
    1133             :  * @param plc callback to lookup accounts with
    1134             :  * @param plc_cls closure for @a plc
    1135             :  * @param http_method HTTP method used for the webhook
    1136             :  * @param url_path rest of the URL after `/kyc-webhook/$LOGIC/`, as NULL-terminated array
    1137             :  * @param connection MHD connection object (for HTTP headers)
    1138             :  * @param body HTTP request body, or NULL if not available
    1139             :  * @param cb function to call with the result
    1140             :  * @param cb_cls closure for @a cb
    1141             :  * @return handle to cancel operation early
    1142             :  */
    1143             : static struct TALER_KYCLOGIC_WebhookHandle *
    1144           0 : oauth2_webhook (void *cls,
    1145             :                 const struct TALER_KYCLOGIC_ProviderDetails *pd,
    1146             :                 TALER_KYCLOGIC_ProviderLookupCallback plc,
    1147             :                 void *plc_cls,
    1148             :                 const char *http_method,
    1149             :                 const char *const url_path[],
    1150             :                 struct MHD_Connection *connection,
    1151             :                 const json_t *body,
    1152             :                 TALER_KYCLOGIC_WebhookCallback cb,
    1153             :                 void *cb_cls)
    1154             : {
    1155           0 :   struct PluginState *ps = cls;
    1156             :   struct TALER_KYCLOGIC_WebhookHandle *wh;
    1157             : 
    1158             :   (void) pd;
    1159             :   (void) plc;
    1160             :   (void) plc_cls;
    1161             :   (void) http_method;
    1162             :   (void) url_path;
    1163             :   (void) connection;
    1164             :   (void) body;
    1165           0 :   wh = GNUNET_new (struct TALER_KYCLOGIC_WebhookHandle);
    1166           0 :   wh->cb = cb;
    1167           0 :   wh->cb_cls = cb_cls;
    1168           0 :   wh->ps = ps;
    1169           0 :   wh->task = GNUNET_SCHEDULER_add_now (&wh_return_not_found,
    1170             :                                        wh);
    1171           0 :   return wh;
    1172             : }
    1173             : 
    1174             : 
    1175             : /**
    1176             :  * Cancel KYC webhook execution.
    1177             :  *
    1178             :  * @param[in] wh handle of operation to cancel
    1179             :  */
    1180             : static void
    1181           0 : oauth2_webhook_cancel (struct TALER_KYCLOGIC_WebhookHandle *wh)
    1182             : {
    1183           0 :   GNUNET_SCHEDULER_cancel (wh->task);
    1184           0 :   GNUNET_free (wh);
    1185           0 : }
    1186             : 
    1187             : 
    1188             : /**
    1189             :  * Initialize OAuth2.0 KYC logic plugin
    1190             :  *
    1191             :  * @param cls a configuration instance
    1192             :  * @return NULL on error, otherwise a `struct TALER_KYCLOGIC_Plugin`
    1193             :  */
    1194             : void *
    1195           1 : libtaler_plugin_kyclogic_oauth2_init (void *cls)
    1196             : {
    1197           1 :   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
    1198             :   struct TALER_KYCLOGIC_Plugin *plugin;
    1199             :   struct PluginState *ps;
    1200             : 
    1201           1 :   ps = GNUNET_new (struct PluginState);
    1202           1 :   ps->cfg = cfg;
    1203           1 :   if (GNUNET_OK !=
    1204           1 :       GNUNET_CONFIGURATION_get_value_string (cfg,
    1205             :                                              "exchange",
    1206             :                                              "BASE_URL",
    1207             :                                              &ps->exchange_base_url))
    1208             :   {
    1209           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1210             :                                "exchange",
    1211             :                                "BASE_URL");
    1212           0 :     GNUNET_free (ps);
    1213           0 :     return NULL;
    1214             :   }
    1215             :   ps->curl_ctx
    1216           2 :     = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
    1217           1 :                         &ps->curl_rc);
    1218           1 :   if (NULL == ps->curl_ctx)
    1219             :   {
    1220           0 :     GNUNET_break (0);
    1221           0 :     GNUNET_free (ps->exchange_base_url);
    1222           0 :     GNUNET_free (ps);
    1223           0 :     return NULL;
    1224             :   }
    1225           1 :   ps->curl_rc = GNUNET_CURL_gnunet_rc_create (ps->curl_ctx);
    1226             : 
    1227           1 :   plugin = GNUNET_new (struct TALER_KYCLOGIC_Plugin);
    1228           1 :   plugin->cls = ps;
    1229             :   plugin->load_configuration
    1230           1 :     = &oauth2_load_configuration;
    1231             :   plugin->unload_configuration
    1232           1 :     = &oauth2_unload_configuration;
    1233             :   plugin->initiate
    1234           1 :     = &oauth2_initiate;
    1235             :   plugin->initiate_cancel
    1236           1 :     = &oauth2_initiate_cancel;
    1237             :   plugin->proof
    1238           1 :     = &oauth2_proof;
    1239             :   plugin->proof_cancel
    1240           1 :     = &oauth2_proof_cancel;
    1241             :   plugin->webhook
    1242           1 :     = &oauth2_webhook;
    1243             :   plugin->webhook_cancel
    1244           1 :     = &oauth2_webhook_cancel;
    1245           1 :   return plugin;
    1246             : }
    1247             : 
    1248             : 
    1249             : /**
    1250             :  * Unload authorization plugin
    1251             :  *
    1252             :  * @param cls a `struct TALER_KYCLOGIC_Plugin`
    1253             :  * @return NULL (always)
    1254             :  */
    1255             : void *
    1256           0 : libtaler_plugin_kyclogic_oauth2_done (void *cls)
    1257             : {
    1258           0 :   struct TALER_KYCLOGIC_Plugin *plugin = cls;
    1259           0 :   struct PluginState *ps = plugin->cls;
    1260             : 
    1261           0 :   if (NULL != ps->curl_ctx)
    1262             :   {
    1263           0 :     GNUNET_CURL_fini (ps->curl_ctx);
    1264           0 :     ps->curl_ctx = NULL;
    1265             :   }
    1266           0 :   if (NULL != ps->curl_rc)
    1267             :   {
    1268           0 :     GNUNET_CURL_gnunet_rc_destroy (ps->curl_rc);
    1269           0 :     ps->curl_rc = NULL;
    1270             :   }
    1271           0 :   GNUNET_free (ps->exchange_base_url);
    1272           0 :   GNUNET_free (ps);
    1273           0 :   GNUNET_free (plugin);
    1274           0 :   return NULL;
    1275             : }

Generated by: LCOV version 1.14