From a273b176da448cd27374acb94feee22c22dd8527 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 22 Jan 2023 21:51:46 +0100 Subject: [PATCH] -towards storing KYC attribute data --- src/exchange/taler-exchange-httpd_kyc-proof.c | 3 + src/include/taler_kyclogic_plugin.h | 2 + src/kyclogic/Makefile.am | 1 + src/kyclogic/kyclogic-oauth2.conf | 8 ++ src/kyclogic/plugin_kyclogic_kycaid.c | 1 + src/kyclogic/plugin_kyclogic_oauth2.c | 87 +++++++++++++++++++ src/kyclogic/plugin_kyclogic_persona.c | 2 + src/kyclogic/taler-exchange-kyc-tester.c | 6 ++ 8 files changed, 110 insertions(+) diff --git a/src/exchange/taler-exchange-httpd_kyc-proof.c b/src/exchange/taler-exchange-httpd_kyc-proof.c index d37164987..1904c4acb 100644 --- a/src/exchange/taler-exchange-httpd_kyc-proof.c +++ b/src/exchange/taler-exchange-httpd_kyc-proof.c @@ -169,6 +169,7 @@ TEH_kyc_proof_cleanup (void) * @param provider_user_id set to user ID at the provider, or NULL if not supported or unknown * @param provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown * @param expiration until when is the KYC check valid + * @param attributes user attributes returned by the provider * @param http_status HTTP status code of @a response * @param[in] response to return to the HTTP client */ @@ -179,6 +180,7 @@ proof_cb ( const char *provider_user_id, const char *provider_legitimization_id, struct GNUNET_TIME_Absolute expiration, + const json_t *attributes, unsigned int http_status, struct MHD_Response *response) { @@ -194,6 +196,7 @@ proof_cb ( { enum GNUNET_DB_QueryStatus qs; + // FIXME: also store 'attributes' in DB! qs = TEH_plugin->update_kyc_process_by_row (TEH_plugin->cls, kpc->process_row, kpc->provider_section, diff --git a/src/include/taler_kyclogic_plugin.h b/src/include/taler_kyclogic_plugin.h index c2266e1ae..1782af917 100644 --- a/src/include/taler_kyclogic_plugin.h +++ b/src/include/taler_kyclogic_plugin.h @@ -158,6 +158,7 @@ typedef void * @param status KYC status * @param provider_user_id set to user ID at the provider, or NULL if not supported or unknown * @param provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown + * @param attributes user attributes returned by the provider * @param expiration until when is the KYC check valid * @param http_status HTTP status code of @a response * @param[in] response to return to the HTTP client @@ -169,6 +170,7 @@ typedef void const char *provider_user_id, const char *provider_legitimization_id, struct GNUNET_TIME_Absolute expiration, + const json_t *attributes, unsigned int http_status, struct MHD_Response *response); diff --git a/src/kyclogic/Makefile.am b/src/kyclogic/Makefile.am index c45424178..858331f39 100644 --- a/src/kyclogic/Makefile.am +++ b/src/kyclogic/Makefile.am @@ -79,6 +79,7 @@ libtaler_plugin_kyclogic_oauth2_la_LIBADD = \ $(LTLIBINTL) libtaler_plugin_kyclogic_oauth2_la_LDFLAGS = \ $(TALER_PLUGIN_LDFLAGS) \ + $(top_builddir)/src/templating/libtalertemplating.la \ $(top_builddir)/src/mhd/libtalermhd.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ diff --git a/src/kyclogic/kyclogic-oauth2.conf b/src/kyclogic/kyclogic-oauth2.conf index 7ccf81c0d..d3df585d8 100644 --- a/src/kyclogic/kyclogic-oauth2.conf +++ b/src/kyclogic/kyclogic-oauth2.conf @@ -25,3 +25,11 @@ KYC_OAUTH2_POST_URL = http://example.com/thank-you # For authentication to the OAuth2.0 service KYC_OAUTH2_CLIENT_ID = testcase 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! +# +KYC_ATTRIBUTE_TEMPLATE = "{"fullname":"{{first_name}} {{last_name}}","phone":"{{phone}}"}" \ No newline at end of file diff --git a/src/kyclogic/plugin_kyclogic_kycaid.c b/src/kyclogic/plugin_kyclogic_kycaid.c index 8e9323171..6926135c3 100644 --- a/src/kyclogic/plugin_kyclogic_kycaid.c +++ b/src/kyclogic/plugin_kyclogic_kycaid.c @@ -632,6 +632,7 @@ proof_reply (void *cls) NULL, /* user id */ NULL, /* provider legi ID */ GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */ + NULL, /* attributes */ MHD_HTTP_BAD_REQUEST, resp); } diff --git a/src/kyclogic/plugin_kyclogic_oauth2.c b/src/kyclogic/plugin_kyclogic_oauth2.c index 5709b18f8..f5a08e92e 100644 --- a/src/kyclogic/plugin_kyclogic_oauth2.c +++ b/src/kyclogic/plugin_kyclogic_oauth2.c @@ -21,6 +21,7 @@ #include "platform.h" #include "taler_kyclogic_plugin.h" #include "taler_mhd_lib.h" +#include "taler_templating_lib.h" #include "taler_json_lib.h" #include #include "taler_util.h" @@ -105,6 +106,12 @@ struct TALER_KYCLOGIC_ProviderDetails */ char *post_kyc_redirect_url; + /** + * Template for converting user-data returned by + * the provider into our KYC attribute data. + */ + char *attribute_template; + /** * Validity time for a successful KYC process. */ @@ -194,6 +201,11 @@ struct TALER_KYCLOGIC_ProofHandle */ char *post_body; + /** + * KYC attributes returned about the user by the OAuth 2.0 server. + */ + json_t *attributes; + /** * Response to return. */ @@ -277,6 +289,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); } @@ -443,6 +456,21 @@ oauth2_load_configuration (void *cls, } pd->post_kyc_redirect_url = s; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (ps->cfg, + provider_section_name, + "KYC_OAUTH2_ATTRIBUTE_TEMPLATE", + &s)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + provider_section_name, + "KYC_OAUTH2_ATTRIBUTE_TEMPLATE"); + } + else + { + pd->attribute_template = s; + } + return pd; } @@ -566,9 +594,12 @@ return_proof_response (void *cls) ph->provider_user_id, ph->provider_legitimization_id, GNUNET_TIME_relative_to_absolute (ph->pd->validity), + ph->attributes, ph->http_status, ph->response); GNUNET_free (ph->provider_user_id); + if (NULL != ph->attributes) + json_decref (ph->attributes); GNUNET_free (ph); } @@ -640,6 +671,57 @@ 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. @@ -689,6 +771,7 @@ parse_proof_success_reply (struct TALER_KYCLOGIC_ProofHandle *ph, GNUNET_break_op (0); handle_proof_error (ph, j); + GNUNET_JSON_parse_free (spec); return; } { @@ -716,6 +799,7 @@ parse_proof_success_reply (struct TALER_KYCLOGIC_ProofHandle *ph, "Unexpected response from KYC gateway: data must contain id"); ph->http_status = MHD_HTTP_BAD_GATEWAY; + GNUNET_JSON_parse_free (spec); return; } ph->status = TALER_KYCLOGIC_STATUS_SUCCESS; @@ -731,6 +815,9 @@ parse_proof_success_reply (struct TALER_KYCLOGIC_ProofHandle *ph, ph->http_status = MHD_HTTP_SEE_OTHER; ph->provider_user_id = GNUNET_strdup (id); } + ph->attributes = data2attributes (ph->pd, + data); + GNUNET_JSON_parse_free (spec); } diff --git a/src/kyclogic/plugin_kyclogic_persona.c b/src/kyclogic/plugin_kyclogic_persona.c index abc8e78f5..9f3952558 100644 --- a/src/kyclogic/plugin_kyclogic_persona.c +++ b/src/kyclogic/plugin_kyclogic_persona.c @@ -890,6 +890,7 @@ proof_generic_reply (struct TALER_KYCLOGIC_ProofHandle *ph, account_id, inquiry_id, expiration, + NULL, /* FIXME: return attributes! */ http_status, resp); } @@ -1173,6 +1174,7 @@ handle_proof_finished (void *cls, account_id, inquiry_id, expiration, + NULL, /* FIXME: return attributes! */ MHD_HTTP_SEE_OTHER, resp); } diff --git a/src/kyclogic/taler-exchange-kyc-tester.c b/src/kyclogic/taler-exchange-kyc-tester.c index d436ef7ee..bb473c682 100644 --- a/src/kyclogic/taler-exchange-kyc-tester.c +++ b/src/kyclogic/taler-exchange-kyc-tester.c @@ -688,6 +688,7 @@ handler_kyc_webhook_post ( * @param provider_user_id set to user ID at the provider, or NULL if not supported or unknown * @param provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown * @param expiration until when is the KYC check valid + * @param attributes attributes about the user * @param http_status HTTP status code of @a response * @param[in] response to return to the HTTP client */ @@ -698,6 +699,7 @@ proof_cb ( const char *provider_user_id, const char *provider_legitimization_id, struct GNUNET_TIME_Absolute expiration, + const json_t *attributes, unsigned int http_status, struct MHD_Response *response) { @@ -710,6 +712,10 @@ proof_cb ( status, http_status, provider_user_id); + if (NULL != attributes) + json_dumpf (attributes, + stderr, + JSON_INDENT (2)); MHD_resume_connection (rs->rc->connection); TALER_MHD_daemon_trigger (); rs->rc->response = response;