From f50a2e11b09d67eaa1db3b2de882294f08c2847a Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 9 Aug 2022 12:11:56 +0200 Subject: [PATCH] work on kyc-tester --- src/kyclogic/Makefile.am | 3 +- src/kyclogic/kyclogic-oauth2.conf | 27 +++ src/kyclogic/kyclogic.conf | 15 ++ src/kyclogic/plugin_kyclogic_oauth2.c | 16 +- src/kyclogic/sample.conf | 33 +++ src/kyclogic/taler-exchange-kyc-tester.c | 290 ++++++++++++++++------- 6 files changed, 287 insertions(+), 97 deletions(-) create mode 100644 src/kyclogic/sample.conf diff --git a/src/kyclogic/Makefile.am b/src/kyclogic/Makefile.am index c57fc1fce..5531e9f98 100644 --- a/src/kyclogic/Makefile.am +++ b/src/kyclogic/Makefile.am @@ -14,7 +14,8 @@ pkgcfg_DATA = \ EXTRA_DIST = \ kyclogic.conf \ - kyclogic-oauth2.conf + kyclogic-oauth2.conf \ + sample.conf lib_LTLIBRARIES = \ libtalerkyclogic.la diff --git a/src/kyclogic/kyclogic-oauth2.conf b/src/kyclogic/kyclogic-oauth2.conf index e69de29bb..7ccf81c0d 100644 --- a/src/kyclogic/kyclogic-oauth2.conf +++ b/src/kyclogic/kyclogic-oauth2.conf @@ -0,0 +1,27 @@ +# This file is in the public domain. + +# Example Oauth2.0 provider configuration. + +[kyc-provider-example-oauth2] + +COST = 42 +LOGIC = oauth2 +USER_TYPE = INDIVIDUAL +PROVIDED_CHECKS = EXAMPLE_DO_NOT_USE + +# How long is the KYC check valid? +KYC_OAUTH2_VALIDITY = forever + +# URL where we initiate the user's login process +KYC_OAUTH2_LOGIN_URL = http://kyc.example.com/login +# URL where we send the user's authentication information +KYC_OAUTH2_AUTH_URL = http://kyc.example.com/auth +# URL of the user info access point. +KYC_OAUTH2_INFO_URL = http://kyc.example.com/info + +# Where does the client get redirected upon completion? +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 diff --git a/src/kyclogic/kyclogic.conf b/src/kyclogic/kyclogic.conf index e69de29bb..a66ce601c 100644 --- a/src/kyclogic/kyclogic.conf +++ b/src/kyclogic/kyclogic.conf @@ -0,0 +1,15 @@ +# This file is in the public domain. +# +# Sample legitimization rule set. + +#[kyc-legitimization-withdraw-high] +# KYC hook is this rule is about. +#OPERATION_TYPE = WITHDRAW +# Which checks must be done. Give names used by providers. +#REQUIRED_CHECKS = PHONE GOVID SSN +# Treshold amount above which the checks are required. +#THRESHOLD = KUDOS:100 +# Timeframe over which amounts involved in the +# operation type are accumulated to test against +# the threshold. +#TIMEFRAME = 1a diff --git a/src/kyclogic/plugin_kyclogic_oauth2.c b/src/kyclogic/plugin_kyclogic_oauth2.c index 42f195be3..0a19a8497 100644 --- a/src/kyclogic/plugin_kyclogic_oauth2.c +++ b/src/kyclogic/plugin_kyclogic_oauth2.c @@ -101,9 +101,9 @@ struct TALER_KYCLOGIC_ProviderDetails char *post_kyc_redirect_url; /** - * Expiration time for a successful KYC process. + * Validity time for a successful KYC process. */ - struct GNUNET_TIME_Relative expiration; + struct GNUNET_TIME_Relative validity; }; @@ -295,12 +295,12 @@ oauth2_load_configuration (void *cls, if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (ps->cfg, provider_section_name, - "KYC_OAUTH2_EXPIRATION", - &pd->expiration)) + "KYC_OAUTH2_VALIDITY", + &pd->validity)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, provider_section_name, - "KYC_OAUTH2_EXPIARTION"); + "KYC_OAUTH2_VALIDITY"); oauth2_unload_configuration (pd); return NULL; } @@ -367,12 +367,12 @@ oauth2_load_configuration (void *cls, if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (ps->cfg, provider_section_name, - "KYC_INFO_URL", + "KYC_OAUTH2_INFO_URL", &s)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, provider_section_name, - "KYC_INFO_URL"); + "KYC_OAUTH2_INFO_URL"); oauth2_unload_configuration (pd); return NULL; } @@ -553,7 +553,7 @@ return_proof_response (void *cls) ph->status, ph->provider_user_id, ph->provider_legitimization_id, - GNUNET_TIME_relative_to_absolute (ph->pd->expiration), + GNUNET_TIME_relative_to_absolute (ph->pd->validity), ph->http_status, ph->response); GNUNET_free (ph->provider_user_id); diff --git a/src/kyclogic/sample.conf b/src/kyclogic/sample.conf new file mode 100644 index 000000000..b9a88c292 --- /dev/null +++ b/src/kyclogic/sample.conf @@ -0,0 +1,33 @@ +# This file is in the public domain. +# + +[exchange] + +# HTTP port the exchange listens to +PORT = 8081 + +# Base URL of the exchange. Must be set to a URL where the +# exchange (or the twister) is actually listening. +BASE_URL = "http://localhost:8081/" + +[kyc-provider-test-oauth2] + +COST = 0 +LOGIC = oauth2 +USER_TYPE = INDIVIDUAL +PROVIDED_CHECKS = DUMMY + +KYC_OAUTH2_VALIDITY = forever +KYC_OAUTH2_AUTH_URL = http://kyc.taler.net/auth +KYC_OAUTH2_LOGIN_URL = http://kyc.taler.net/login +KYC_OAUTH2_INFO_URL = http://kyc.taler.net/info +KYC_OAUTH2_POST_URL = http://kyc.taler.net/thank-you +KYC_OAUTH2_CLIENT_ID = testcase +KYC_OAUTH2_CLIENT_SECRET = password + +[kyc-legitimization-withdraw-high] + +OPERATION_TYPE = WITHDRAW +REQUIRED_CHECKS = DUMMY +THRESHOLD = KUDOS:100 +TIMEFRAME = 1a diff --git a/src/kyclogic/taler-exchange-kyc-tester.c b/src/kyclogic/taler-exchange-kyc-tester.c index 1fb0afa47..753c65176 100644 --- a/src/kyclogic/taler-exchange-kyc-tester.c +++ b/src/kyclogic/taler-exchange-kyc-tester.c @@ -171,21 +171,51 @@ static const struct GNUNET_CONFIGURATION_Handle *TEKT_cfg; */ static struct MHD_Daemon *mhd; -/** - * Our currency. - */ -static char *TEKT_currency; - /** * Our base URL. */ static char *TEKT_base_url; +/** + * Payto set via command-line (or otherwise random). + */ +static struct TALER_PaytoHashP cmd_line_h_payto; + +/** + * Row ID to use, override with '-r' + */ +static unsigned int kyc_row_id = 42; + +/** + * -P command-line option. + */ +static int print_h_payto; + +/** + * -w command-line option. + */ +static int run_webservice; + /** * Value to return from main() */ static int global_ret; +/** + * -i command-line flag. + */ +static char *initiate_section; + +/** + * Handle for ongoing initiation operation. + */ +static struct TALER_KYCLOGIC_InitiateHandle *ih; + +/** + * KYC logic running for @e ih. + */ +static struct TALER_KYCLOGIC_Plugin *logic; + /** * Port to run the daemon on. */ @@ -203,24 +233,6 @@ static struct GNUNET_CURL_Context *TEKT_curl_ctx; static struct GNUNET_CURL_RescheduleContext *exchange_curl_rc; -/** - * Generate a 404 "not found" reply on @a connection with - * the hint @a details. - * - * @param connection where to send the reply on - * @param details details for the error message, can be NULL - */ -static MHD_RESULT -r404 (struct MHD_Connection *connection, - const char *details) -{ - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN, - details); -} - - /** * Context for the webhook. */ @@ -427,11 +439,12 @@ kyc_provider_account_lookup ( const char *provider_legitimization_id, struct TALER_PaytoHashP *h_payto) { - // FIXME: pass value to use for h_payto via command-line? - memset (h_payto, - 42, - sizeof (*h_payto)); - return 1; // FIXME... + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Simulated account lookup using `%s/%s'\n", + provider_section, + provider_legitimization_id); + *h_payto = cmd_line_h_payto; + return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; } @@ -745,25 +758,13 @@ handle_mhd_request (void *cls, { static struct TEKT_RequestHandler handlers[] = { #if FIXME - /* KYC endpoints */ - { - .url = "kyc-check", - .method = MHD_HTTP_METHOD_GET, - .handler.get = &TEKT_handler_kyc_check, - .nargs = 1 - }, + /* simulated KYC endpoints */ { .url = "kyc-proof", .method = MHD_HTTP_METHOD_GET, .handler.get = &TEKT_handler_kyc_proof, .nargs = 1 }, - { - .url = "kyc-wallet", - .method = MHD_HTTP_METHOD_POST, - .handler.post = &TEKT_handler_kyc_wallet, - .nargs = 0 - }, #endif { .url = "kyc-webhook", @@ -994,6 +995,11 @@ do_shutdown (void *cls) struct MHD_Daemon *mhd; (void) cls; + if (NULL != ih) + { + logic->initiate_cancel (ih); + ih = NULL; + } kyc_webhook_cleanup (); TALER_KYCLOGIC_kyc_done (); mhd = TALER_MHD_daemon_stop (); @@ -1012,6 +1018,45 @@ do_shutdown (void *cls) } +/** + * Function called with the result of a KYC initiation + * operation. + * + * @param cls closure + * @param ec #TALER_EC_NONE on success + * @param redirect_url set to where to redirect the user on success, NULL on failure + * @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 error_msg_hint set to additional details to return to user, NULL on success + */ +static void +initiate_cb ( + void *cls, + enum TALER_ErrorCode ec, + const char *redirect_url, + const char *provider_user_id, + const char *provider_legitimization_id, + const char *error_msg_hint) +{ + ih = NULL; + if (TALER_EC_NONE != ec) + { + fprintf (stderr, + "Failed to start KYC process: %s (#%d)\n", + error_msg_hint, + ec); + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + return; + } + fprintf (stdout, + "Visit `%s' to begin KYC process (%s/%s)\n", + redirect_url, + provider_user_id, + provider_legitimization_id); +} + + /** * Main function that will be run by the scheduler. * @@ -1032,6 +1077,17 @@ run (void *cls, (void) cls; (void) args; (void ) cfgfile; + if (print_h_payto) + { + char *s; + + s = GNUNET_STRINGS_data_to_string_alloc (&cmd_line_h_payto, + sizeof (cmd_line_h_payto)); + fprintf (stdout, + "%s\n", + s); + GNUNET_free (s); + } TALER_MHD_setup (TALER_MHD_GO_NONE); TEKT_cfg = config; if (GNUNET_OK != @@ -1041,61 +1097,87 @@ run (void *cls, GNUNET_SCHEDULER_shutdown (); return; } + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, + NULL); if (GNUNET_OK != exchange_serve_process_config ()) { global_ret = EXIT_NOTCONFIGURED; - TALER_KYCLOGIC_kyc_done (); - GNUNET_SCHEDULER_shutdown (); - return; - } - TEKT_curl_ctx - = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, - &exchange_curl_rc); - if (NULL == TEKT_curl_ctx) - { - GNUNET_break (0); - global_ret = EXIT_FAILURE; - GNUNET_SCHEDULER_shutdown (); - return; - } - exchange_curl_rc = GNUNET_CURL_gnunet_rc_create (TEKT_curl_ctx); - GNUNET_SCHEDULER_add_shutdown (&do_shutdown, - NULL); - fh = TALER_MHD_bind (TEKT_cfg, - "exchange", - &serve_port); - if ( (0 == serve_port) && - (-1 == fh) ) - { - GNUNET_SCHEDULER_shutdown (); - return; - } - mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME - | MHD_USE_PIPE_FOR_SHUTDOWN - | MHD_USE_DEBUG | MHD_USE_DUAL_STACK - | MHD_USE_TCP_FASTOPEN, - (-1 == fh) ? serve_port : 0, - NULL, NULL, - &handle_mhd_request, NULL, - MHD_OPTION_LISTEN_SOCKET, - fh, - MHD_OPTION_EXTERNAL_LOGGER, - &TALER_MHD_handle_logs, - NULL, - MHD_OPTION_NOTIFY_COMPLETED, - &handle_mhd_completion_callback, - NULL, - MHD_OPTION_END); - if (NULL == mhd) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to launch HTTP service. Is the port in use?\n"); GNUNET_SCHEDULER_shutdown (); return; } global_ret = EXIT_SUCCESS; - TALER_MHD_daemon_start (mhd); + if (NULL != initiate_section) + { + struct TALER_KYCLOGIC_ProviderDetails *pd; + + if (GNUNET_OK != + TALER_KYCLOGIC_kyc_get_logic (initiate_section, + &logic, + &pd)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not initiate KYC with provider `%s' (configuration error?)\n", + initiate_section); + global_ret = EXIT_NOTCONFIGURED; + GNUNET_SCHEDULER_shutdown (); + return; + } + ih = logic->initiate (logic->cls, + pd, + &cmd_line_h_payto, + kyc_row_id, + &initiate_cb, + NULL); + GNUNET_break (NULL != ih); + } + if (run_webservice) + { + TEKT_curl_ctx + = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &exchange_curl_rc); + if (NULL == TEKT_curl_ctx) + { + GNUNET_break (0); + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + return; + } + exchange_curl_rc = GNUNET_CURL_gnunet_rc_create (TEKT_curl_ctx); + fh = TALER_MHD_bind (TEKT_cfg, + "exchange", + &serve_port); + if ( (0 == serve_port) && + (-1 == fh) ) + { + GNUNET_SCHEDULER_shutdown (); + return; + } + mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME + | MHD_USE_PIPE_FOR_SHUTDOWN + | MHD_USE_DEBUG | MHD_USE_DUAL_STACK + | MHD_USE_TCP_FASTOPEN, + (-1 == fh) ? serve_port : 0, + NULL, NULL, + &handle_mhd_request, NULL, + MHD_OPTION_LISTEN_SOCKET, + fh, + MHD_OPTION_EXTERNAL_LOGGER, + &TALER_MHD_handle_logs, + NULL, + MHD_OPTION_NOTIFY_COMPLETED, + &handle_mhd_completion_callback, + NULL, + MHD_OPTION_END); + if (NULL == mhd) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to launch HTTP service. Is the port in use?\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + TALER_MHD_daemon_start (mhd); + } } @@ -1113,11 +1195,43 @@ main (int argc, const struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_option_help ( "tool to test KYC provider integrations"), + GNUNET_GETOPT_option_flag ( + 'P', + "print-payto-hash", + "output the hash of the payto://-URI", + &print_h_payto), + GNUNET_GETOPT_option_uint ( + 'r', + "rowid", + "NUMBER", + "override row ID to use in simulation (default: 42)", + &kyc_row_id), + GNUNET_GETOPT_option_flag ( + 'w', + "run-webservice", + "run the integrated HTTP service", + &run_webservice), + GNUNET_GETOPT_option_string ( + 'i', + "initiate", + "SECTION_NAME", + "initiate KYC check using provider configured in SECTION_NAME of the configuration", + &initiate_section), + GNUNET_GETOPT_option_base32_fixed_size ( + 'p', + "payto-hash", + "URI", + "base32 encoding of the hash of a payto://-URI to use for the account (otherwise a random value will be used)", + &cmd_line_h_payto, + sizeof (cmd_line_h_payto)), GNUNET_GETOPT_OPTION_END }; enum GNUNET_GenericReturnValue ret; TALER_OS_init (); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, + &cmd_line_h_payto, + sizeof (cmd_line_h_payto)); ret = GNUNET_PROGRAM_run (argc, argv, "taler-exchange-kyc-tester", "tool to test KYC provider integrations",