aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Schanzenbach <mschanzenbach@posteo.de>2021-02-22 15:21:15 +0100
committerMartin Schanzenbach <mschanzenbach@posteo.de>2021-04-20 10:50:35 +0200
commit8562992bff092c27d6f589667c74659831da364c (patch)
treebe609eb58fbc34ec605e213bee596905247a58e0 /src
parent2305c2f718507d3a1870606686493f32af824220 (diff)
downloadgnunet-8562992bff092c27d6f589667c74659831da364c.tar.gz
gnunet-8562992bff092c27d6f589667c74659831da364c.zip
-add pabc rest api for credential requests
Diffstat (limited to 'src')
-rw-r--r--src/reclaim/Makefile.am20
-rw-r--r--src/reclaim/plugin_rest_pabc.c560
2 files changed, 580 insertions, 0 deletions
diff --git a/src/reclaim/Makefile.am b/src/reclaim/Makefile.am
index 66e185b5a..6ad842789 100644
--- a/src/reclaim/Makefile.am
+++ b/src/reclaim/Makefile.am
@@ -18,6 +18,7 @@ CREDENTIAL_PLUGIN = \
18 18
19if HAVE_PABC 19if HAVE_PABC
20 CREDENTIAL_PLUGIN += libgnunet_plugin_reclaim_credential_pabc.la 20 CREDENTIAL_PLUGIN += libgnunet_plugin_reclaim_credential_pabc.la
21 REST_PLUGIN += libgnunet_plugin_rest_pabc.la
21endif 22endif
22 23
23EXTRA_DIST = \ 24EXTRA_DIST = \
@@ -91,6 +92,25 @@ libgnunet_plugin_rest_openid_connect_la_LDFLAGS = \
91 $(GN_PLUGIN_LDFLAGS) 92 $(GN_PLUGIN_LDFLAGS)
92libgnunet_plugin_rest_openid_connect_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS) 93libgnunet_plugin_rest_openid_connect_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
93 94
95if HAVE_PABC
96libgnunet_plugin_rest_pabc_la_SOURCES = \
97 plugin_rest_pabc.c
98libgnunet_plugin_rest_pabc_la_LIBADD = \
99 libgnunetreclaim.la \
100 $(top_builddir)/src/json/libgnunetjson.la \
101 $(top_builddir)/src/rest/libgnunetrest.la \
102 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
103 $(LTLIBINTL) -ljansson -lpabc $(MHD_LIBS)
104libgnunet_plugin_rest_pabc_la_DEPENDENCIES = \
105 libgnunetreclaim.la \
106 $(top_builddir)/src/json/libgnunetjson.la \
107 $(top_builddir)/src/rest/libgnunetrest.la \
108 $(top_builddir)/src/util/libgnunetutil.la
109libgnunet_plugin_rest_pabc_la_LDFLAGS = \
110 $(GN_PLUGIN_LDFLAGS)
111libgnunet_plugin_rest_pabc_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
112endif
113
94 114
95libgnunet_plugin_gnsrecord_reclaim_la_SOURCES = \ 115libgnunet_plugin_gnsrecord_reclaim_la_SOURCES = \
96 plugin_gnsrecord_reclaim.c 116 plugin_gnsrecord_reclaim.c
diff --git a/src/reclaim/plugin_rest_pabc.c b/src/reclaim/plugin_rest_pabc.c
new file mode 100644
index 000000000..c3bb8847f
--- /dev/null
+++ b/src/reclaim/plugin_rest_pabc.c
@@ -0,0 +1,560 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Martin Schanzenbach
22 * @file reclaim/plugin_rest_pabc.c
23 * @brief GNUnet pabc REST plugin
24 *
25 */
26#include "platform.h"
27#include "microhttpd.h"
28#include <inttypes.h>
29#include <jansson.h>
30#include <libpabc/libpabc.h>
31#include "gnunet_reclaim_lib.h"
32#include "gnunet_reclaim_service.h"
33#include "gnunet_rest_lib.h"
34#include "gnunet_rest_plugin.h"
35#include "gnunet_signatures.h"
36
37/**
38 * REST root namespace
39 */
40#define GNUNET_REST_API_NS_PABC "/pabc"
41
42/**
43 * Credential request endpoint
44 */
45#define GNUNET_REST_API_NS_PABC_CR "/pabc/cr"
46
47/**
48 * The configuration handle
49 */
50const struct GNUNET_CONFIGURATION_Handle *cfg;
51
52/**
53 * HTTP methods allows for this plugin
54 */
55static char *allow_methods;
56
57/**
58 * @brief struct returned by the initialization function of the plugin
59 */
60struct Plugin
61{
62 const struct GNUNET_CONFIGURATION_Handle *cfg;
63};
64
65
66struct RequestHandle
67{
68 /**
69 * DLL
70 */
71 struct RequestHandle *next;
72
73 /**
74 * DLL
75 */
76 struct RequestHandle *prev;
77
78 /**
79 * Rest connection
80 */
81 struct GNUNET_REST_RequestHandle *rest_handle;
82
83 /**
84 * Desired timeout for the lookup (default is no timeout).
85 */
86 struct GNUNET_TIME_Relative timeout;
87
88 /**
89 * ID of a task associated with the resolution process.
90 */
91 struct GNUNET_SCHEDULER_Task *timeout_task;
92
93 /**
94 * The plugin result processor
95 */
96 GNUNET_REST_ResultProcessor proc;
97
98 /**
99 * The closure of the result processor
100 */
101 void *proc_cls;
102
103 /**
104 * The url
105 */
106 char *url;
107
108 /**
109 * Error response message
110 */
111 char *emsg;
112
113 /**
114 * Reponse code
115 */
116 int response_code;
117
118 /**
119 * Response object
120 */
121 json_t *resp_object;
122};
123
124/**
125 * DLL
126 */
127static struct RequestHandle *requests_head;
128
129/**
130 * DLL
131 */
132static struct RequestHandle *requests_tail;
133
134
135/**
136 * Cleanup lookup handle
137 * @param handle Handle to clean up
138 */
139static void
140cleanup_handle (void *cls)
141{
142 struct RequestHandle *handle = cls;
143
144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
145 if (NULL != handle->resp_object)
146 json_decref (handle->resp_object);
147 if (NULL != handle->timeout_task)
148 GNUNET_SCHEDULER_cancel (handle->timeout_task);
149 if (NULL != handle->url)
150 GNUNET_free (handle->url);
151 if (NULL != handle->emsg)
152 GNUNET_free (handle->emsg);
153 GNUNET_CONTAINER_DLL_remove (requests_head,
154 requests_tail,
155 handle);
156 GNUNET_free (handle);
157}
158
159
160/**
161 * Task run on error, sends error message. Cleans up everything.
162 *
163 * @param cls the `struct RequestHandle`
164 */
165static void
166do_error (void *cls)
167{
168 struct RequestHandle *handle = cls;
169 struct MHD_Response *resp;
170 char *json_error;
171
172 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg);
173 if (0 == handle->response_code)
174 {
175 handle->response_code = MHD_HTTP_BAD_REQUEST;
176 }
177 resp = GNUNET_REST_create_response (json_error);
178 MHD_add_response_header (resp, "Content-Type", "application/json");
179 handle->proc (handle->proc_cls, resp, handle->response_code);
180 cleanup_handle (handle);
181 GNUNET_free (json_error);
182}
183
184
185/**
186 * Task run on timeout, sends error message. Cleans up everything.
187 *
188 * @param cls the `struct RequestHandle`
189 */
190static void
191do_timeout (void *cls)
192{
193 struct RequestHandle *handle = cls;
194
195 handle->timeout_task = NULL;
196 do_error (handle);
197}
198
199
200static void
201return_response (void *cls)
202{
203 char *result_str;
204 struct RequestHandle *handle = cls;
205 struct MHD_Response *resp;
206
207 result_str = json_dumps (handle->resp_object, 0);
208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
209 resp = GNUNET_REST_create_response (result_str);
210 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
211 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
212 GNUNET_free (result_str);
213 cleanup_handle (handle);
214}
215
216static enum pabc_status
217set_attributes_from_idtoken (const struct pabc_context *ctx,
218 const struct pabc_public_parameters *pp,
219 struct pabc_user_context *usr_ctx,
220 const char *id_token)
221{
222 json_t *payload_json;
223 json_t *value;
224 const char *key;
225 enum pabc_status status;
226
227 //FIXME parse JWT
228 json_object_foreach(payload_json, key, value)
229 {
230 //FIXME skip metadata in JWT, map attributes to PP
231 status = pabc_set_attribute_value_by_name (ctx, pp, usr_ctx,
232 key,
233 json_string_value (value));
234 if (PABC_OK != status)
235 {
236 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
237 "Failed to set attribute.\n");
238 return PABC_FAILURE;
239 }
240 }
241 return PABC_OK;
242}
243
244
245static void
246cr_cont (struct GNUNET_REST_RequestHandle *con_handle,
247 const char *url,
248 void *cls)
249{
250 struct RequestHandle *handle = cls;
251 char term_data[handle->rest_handle->data_size + 1];
252 char *response_str;
253 json_t *data_json;
254 json_t *nonce_json;
255 json_t *pp_json;
256 json_t *idtoken_json;
257 json_error_t err;
258 struct pabc_public_parameters *pp = NULL;
259 struct pabc_context *ctx = NULL;
260 struct pabc_user_context *usr_ctx = NULL;
261 struct pabc_credential_request *cr = NULL;
262 struct pabc_nonce *nonce = NULL;
263 enum pabc_status status;
264
265
266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
267 "Credential request...\n");
268
269 if (0 >= handle->rest_handle->data_size)
270 {
271 GNUNET_SCHEDULER_add_now (&do_error, handle);
272 return;
273 }
274
275 term_data[handle->rest_handle->data_size] = '\0';
276 GNUNET_memcpy (term_data,
277 handle->rest_handle->data,
278 handle->rest_handle->data_size);
279 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
280 if (NULL == data_json)
281 {
282 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
283 "Unable to parse %s\n", term_data);
284 GNUNET_SCHEDULER_add_now (&do_error, handle);
285 return;
286 }
287 if (!json_is_object (data_json))
288 {
289 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
290 "Unable to parse %s\n", term_data);
291 json_decref (data_json);
292 GNUNET_SCHEDULER_add_now (&do_error, handle);
293 return;
294 }
295
296 nonce_json = json_object_get (data_json, "nonce");
297 if (NULL == nonce_json)
298 {
299 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
300 "Unable to parse nonce\n");
301 json_decref (data_json);
302 GNUNET_SCHEDULER_add_now (&do_error, handle);
303 return;
304 }
305 idtoken_json = json_object_get (idtoken_json, "id_token");
306 if (NULL == idtoken_json)
307 {
308 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
309 "Unable to parse id_token\n");
310 json_decref (data_json);
311 GNUNET_SCHEDULER_add_now (&do_error, handle);
312 return;
313 }
314 pp_json = json_object_get (data_json, "public_params");
315 if (NULL == pp_json)
316 {
317 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
318 "Unable to parse public parameters\n");
319 json_decref (data_json);
320 GNUNET_SCHEDULER_add_now (&do_error, handle);
321 return;
322 }
323
324 PABC_ASSERT (pabc_new_ctx (&ctx));
325 // load stuff FIXME: Needs helper
326 //status = load_public_parameters (ctx, pp_name, &pp);
327 if (status != PABC_OK)
328 {
329 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to read public parameters.\n");
330 json_decref (data_json);
331 GNUNET_SCHEDULER_add_now (&do_error, handle);
332 return;
333 }
334
335 /*FIXME: Needs helper
336 * status = read_usr_ctx (usr_name, pp_name, ctx, pp, &usr_ctx);
337 */
338 if (PABC_OK != status)
339 {
340 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to read user context.\n");
341 pabc_free_public_parameters (ctx, &pp);
342 json_decref (data_json);
343 GNUNET_SCHEDULER_add_now (&do_error, handle);
344 return;
345 }
346
347 // Set attributes from JWT to context
348 status = set_attributes_from_idtoken (ctx,
349 pp,
350 usr_ctx,
351 json_string_value (idtoken_json));
352 if (status != PABC_OK)
353 {
354 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to set attributes.\n");
355 pabc_free_user_context (ctx, pp, &usr_ctx);
356 pabc_free_public_parameters (ctx, &pp);
357 json_decref (data_json);
358 GNUNET_SCHEDULER_add_now (&do_error, handle);
359 return;
360 }
361
362
363 // nonce
364 status = pabc_new_nonce (ctx, &nonce);
365 if (status != PABC_OK)
366 {
367 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to allocate nonce.\n");
368 pabc_free_user_context (ctx, pp, &usr_ctx);
369 pabc_free_public_parameters (ctx, &pp);
370 json_decref (data_json);
371 GNUNET_SCHEDULER_add_now (&do_error, handle);
372 return;
373 }
374 //FIXME: where does this come from???
375 status = pabc_decode_nonce (ctx, nonce, json_string_value (nonce_json));
376 if (status != PABC_OK)
377 {
378 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to decode nonce.\n");
379 pabc_free_nonce (ctx, &nonce);
380 pabc_free_user_context (ctx, pp, &usr_ctx);
381 pabc_free_public_parameters (ctx, &pp);
382 json_decref (data_json);
383 GNUNET_SCHEDULER_add_now (&do_error, handle);
384 return;
385 }
386
387 // cr
388 status = pabc_new_credential_request (ctx, pp, &cr);
389 if (PABC_OK != status)
390 {
391 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to allocate cr.\n");
392 pabc_free_nonce (ctx, &nonce);
393 pabc_free_user_context (ctx, pp, &usr_ctx);
394 pabc_free_public_parameters (ctx, &pp);
395 json_decref (data_json);
396 GNUNET_SCHEDULER_add_now (&do_error, handle);
397 return;
398 }
399
400 status = pabc_gen_credential_request (ctx, pp, usr_ctx, nonce, cr);
401 if (PABC_OK != status)
402 {
403 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to generate cr.\n");
404 pabc_free_nonce (ctx, &nonce);
405 pabc_free_credential_request (ctx, pp, &cr);
406 pabc_free_user_context (ctx, pp, &usr_ctx);
407 pabc_free_public_parameters (ctx, &pp);
408 json_decref (data_json);
409 GNUNET_SCHEDULER_add_now (&do_error, handle);
410 return;
411 }
412 handle->resp_object = json_object ();
413 pabc_encode_credential_request (ctx, pp, cr, &response_str);
414 if (PABC_OK != status)
415 {
416 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to serialize cr.\n");
417 pabc_free_nonce (ctx, &nonce);
418 pabc_free_credential_request (ctx, pp, &cr);
419 pabc_free_user_context (ctx, pp, &usr_ctx);
420 pabc_free_public_parameters (ctx, &pp);
421 json_decref (data_json);
422 GNUNET_SCHEDULER_add_now (&do_error, handle);
423 return;
424 }
425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s\n", response_str);
426 json_object_set_new (handle->resp_object, "cr",
427 json_string (response_str));
428 GNUNET_free (response_str);
429
430 // clean up
431 pabc_free_nonce (ctx, &nonce);
432 pabc_free_credential_request (ctx, pp, &cr);
433 pabc_free_user_context (ctx, pp, &usr_ctx);
434 pabc_free_public_parameters (ctx, &pp);
435 GNUNET_SCHEDULER_add_now (&return_response, handle);
436 json_decref (data_json);
437}
438
439
440/**
441 * Respond to OPTIONS request
442 *
443 * @param con_handle the connection handle
444 * @param url the url
445 * @param cls the RequestHandle
446 */
447static void
448options_cont (struct GNUNET_REST_RequestHandle *con_handle,
449 const char *url,
450 void *cls)
451{
452 struct MHD_Response *resp;
453 struct RequestHandle *handle = cls;
454
455 // For now, independent of path return all options
456 resp = GNUNET_REST_create_response (NULL);
457 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
458 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
459 cleanup_handle (handle);
460 return;
461}
462
463
464static enum GNUNET_GenericReturnValue
465rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
466 GNUNET_REST_ResultProcessor proc,
467 void *proc_cls)
468{
469 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
470 struct GNUNET_REST_RequestHandlerError err;
471 static const struct GNUNET_REST_RequestHandler handlers[] =
472 {
473 {MHD_HTTP_METHOD_POST,
474 GNUNET_REST_API_NS_PABC_CR, &cr_cont },
475 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_PABC, &options_cont },
476 GNUNET_REST_HANDLER_END
477 };
478
479 handle->response_code = 0;
480 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
481 handle->proc_cls = proc_cls;
482 handle->proc = proc;
483 handle->rest_handle = rest_handle;
484
485 handle->url = GNUNET_strdup (rest_handle->url);
486 if (handle->url[strlen (handle->url) - 1] == '/')
487 handle->url[strlen (handle->url) - 1] = '\0';
488 handle->timeout_task =
489 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
490 GNUNET_CONTAINER_DLL_insert (requests_head,
491 requests_tail,
492 handle);
493 if (GNUNET_NO ==
494 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
495 {
496 cleanup_handle (handle);
497 return GNUNET_NO;
498 }
499
500 return GNUNET_YES;
501}
502
503
504/**
505 * Entry point for the plugin.
506 *
507 * @param cls Config info
508 * @return NULL on error, otherwise the plugin context
509 */
510void *
511libgnunet_plugin_rest_reclaim_init (void *cls)
512{
513 static struct Plugin plugin;
514 struct GNUNET_REST_Plugin *api;
515
516 cfg = cls;
517 if (NULL != plugin.cfg)
518 return NULL; /* can only initialize once! */
519 memset (&plugin, 0, sizeof(struct Plugin));
520 plugin.cfg = cfg;
521 api = GNUNET_new (struct GNUNET_REST_Plugin);
522 api->cls = &plugin;
523 api->name = GNUNET_REST_API_NS_PABC;
524 api->process_request = &rest_identity_process_request;
525 GNUNET_asprintf (&allow_methods,
526 "%s, %s",
527 MHD_HTTP_METHOD_POST,
528 MHD_HTTP_METHOD_OPTIONS);
529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
530 _ ("Identity Provider REST API initialized\n"));
531 return api;
532}
533
534
535/**
536 * Exit point from the plugin.
537 *
538 * @param cls the plugin context (as returned by "init")
539 * @return always NULL
540 */
541void *
542libgnunet_plugin_rest_reclaim_done (void *cls)
543{
544 struct GNUNET_REST_Plugin *api = cls;
545 struct Plugin *plugin = api->cls;
546 struct RequestHandle *request;
547
548 plugin->cfg = NULL;
549 while (NULL != (request = requests_head))
550 do_error (request);
551
552 GNUNET_free (allow_methods);
553 GNUNET_free (api);
554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
555 "PABC REST plugin is finished\n");
556 return NULL;
557}
558
559
560/* end of plugin_rest_reclaim.c */