From ee57a5f9c481555d0462012439a99778a2dbcbcb Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 3 Nov 2023 14:44:25 +0100 Subject: add external converter logic for oauth2 plugin --- src/kyclogic/Makefile.am | 5 +- src/kyclogic/kyclogic-oauth2.conf | 6 +- src/kyclogic/plugin_kyclogic_oauth2.c | 204 +++++++++------------ .../taler-exchange-kyc-oauth2-challenger.sh | 0 src/kyclogic/taler-exchange-kyc-oauth2-nda.sh | 0 .../taler-exchange-kyc-oauth2-test-converter.sh | 23 +++ 6 files changed, 117 insertions(+), 121 deletions(-) mode change 100644 => 100755 src/kyclogic/taler-exchange-kyc-oauth2-challenger.sh mode change 100644 => 100755 src/kyclogic/taler-exchange-kyc-oauth2-nda.sh create mode 100755 src/kyclogic/taler-exchange-kyc-oauth2-test-converter.sh (limited to 'src/kyclogic') diff --git a/src/kyclogic/Makefile.am b/src/kyclogic/Makefile.am index 91ec901e9..3e98a956f 100644 --- a/src/kyclogic/Makefile.am +++ b/src/kyclogic/Makefile.am @@ -16,7 +16,10 @@ pkgcfg_DATA = \ bin_SCRIPTS = \ taler-exchange-kyc-kycaid-converter.sh \ - taler-exchange-kyc-persona-converter.sh + taler-exchange-kyc-persona-converter.sh \ + taler-exchange-kyc-oauth2-test-converter.sh \ + taler-exchange-kyc-oauth2-challenger.sh \ + taler-exchange-kyc-oauth2-nda.sh EXTRA_DIST = \ $(pkgcfg_DATA) \ diff --git a/src/kyclogic/kyclogic-oauth2.conf b/src/kyclogic/kyclogic-oauth2.conf index 61b38367f..57e1fc13a 100644 --- a/src/kyclogic/kyclogic-oauth2.conf +++ b/src/kyclogic/kyclogic-oauth2.conf @@ -29,7 +29,7 @@ KYC_OAUTH2_CLIENT_SECRET = password # Mustach template that converts OAuth2.0 data about the user # into GNU Taler standardized attribute data. # -# This is just an example, details will depend on the -# provider! +# This is just an example, you need to pick the right converter +# for the provider! # -KYC_OAUTH2_ATTRIBUTE_TEMPLATE = "{"fullname":"{{last_name}}, {{first_name}}","phone":"{{phone}}"}" \ No newline at end of file +KYC_OAUTH2_CONVERTER_HELPER = taler-exchange-kyc-oauth2-converter.sh diff --git a/src/kyclogic/plugin_kyclogic_oauth2.c b/src/kyclogic/plugin_kyclogic_oauth2.c index 4bd0bbfef..5ef1330ad 100644 --- a/src/kyclogic/plugin_kyclogic_oauth2.c +++ b/src/kyclogic/plugin_kyclogic_oauth2.c @@ -113,10 +113,10 @@ struct TALER_KYCLOGIC_ProviderDetails char *post_kyc_redirect_url; /** - * Template for converting user-data returned by - * the provider into our KYC attribute data. + * Name of the program we use to convert outputs + * from Persona into our JSON inputs. */ - char *attribute_template; + char *conversion_binary; /** * Validity time for a successful KYC process. @@ -187,6 +187,12 @@ struct TALER_KYCLOGIC_ProofHandle */ struct MHD_Connection *connection; + /** + * Handle to an external process that converts the + * Persona response to our internal format. + */ + struct TALER_JSON_ExternalConversion *ec; + /** * Hash of the payto URI that this is about. */ @@ -301,7 +307,7 @@ oauth2_unload_configuration (struct TALER_KYCLOGIC_ProviderDetails *pd) GNUNET_free (pd->client_id); GNUNET_free (pd->client_secret); GNUNET_free (pd->post_kyc_redirect_url); - GNUNET_free (pd->attribute_template); + GNUNET_free (pd->conversion_binary); GNUNET_free (pd); } @@ -501,16 +507,14 @@ oauth2_load_configuration (void *cls, if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (ps->cfg, provider_section_name, - "KYC_OAUTH2_ATTRIBUTE_TEMPLATE", - &s)) + "KYC_OAUTH2_CONVERTER_HELPER", + &pd->conversion_binary)) { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, provider_section_name, - "KYC_OAUTH2_ATTRIBUTE_TEMPLATE"); - } - else - { - pd->attribute_template = s; + "KYC_OAUTH2_CONVERTER_HELPER"); + oauth2_unload_configuration (pd); + return NULL; } return pd; @@ -791,6 +795,11 @@ oauth2_initiate_cancel (struct TALER_KYCLOGIC_InitiateHandle *ih) static void oauth2_proof_cancel (struct TALER_KYCLOGIC_ProofHandle *ph) { + if (NULL != ph->ec) + { + TALER_JSON_external_conversion_stop (ph->ec); + ph->ec = NULL; + } if (NULL != ph->task) { GNUNET_SCHEDULER_cancel (ph->task); @@ -907,93 +916,26 @@ handle_proof_error (struct TALER_KYCLOGIC_ProofHandle *ph, /** - * Convert user data returned by the provider into - * standardized attribute data. - * - * @param pd our provider configuration - * @param data user-data given by the provider - * @return converted KYC attribute data object - */ -static json_t * -data2attributes (const struct TALER_KYCLOGIC_ProviderDetails *pd, - const json_t *data) -{ - json_t *ret; - void *attr_data; - size_t attr_size; - int rv; - json_error_t err; - - if (NULL == pd->attribute_template) - return json_object (); - if (0 != - (rv = TALER_TEMPLATING_fill (pd->attribute_template, - data, - &attr_data, - &attr_size))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to convert KYC provider data to attributes: %d\n", - rv); - json_dumpf (data, - stderr, - JSON_INDENT (2)); - return NULL; - } - ret = json_loadb (attr_data, - attr_size, - JSON_REJECT_DUPLICATES, - &err); - GNUNET_free (attr_data); - if (NULL == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse converted KYC attributes as JSON: %s (at offset %d)\n", - err.text, - err.position); - return NULL; - } - return ret; -} - - -/** - * The request for @a ph succeeded (presumably). - * Call continuation with the result. + * Type of a callback that receives a JSON @a result. * - * @param[in,out] ph request that succeeded - * @param j reply from the server + * @param cls closure with a `struct TALER_KYCLOGIC_ProofHandle *` + * @param status_type how did the process die + * @param code termination status code from the process + * @param attr result some JSON result, NULL if we failed to get an JSON output */ static void -parse_proof_success_reply (struct TALER_KYCLOGIC_ProofHandle *ph, - const json_t *j) +converted_proof_cb (void *cls, + enum GNUNET_OS_ProcessStatusType status_type, + unsigned long code, + const json_t *attr) { - // FIXME: this is not OAuth2.0, this is - // already implementation-specific! - // => move into helper shell script! - const char *state; - const json_t *data; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_string ("status", - &state), - GNUNET_JSON_spec_object_const ("data", - &data), - GNUNET_JSON_spec_end () - }; - enum GNUNET_GenericReturnValue res; - const char *emsg; - unsigned int line; - - res = GNUNET_JSON_parse (j, - spec, - &emsg, - &line); - if (GNUNET_OK != res) + struct TALER_KYCLOGIC_ProofHandle *ph = cls; + + ph->ec = NULL; + if ( (NULL == attr) || + (0 != code) ) { GNUNET_break_op (0); - json_dumpf (j, - stderr, - JSON_INDENT (2)); ph->status = TALER_KYCLOGIC_STATUS_PROVIDER_FAILED; ph->response = TALER_MHD_make_error ( @@ -1001,16 +943,11 @@ parse_proof_success_reply (struct TALER_KYCLOGIC_ProofHandle *ph, "Unexpected response from KYC gateway: proof success must contain data and status"); ph->http_status = MHD_HTTP_BAD_GATEWAY; + ph->task = GNUNET_SCHEDULER_add_now (&return_proof_response, + ph); return; } - if (0 != strcasecmp (state, - "success")) - { - GNUNET_break_op (0); - handle_proof_error (ph, - j); - return; - } + { const char *id; struct GNUNET_JSON_Specification ispec[] = { @@ -1018,15 +955,18 @@ parse_proof_success_reply (struct TALER_KYCLOGIC_ProofHandle *ph, &id), GNUNET_JSON_spec_end () }; + enum GNUNET_GenericReturnValue res; + const char *emsg; + unsigned int line; - res = GNUNET_JSON_parse (data, + res = GNUNET_JSON_parse (attr, ispec, &emsg, &line); if (GNUNET_OK != res) { GNUNET_break_op (0); - json_dumpf (data, + json_dumpf (attr, stderr, JSON_INDENT (2)); ph->status = TALER_KYCLOGIC_STATUS_PROVIDER_FAILED; @@ -1038,21 +978,51 @@ parse_proof_success_reply (struct TALER_KYCLOGIC_ProofHandle *ph, = MHD_HTTP_BAD_GATEWAY; return; } - ph->status = TALER_KYCLOGIC_STATUS_SUCCESS; - ph->response = MHD_create_response_from_buffer (0, - "", - MHD_RESPMEM_PERSISTENT); - GNUNET_assert (NULL != ph->response); - GNUNET_break (MHD_YES == - MHD_add_response_header ( - ph->response, - MHD_HTTP_HEADER_LOCATION, - ph->pd->post_kyc_redirect_url)); - ph->http_status = MHD_HTTP_SEE_OTHER; ph->provider_user_id = GNUNET_strdup (id); } - ph->attributes = data2attributes (ph->pd, - data); + ph->status = TALER_KYCLOGIC_STATUS_SUCCESS; + ph->response = MHD_create_response_from_buffer (0, + "", + MHD_RESPMEM_PERSISTENT); + GNUNET_assert (NULL != ph->response); + GNUNET_break (MHD_YES == + MHD_add_response_header ( + ph->response, + MHD_HTTP_HEADER_LOCATION, + ph->pd->post_kyc_redirect_url)); + ph->http_status = MHD_HTTP_SEE_OTHER; + ph->attributes = json_incref ((json_t *) attr); + ph->task = GNUNET_SCHEDULER_add_now (&return_proof_response, + ph); +} + + +/** + * The request for @a ph succeeded (presumably). + * Call continuation with the result. + * + * @param[in,out] ph request that succeeded + * @param j reply from the server + */ +static void +parse_proof_success_reply (struct TALER_KYCLOGIC_ProofHandle *ph, + const json_t *j) +{ + const struct TALER_KYCLOGIC_ProviderDetails *pd = ph->pd; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Calling converter `%s' with JSON\n", + pd->conversion_binary); + json_dumpf (j, + stderr, + JSON_INDENT (2)); + ph->ec = TALER_JSON_external_conversion_start ( + j, + &converted_proof_cb, + ph, + pd->conversion_binary, + pd->conversion_binary, + NULL); } @@ -1079,7 +1049,7 @@ handle_curl_proof_finished (void *cls, case MHD_HTTP_OK: parse_proof_success_reply (ph, j); - break; + return; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "OAuth2.0 info URL returned HTTP status %u\n", diff --git a/src/kyclogic/taler-exchange-kyc-oauth2-challenger.sh b/src/kyclogic/taler-exchange-kyc-oauth2-challenger.sh old mode 100644 new mode 100755 diff --git a/src/kyclogic/taler-exchange-kyc-oauth2-nda.sh b/src/kyclogic/taler-exchange-kyc-oauth2-nda.sh old mode 100644 new mode 100755 diff --git a/src/kyclogic/taler-exchange-kyc-oauth2-test-converter.sh b/src/kyclogic/taler-exchange-kyc-oauth2-test-converter.sh new file mode 100755 index 000000000..06b8ed1ab --- /dev/null +++ b/src/kyclogic/taler-exchange-kyc-oauth2-test-converter.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# This file is in the public domain. +# +# This code converts (some of) the JSON output from +# Challenger into the GNU Taler +# specific KYC attribute data (again in JSON format). +# + +# Die if anything goes wrong. +set -eu + + +# First, extract everything from stdin. +J=$(jq '{"first":.first_name,"last".last_name"}') + +# Next, combine some fields into larger values. +FULLNAME=$(echo "$J" | jq -r '[.first,.last]|join(" ")') + +jq \ + --arg full_name "${FULLNAME}" \ + '{$full_name}' + +exit 0 -- cgit v1.2.3