summaryrefslogtreecommitdiff
path: root/src/exchange/taler-exchange-httpd_kyc-proof.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2021-11-15 20:00:45 +0100
committerChristian Grothoff <christian@grothoff.org>2021-11-15 20:00:45 +0100
commite5ead880579cbac93353b72e96221c84206a7403 (patch)
tree0f40cdc235a9e75f137fe3ac927f43f263b02826 /src/exchange/taler-exchange-httpd_kyc-proof.c
parent0325a79631d1abba7fdf414748a34c0e8bca55c3 (diff)
downloadexchange-e5ead880579cbac93353b72e96221c84206a7403.tar.gz
exchange-e5ead880579cbac93353b72e96221c84206a7403.tar.bz2
exchange-e5ead880579cbac93353b72e96221c84206a7403.zip
complete oauth logic (in theory)
Diffstat (limited to 'src/exchange/taler-exchange-httpd_kyc-proof.c')
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-proof.c301
1 files changed, 239 insertions, 62 deletions
diff --git a/src/exchange/taler-exchange-httpd_kyc-proof.c b/src/exchange/taler-exchange-httpd_kyc-proof.c
index fdf5ade54..7bd9fdaa6 100644
--- a/src/exchange/taler-exchange-httpd_kyc-proof.c
+++ b/src/exchange/taler-exchange-httpd_kyc-proof.c
@@ -73,6 +73,11 @@ struct KycProofContext
char *post_body;
/**
+ * User ID extracted from the OAuth 2.0 service, or NULL.
+ */
+ char *id;
+
+ /**
* Payment target this is about.
*/
unsigned long long payment_target_uuid;
@@ -165,13 +170,186 @@ persist_kyc_ok (void *cls,
struct KycProofContext *kpc = cls;
return TEH_plugin->set_kyc_ok (TEH_plugin->cls,
- kpc->payment_target_uuid);
+ kpc->payment_target_uuid,
+ kpc->id);
+}
+
+
+/**
+ * The request for @a kpc failed. We may have gotten a useful error
+ * message in @a j. Generate a failure response.
+ *
+ * @param[in,out] kpc request that failed
+ * @param j reply from the server (or NULL)
+ */
+static void
+handle_error (struct KycProofContext *kpc,
+ const json_t *j)
+{
+ const char *msg;
+ const char *desc;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("error",
+ &msg),
+ GNUNET_JSON_spec_string ("error_description",
+ &desc),
+ 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)
+ {
+ GNUNET_break_op (0);
+ kpc->response
+ = TALER_MHD_make_error (
+ TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
+ "Unexpected response from KYC gateway");
+ kpc->response_code
+ = MHD_HTTP_BAD_GATEWAY;
+ return;
+ }
+ }
+ /* case TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_AUTHORZATION_FAILED,
+ we MAY want to in the future look at the requested content type
+ and possibly respond in JSON if indicated. */
+ {
+ char *reply;
+
+ GNUNET_asprintf (&reply,
+ "<html><head><title>%s</title></head><body><h1>%s</h1><p>%s</p></body></html>",
+ msg,
+ msg,
+ desc);
+ kpc->response
+ = MHD_create_response_from_buffer (strlen (reply),
+ reply,
+ MHD_RESPMEM_MUST_COPY);
+ GNUNET_assert (NULL != kpc->response);
+ GNUNET_free (reply);
+ }
+ kpc->response_code = MHD_HTTP_FORBIDDEN;
+}
+
+
+/**
+ * The request for @a kpc succeeded (presumably).
+ * Parse the user ID and store it in @a kpc (if possible).
+ *
+ * @param[in,out] kpc request that succeeded
+ * @param j reply from the server
+ */
+static void
+parse_success_reply (struct KycProofContext *kpc,
+ const json_t *j)
+{
+ const char *state;
+ json_t *data;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("status",
+ &state),
+ GNUNET_JSON_spec_json ("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)
+ {
+ GNUNET_break_op (0);
+ kpc->response
+ = TALER_MHD_make_error (
+ TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
+ "Unexpected response from KYC gateway");
+ kpc->response_code
+ = MHD_HTTP_BAD_GATEWAY;
+ return;
+ }
+ if (0 != strcasecmp (state,
+ "success"))
+ {
+ GNUNET_break_op (0);
+ handle_error (kpc,
+ j);
+ return;
+ }
+ {
+ const char *id;
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_string ("id",
+ &id),
+ GNUNET_JSON_spec_end ()
+ };
+
+ res = GNUNET_JSON_parse (data,
+ ispec,
+ &emsg,
+ &line);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ kpc->response
+ = TALER_MHD_make_error (
+ TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
+ "Unexpected response from KYC gateway");
+ kpc->response_code
+ = MHD_HTTP_BAD_GATEWAY;
+ return;
+ }
+ kpc->id = GNUNET_strdup (id);
+ }
}
/**
* After we are done with the CURL interaction we
- * need to update our database state.
+ * need to update our database state with the information
+ * retrieved.
+ *
+ * @param cls our `struct KycProofContext`
+ * @param response_code HTTP response code from server, 0 on hard error
+ * @param response in JSON, NULL if response was not in JSON format
+ */
+static void
+handle_curl_fetch_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct KycProofContext *kpc = cls;
+ const json_t *j = response;
+
+ kpc->job = NULL;
+ switch (response_code)
+ {
+ case MHD_HTTP_OK:
+ parse_success_reply (kpc,
+ j);
+ break;
+ default:
+ handle_error (kpc,
+ j);
+ break;
+ }
+ kpc_resume (kpc);
+}
+
+
+/**
+ * After we are done with the CURL interaction we
+ * need to fetch the user's account details.
*
* @param cls our `struct KycProofContext`
* @param response_code HTTP response code from server, 0 on hard error
@@ -205,6 +383,7 @@ handle_curl_login_finished (void *cls,
&refresh_token),
GNUNET_JSON_spec_end ()
};
+ CURL *eh;
{
enum GNUNET_GenericReturnValue res;
@@ -224,8 +403,7 @@ handle_curl_login_finished (void *cls,
"Unexpected response from KYC gateway");
kpc->response_code
= MHD_HTTP_BAD_GATEWAY;
- kpc_resume (kpc);
- return;
+ break;
}
}
if (0 != strcasecmp (token_type,
@@ -238,74 +416,72 @@ handle_curl_login_finished (void *cls,
"Unexpected token type in response from KYC gateway");
kpc->response_code
= MHD_HTTP_BAD_GATEWAY;
- kpc_resume (kpc);
- return;
+ break;
}
- /* TODO: Here we might want to keep something to persist in the DB, and
- possibly use the access_token to download information we should
- persist; then continue! */
-
- kpc_resume (kpc);
- return;
- }
- default:
- {
- const char *msg;
- const char *desc;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("error",
- &msg),
- GNUNET_JSON_spec_string ("error_description",
- &desc),
- GNUNET_JSON_spec_end ()
- };
-
+ /* We guard against a few characters that could
+ conceivably be abused to mess with the HTTP header */
+ if ( (NULL != strchr (access_token,
+ '\n')) ||
+ (NULL != strchr (access_token,
+ '\r')) ||
+ (NULL != strchr (access_token,
+ ' ')) ||
+ (NULL != strchr (access_token,
+ ';')) )
{
- enum GNUNET_GenericReturnValue res;
- const char *emsg;
- unsigned int line;
-
- res = GNUNET_JSON_parse (j,
- spec,
- &emsg,
- &line);
- if (GNUNET_OK != res)
- {
- GNUNET_break_op (0);
- kpc->response
- = TALER_MHD_make_error (
- TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
- "Unexpected response from KYC gateway");
- kpc->response_code
- = MHD_HTTP_BAD_GATEWAY;
- kpc_resume (kpc);
- return;
- }
+ GNUNET_break_op (0);
+ kpc->response
+ = TALER_MHD_make_error (
+ TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
+ "Illegal character in access token");
+ kpc->response_code
+ = MHD_HTTP_BAD_GATEWAY;
+ break;
}
- /* case TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_AUTHORZATION_FAILED,
- we MAY want to in the future look at the requested content type
- and possibly respond in JSON if indicated. */
- {
- char *reply;
- GNUNET_asprintf (&reply,
- "<html><head><title>%s</title></head><body><h1>%s</h1><p>%s</p></body></html>",
- msg,
- msg,
- desc);
+ eh = curl_easy_init ();
+ if (NULL == eh)
+ {
+ GNUNET_break_op (0);
kpc->response
- = MHD_create_response_from_buffer (strlen (reply),
- reply,
- MHD_RESPMEM_MUST_COPY);
- GNUNET_assert (NULL != kpc->response);
- GNUNET_free (reply);
+ = TALER_MHD_make_error (
+ TALER_EC_GENERIC_ALLOCATION_FAILURE,
+ "curl_easy_init");
+ kpc->response_code
+ = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ break;
}
- kpc->response_code = MHD_HTTP_FORBIDDEN;
- kpc_resume (kpc);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ TEH_kyc_config.details.oauth2.info_url));
+ {
+ char *hdr;
+ struct curl_slist *slist;
+
+ GNUNET_asprintf (&hdr,
+ "%s: Bearer %s",
+ MHD_HTTP_HEADER_AUTHORIZATION,
+ access_token);
+ slist = curl_slist_append (NULL,
+ hdr);
+ kpc->job = GNUNET_CURL_job_add2 (TEH_curl_ctx,
+ eh,
+ slist,
+ &handle_curl_fetch_finished,
+ kpc);
+ curl_slist_free_all (slist);
+ GNUNET_free (hdr);
+ }
+ return;
}
+ default:
+ handle_error (kpc,
+ j);
break;
}
+ kpc_resume (kpc);
}
@@ -331,6 +507,7 @@ clean_kpc (struct TEH_RequestContext *rc)
}
GNUNET_free (kpc->post_body);
GNUNET_free (kpc->token_url);
+ GNUNET_free (kpc->id);
GNUNET_free (kpc);
}