From 234dbcc7b71ac98e7f63393e454377d1e2ae11c7 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 4 May 2017 15:18:43 +0200 Subject: switch bank api to new authentication method API --- src/bank-lib/Makefile.am | 3 +- src/bank-lib/bank_api_admin.c | 26 +++-- src/bank-lib/bank_api_common.c | 88 ++++++++++++++++ src/bank-lib/bank_api_common.h | 42 ++++++++ src/bank-lib/fakebank.c | 6 -- src/bank-lib/test_bank_interpreter.c | 13 +-- src/include/taler_bank_service.h | 188 ++++++++++++++++++++++++++++++++++- src/wire/plugin_wire_test.c | 35 ++++--- 8 files changed, 357 insertions(+), 44 deletions(-) create mode 100644 src/bank-lib/bank_api_common.c create mode 100644 src/bank-lib/bank_api_common.h diff --git a/src/bank-lib/Makefile.am b/src/bank-lib/Makefile.am index a87a2c467..feb7e50f9 100644 --- a/src/bank-lib/Makefile.am +++ b/src/bank-lib/Makefile.am @@ -15,7 +15,8 @@ libtalerbank_la_LDFLAGS = \ -no-undefined libtalerbank_la_SOURCES = \ - bank_api_admin.c + bank_api_admin.c \ + bank_api_common.c bank_api_common.h libtalerbank_la_LIBADD = \ $(top_builddir)/src/json/libtalerjson.la \ diff --git a/src/bank-lib/bank_api_admin.c b/src/bank-lib/bank_api_admin.c index 0db28e479..213cd08b3 100644 --- a/src/bank-lib/bank_api_admin.c +++ b/src/bank-lib/bank_api_admin.c @@ -20,13 +20,8 @@ * @author Christian Grothoff */ #include "platform.h" -#include +#include "bank_api_common.h" #include /* just for HTTP status codes */ -#include -#include -#include -#include "taler_bank_service.h" -#include "taler_json_lib.h" #include "taler_signatures.h" @@ -52,9 +47,9 @@ struct TALER_BANK_AdminAddIncomingHandle struct GNUNET_CURL_Job *job; /** - * HTTP headers for the request. + * HTTP authentication-related headers for the request. */ - struct curl_slist *headers; + struct curl_slist *authh; /** * Function to call with the result. @@ -162,8 +157,8 @@ handle_admin_add_incoming_finished (void *cls, * to the operators of the bank. * * @param ctx curl context for the event loop - * @param auth authentication data to send to the bank * @param bank_base_url URL of the bank (used to execute this request) + * @param auth authentication data to send to the bank * @param exchange_base_url base URL of the exchange (for tracking) * @param wtid wire transfer identifier for the transfer * @param amount amount that was deposited @@ -177,8 +172,8 @@ handle_admin_add_incoming_finished (void *cls, */ struct TALER_BANK_AdminAddIncomingHandle * TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx, - const json_t *auth, const char *bank_base_url, + const struct TALER_BANK_AuthenticationData *auth, const char *exchange_base_url, const struct TALER_WireTransferIdentifierRawP *wtid, const struct TALER_Amount *amount, @@ -191,9 +186,8 @@ TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx, json_t *admin_obj; CURL *eh; - admin_obj = json_pack ("{s:s, s:O, s:o, s:o, s:I, s:I}", + admin_obj = json_pack ("{s:s, s:o, s:o, s:I, s:I}", "exchange_url", exchange_base_url, - "auth", auth, "wtid", GNUNET_JSON_from_data_auto (wtid), "amount", TALER_JSON_from_amount (amount), "debit_account", (json_int_t) debit_account_no, @@ -203,12 +197,16 @@ TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx, aai->cb_cls = res_cb_cls; aai->request_url = path_to_url (bank_base_url, "/admin/add/incoming"); - + aai->authh = TALER_BANK_make_auth_header_ (auth); eh = curl_easy_init (); GNUNET_assert (NULL != (aai->json_enc = json_dumps (admin_obj, JSON_COMPACT))); json_decref (admin_obj); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HTTPHEADER, + aai->authh)); GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_URL, @@ -244,7 +242,7 @@ TALER_BANK_admin_add_incoming_cancel (struct TALER_BANK_AdminAddIncomingHandle * GNUNET_CURL_job_cancel (aai->job); aai->job = NULL; } - curl_slist_free_all (aai->headers); + curl_slist_free_all (aai->authh); GNUNET_free (aai->request_url); GNUNET_free (aai->json_enc); GNUNET_free (aai); diff --git a/src/bank-lib/bank_api_common.c b/src/bank-lib/bank_api_common.c new file mode 100644 index 000000000..0476379d8 --- /dev/null +++ b/src/bank-lib/bank_api_common.c @@ -0,0 +1,88 @@ +/* + This file is part of TALER + Copyright (C) 2015, 2016, 2017 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see + +*/ +/** + * @file bank-lib/bank_api_common.c + * @brief Common functions for the bank API + * @author Christian Grothoff + */ +#include "platform.h" +#include "bank_api_common.h" + + +/** + * Append HTTP key-value pair to curl header list. + * + * @param hdr list to append to, can be NULL + * @param key key to append + * @param value value to append + * @return new list, NULL on error + */ +static struct curl_slist * +append (struct curl_slist *hdr, + const char *key, + const char *value) +{ + char *str; + struct curl_slist *ret; + + GNUNET_asprintf (&str, + "%s: %s", + key, + value); + ret = curl_slist_append (hdr, + str); + GNUNET_free (str); + if (NULL == ret) + { + GNUNET_break (0); + curl_slist_free_all (hdr); + return NULL; + } + return ret; +} + + +/** + * Build authentication header from @a auth. + * + * @param auth authentication data to use + * @return NULL on error, otherwise curl headers to use + */ +struct curl_slist * +TALER_BANK_make_auth_header_ (const struct TALER_BANK_AuthenticationData *auth) +{ + struct curl_slist *authh; + + switch (auth->method) + { + case TALER_BANK_AUTH_NONE: + return NULL; + case TALER_BANK_AUTH_BASIC: + authh = append (NULL, + "X-Taler-Bank-Username", + auth->details.basic.username); + if (NULL == authh) + return NULL; + authh = append (authh, + "X-Taler-Bank-Password", + auth->details.basic.password); + break; + } + return authh; +} + +/* end of bank_api_common.c */ diff --git a/src/bank-lib/bank_api_common.h b/src/bank-lib/bank_api_common.h new file mode 100644 index 000000000..a979ee3ac --- /dev/null +++ b/src/bank-lib/bank_api_common.h @@ -0,0 +1,42 @@ +/* + This file is part of TALER + Copyright (C) 2015, 2016, 2017 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see + +*/ +/** + * @file bank-lib/bank_api_common.h + * @brief Common functions for the bank API + * @author Christian Grothoff + */ +#ifndef BANK_API_COMMON_H +#define BANK_API_COMMON_H +#include +#include +#include +#include +#include "taler_bank_service.h" +#include "taler_json_lib.h" + + +/** + * Build authentication header from @a auth. + * + * @param auth authentication data to use + * @return NULL on error, otherwise curl headers to use + */ +struct curl_slist * +TALER_BANK_make_auth_header_ (const struct TALER_BANK_AuthenticationData *auth); + + +#endif diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c index 486c7a7e2..88d5c36db 100644 --- a/src/bank-lib/fakebank.c +++ b/src/bank-lib/fakebank.c @@ -318,13 +318,11 @@ handle_mhd_request (void *cls, t = GNUNET_new (struct Transaction); { const char *base_url; - json_t *auth; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("wtid", &t->wtid), GNUNET_JSON_spec_uint64 ("debit_account", &t->debit_account), GNUNET_JSON_spec_uint64 ("credit_account", &t->credit_account), TALER_JSON_spec_amount ("amount", &t->amount), - GNUNET_JSON_spec_json ("auth", &auth), GNUNET_JSON_spec_string ("exchange_url", &base_url), GNUNET_JSON_spec_end () }; @@ -337,10 +335,6 @@ handle_mhd_request (void *cls, json_decref (json); return MHD_NO; } - /* For now, we ignore authentication, this is the fakebank. - We may choose to support "proper" authentication once - it is non-trivial and actually needs to be tested. */ - json_decref (auth); t->exchange_base_url = GNUNET_strdup (base_url); GNUNET_CONTAINER_DLL_insert (h->transactions_head, h->transactions_tail, diff --git a/src/bank-lib/test_bank_interpreter.c b/src/bank-lib/test_bank_interpreter.c index 346e32085..5f2d66648 100644 --- a/src/bank-lib/test_bank_interpreter.c +++ b/src/bank-lib/test_bank_interpreter.c @@ -188,7 +188,7 @@ interpreter_run (void *cls) struct TALER_WireTransferIdentifierRawP wtid; struct TALER_Amount amount; const struct GNUNET_SCHEDULER_TaskContext *tc; - json_t *auth; + struct TALER_BANK_AuthenticationData auth; is->task = NULL; tc = GNUNET_SCHEDULER_get_task_context (); @@ -220,15 +220,13 @@ interpreter_run (void *cls) GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &cmd->details.admin_add_incoming.wtid, sizeof (cmd->details.admin_add_incoming.wtid)); - auth = json_pack ("{s:s, s:{s:s, s:s}}", - "type", "basic", - "data", - "username", "user", - "password", "pass"); + auth.method = TALER_BANK_AUTH_BASIC; /* or "NONE"? */ + auth.details.basic.username = "user"; + auth.details.basic.password = "pass"; cmd->details.admin_add_incoming.aih = TALER_BANK_admin_add_incoming (is->ctx, - auth, "http://localhost:8081", + &auth, cmd->details.admin_add_incoming.exchange_base_url, &cmd->details.admin_add_incoming.wtid, &amount, @@ -236,7 +234,6 @@ interpreter_run (void *cls) cmd->details.admin_add_incoming.credit_account_no, &add_incoming_cb, is); - json_decref (auth); if (NULL == cmd->details.admin_add_incoming.aih) { GNUNET_break (0); diff --git a/src/include/taler_bank_service.h b/src/include/taler_bank_service.h index 9a0926bf4..a564bd336 100644 --- a/src/include/taler_bank_service.h +++ b/src/include/taler_bank_service.h @@ -26,6 +26,62 @@ #include #include "taler_util.h" + +/** + * Authentication method types. + */ +enum TALER_BANK_AuthenticationMethod { + + /** + * No authentication. + */ + TALER_BANK_AUTH_NONE, + + /** + * Basic authentication with cleartext username and password. + */ + TALER_BANK_AUTH_BASIC +}; + + +/** + * Information used to authenticate to the bank. + */ +struct TALER_BANK_AuthenticationData +{ + + /** + * Which authentication method should we use? + */ + enum TALER_BANK_AuthenticationMethod method; + + /** + * Further details as per @e method. + */ + union + { + + /** + * Details for #TALER_BANK_AUTH_BASIC. + */ + struct + { + /** + * Username to use. + */ + char *username; + + /** + * Password to use. + */ + char *password; + } basic; + + } details; + +}; + + /* ********************* /admin/add/incoming *********************** */ @@ -57,8 +113,8 @@ typedef void * to the operators of the bank. * * @param ctx curl context for the event loop - * @param auth authentication data to send to the bank * @param bank_base_url URL of the bank (used to execute this request) + * @param auth authentication data to use * @param exchange_base_url base URL of the exchange (for tracking) * @param wtid wire transfer identifier for the transfer * @param amount amount that was deposited @@ -72,8 +128,8 @@ typedef void */ struct TALER_BANK_AdminAddIncomingHandle * TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx, - const json_t *auth, const char *bank_base_url, + const struct TALER_BANK_AuthenticationData *auth, const char *exchange_base_url, const struct TALER_WireTransferIdentifierRawP *wtid, const struct TALER_Amount *amount, @@ -92,4 +148,132 @@ TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx, void TALER_BANK_admin_add_incoming_cancel (struct TALER_BANK_AdminAddIncomingHandle *aai); + +/** + * Which types of transactions should be returned? + */ +enum TALER_BANK_Direction { + + /** + * Transactions where the bank account receives money. + */ + TALER_BANK_DIRECTION_CREDIT = 1, + + /** + * Transactions where the bank account looses money. + */ + TALER_BANK_DIRECTION_DEBIT = 2, + + /** + * Return both types of transactions. + */ + TALER_BANK_DIRECTION_BOTH = (TALER_BANK_DIRECTION_CREDIT | TALER_BANK_DIRECTION_DEBIT) + +}; + + +/** + * Handle for querying the bank's transaction history. + */ +struct TALER_BANK_HistoryHandle; + +/** + * Details about a wire transfer. + */ +struct TALER_BANK_TransferDetails +{ + /** + * amount that was transferred + */ + struct TALER_Amount amount; + + /** + * when did the transfer happen + */ + struct GNUNET_TIME_Absolute execution_date; + + /** + * monotonically increasing counter corresponding to the transaction + */ + uint64_t serial_id; + + /** + * wire transfer subject + */ + char *wire_transfer_subject; + + /** + * what was the other account that was involved + */ + json_t *account_details; +}; + + +/** + * Callbacks of this type are used to serve the result of asking + * the bank for the transaction history. + * + * @param cls closure + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the bank's reply is bogus (fails to follow the protocol), + * #MHD_HTTP_NO_CONTENT if there are no more results; on success the + * last callback is always of this status (even if `abs(num_results)` were + * already returned). + * @param dir direction of the transfer + * @param details details about the wire transfer + * @param json detailed response from the HTTPD, or NULL if reply was not in JSON + */ +typedef void +(*TALER_BANK_HistoryResultCallback) (void *cls, + unsigned int http_status, + enum TALER_BANK_Direction dir, + const struct TALER_BANK_TransferDetails *details, + const json_t *json); + + +/** + * Notify the bank that we have received an incoming transaction + * which fills a reserve. Note that this API is an administrative + * API and thus not accessible to typical bank clients, but only + * to the operators of the bank. + * + * @param ctx curl context for the event loop + * @param bank_base_url URL of the bank (used to execute this request) + * @param auth authentication data to use + * @param account_number which account number should we query + * @param direction what kinds of wire transfers should be returned + * @param start_row from which row on do we want to get results, use UINT64_MAX for the latest + * @param num_results how many results do we want; negative numbers to go into the past, + * positive numbers to go into the future starting at @a start_row; + * must not be zero. + * @param hres_cb the callback to call with the transaction history + * @param hres_cb_cls closure for the above callback + * @return NULL + * if the inputs are invalid (i.e. zero value for @e num_results). + * In this case, the callback is not called. + */ +struct TALER_BANK_HistoryHandle * +TALER_BANK_history (struct GNUNET_CURL_Context *ctx, + const char *bank_base_url, + const struct TALER_BANK_AuthenticationData *auth, + uint64_t account_number, + enum TALER_BANK_Direction direction, + uint64_t start_row, + int64_t num_results, + TALER_BANK_HistoryResultCallback hres_cb, + void *hres_cb_cls); + + +/** + * Cancel an history request. This function cannot be used on a request + * handle if the last response (anything with a status code other than + * 200) is already served for it. + * + * @param hh the history request handle + */ +void +TALER_BANK_history_cancel (struct TALER_BANK_HistoryHandle *hh); + + + #endif /* _TALER_BANK_SERVICE_H */ diff --git a/src/wire/plugin_wire_test.c b/src/wire/plugin_wire_test.c index 201bbf08b..12adade81 100644 --- a/src/wire/plugin_wire_test.c +++ b/src/wire/plugin_wire_test.c @@ -48,7 +48,7 @@ struct TestClosure /** * Authentication information. */ - json_t *auth; + struct TALER_BANK_AuthenticationData auth; /** * Handle to the context for sending funds to the bank. @@ -726,8 +726,8 @@ test_execute_wire_transfer (void *cls, eh->cc = cc; eh->cc_cls = cc_cls; eh->aaih = TALER_BANK_admin_add_incoming (tc->ctx, - tc->auth, tc->bank_uri, + &tc->auth, exchange_base_url, &bf.wtid, &amount, @@ -850,13 +850,9 @@ libtaler_plugin_wire_test_init (void *cls) GNUNET_free (user); return NULL; } - tc->auth = json_pack ("{s:s, s:{s:s, s:s}}", - "type", "basic", - "data", - "username", user, - "password", pass); - GNUNET_free (user); - GNUNET_free (pass); + tc->auth.method = TALER_BANK_AUTH_BASIC; + tc->auth.details.basic.username = user; + tc->auth.details.basic.password = pass; tc->ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, &tc->rc); tc->rc = GNUNET_CURL_gnunet_rc_create (tc->ctx); @@ -865,7 +861,8 @@ libtaler_plugin_wire_test_init (void *cls) GNUNET_break (0); GNUNET_free (tc->currency); GNUNET_free (tc->bank_uri); - json_decref (tc->auth); + GNUNET_free (tc->auth.details.basic.username); + GNUNET_free (tc->auth.details.basic.password); GNUNET_free (tc); return NULL; } @@ -906,10 +903,22 @@ libtaler_plugin_wire_test_done (void *cls) GNUNET_CURL_gnunet_rc_destroy (tc->rc); tc->rc = NULL; } - if (NULL != tc->auth) + switch (tc->auth.method) { - json_decref (tc->auth); - tc->auth = NULL; + case TALER_BANK_AUTH_NONE: + break; + case TALER_BANK_AUTH_BASIC: + if (NULL != tc->auth.details.basic.username) + { + GNUNET_free (tc->auth.details.basic.username); + tc->auth.details.basic.username = NULL; + } + if (NULL != tc->auth.details.basic.password) + { + GNUNET_free (tc->auth.details.basic.password); + tc->auth.details.basic.password = NULL; + } + break; } GNUNET_free_non_null (tc->currency); GNUNET_free_non_null (tc->bank_uri); -- cgit v1.2.3