GNUnet  0.19.4
plugin_rest_pabc.c
Go to the documentation of this file.
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  */
26 #include "platform.h"
27 #include "microhttpd.h"
28 #include <inttypes.h>
29 #include <jansson.h>
30 #include <pabc/pabc.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 #include "pabc_helper.h"
37 
41 #define GNUNET_REST_API_NS_PABC "/pabc"
42 
46 #define GNUNET_REST_API_NS_PABC_CR "/pabc/cr"
47 
52 
56 static char *allow_methods;
57 
61 struct Plugin
62 {
63  const struct GNUNET_CONFIGURATION_Handle *cfg;
64 };
65 
66 
67 struct RequestHandle
68 {
72  struct RequestHandle *next;
73 
77  struct RequestHandle *prev;
78 
83 
88 
93 
98 
102  void *proc_cls;
103 
107  char *url;
108 
112  char *emsg;
113 
117  int response_code;
118 
122  json_t *resp_object;
123 };
124 
129 
134 
135 
140 static void
141 cleanup_handle (void *cls)
142 {
143  struct RequestHandle *handle = cls;
144 
145  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
146  if (NULL != handle->resp_object)
147  json_decref (handle->resp_object);
148  if (NULL != handle->timeout_task)
149  GNUNET_SCHEDULER_cancel (handle->timeout_task);
150  if (NULL != handle->url)
151  GNUNET_free (handle->url);
152  if (NULL != handle->emsg)
153  GNUNET_free (handle->emsg);
156  handle);
158 }
159 
160 
166 static void
167 do_error (void *cls)
168 {
169  struct RequestHandle *handle = cls;
170  struct MHD_Response *resp;
171  char *json_error;
172 
173  GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg);
174  if (0 == handle->response_code)
175  {
176  handle->response_code = MHD_HTTP_BAD_REQUEST;
177  }
178  resp = GNUNET_REST_create_response (json_error);
179  MHD_add_response_header (resp, "Content-Type", "application/json");
180  handle->proc (handle->proc_cls, resp, handle->response_code);
182  GNUNET_free (json_error);
183 }
184 
185 
191 static void
192 do_timeout (void *cls)
193 {
194  struct RequestHandle *handle = cls;
195 
196  handle->timeout_task = NULL;
197  do_error (handle);
198 }
199 
200 
201 static void
202 return_response (void *cls)
203 {
204  char *result_str;
205  struct RequestHandle *handle = cls;
206  struct MHD_Response *resp;
207 
208  result_str = json_dumps (handle->resp_object, 0);
209  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
210  resp = GNUNET_REST_create_response (result_str);
211  MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
212  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
213  GNUNET_free (result_str);
215 }
216 
217 
218 static enum pabc_status
219 set_attributes_from_idtoken (const struct pabc_context *ctx,
220  const struct pabc_public_parameters *pp,
221  struct pabc_user_context *usr_ctx,
222  const char *id_token)
223 {
224  json_t *payload_json;
225  json_t *value;
226  json_error_t json_err;
227  const char *key;
228  const char *jwt_body;
229  char *decoded_jwt;
230  char delim[] = ".";
231  char *jwt_string;
232  const char *pabc_key;
233  enum pabc_status status;
234 
235  // FIXME parse JWT
236  jwt_string = GNUNET_strndup (id_token, strlen (id_token));
237  jwt_body = strtok (jwt_string, delim);
238  jwt_body = strtok (NULL, delim);
239  GNUNET_STRINGS_base64url_decode (jwt_body, strlen (jwt_body),
240  (void **) &decoded_jwt);
241  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decoded ID Token: %s\n", decoded_jwt);
242  payload_json = json_loads (decoded_jwt, JSON_DECODE_ANY, &json_err);
243  GNUNET_free (decoded_jwt);
244 
245  json_object_foreach (payload_json, key, value)
246  {
247  pabc_key = key;
248  if (0 == strcmp ("iss", key))
249  pabc_key = "issuer"; // rename
250  if (0 == strcmp ("sub", key))
251  pabc_key = "subject"; // rename
252  if (0 == strcmp ("jti", key))
253  continue;
254  if (0 == strcmp ("exp", key))
255  pabc_key = "expiration"; // rename
256  if (0 == strcmp ("iat", key))
257  continue;
258  if (0 == strcmp ("nbf", key))
259  continue;
260  if (0 == strcmp ("aud", key))
261  continue;
262  char *tmp_val;
263  if (json_is_string (value))
264  tmp_val = GNUNET_strdup (json_string_value (value));
265  else
266  tmp_val = json_dumps (value, JSON_ENCODE_ANY);
267  if (NULL == tmp_val)
268  {
270  "Unable to encode JSON value for `%s'\n", key);
271  continue;
272  }
274  "Setting `%s' to `%s'\n", key, tmp_val);
275  status = pabc_set_attribute_value_by_name (ctx, pp, usr_ctx,
276  pabc_key,
277  tmp_val);
278  GNUNET_free (tmp_val);
279  if (PABC_OK != status)
280  {
282  "Failed to set attribute `%s'.\n", key);
283  }
284  }
285  GNUNET_free (jwt_string);
286  return PABC_OK;
287 }
288 
289 
290 static enum GNUNET_GenericReturnValue
291 setup_new_user_context (struct pabc_context *ctx,
292  struct pabc_public_parameters *pp,
293  struct pabc_user_context **usr_ctx)
294 {
295  if (PABC_OK != pabc_new_user_context (ctx, pp, usr_ctx))
296  return GNUNET_SYSERR;
297 
298  if (PABC_OK != pabc_populate_user_context (ctx, *usr_ctx))
299  {
300  pabc_free_user_context (ctx, pp, usr_ctx);
301  return GNUNET_SYSERR;
302  }
303  return GNUNET_OK;
304 }
305 
306 
307 static void
308 cr_cont (struct GNUNET_REST_RequestHandle *con_handle,
309  const char *url,
310  void *cls)
311 {
312  struct RequestHandle *handle = cls;
313  char term_data[handle->rest_handle->data_size + 1];
314  char *response_str;
315  json_t *data_json;
316  json_t *nonce_json;
317  json_t *pp_json;
318  json_t *idtoken_json;
319  json_t *iss_json;
320  json_t *identity_json;
321  json_error_t err;
322  struct pabc_public_parameters *pp = NULL;
323  struct pabc_context *ctx = NULL;
324  struct pabc_user_context *usr_ctx = NULL;
325  struct pabc_credential_request *cr = NULL;
326  struct pabc_nonce *nonce = NULL;
327  enum pabc_status status;
328 
329 
331  "Credential request...\n");
332 
333  if (0 >= handle->rest_handle->data_size)
334  {
336  return;
337  }
338 
339  term_data[handle->rest_handle->data_size] = '\0';
340  GNUNET_memcpy (term_data,
341  handle->rest_handle->data,
342  handle->rest_handle->data_size);
343  data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
344  if (NULL == data_json)
345  {
347  "Unable to parse %s\n", term_data);
349  return;
350  }
351  if (! json_is_object (data_json))
352  {
354  "Unable to parse %s\n", term_data);
355  json_decref (data_json);
357  return;
358  }
359 
360  nonce_json = json_object_get (data_json, "nonce");
361  if (NULL == nonce_json)
362  {
364  "Unable to parse nonce\n");
365  json_decref (data_json);
367  return;
368  }
369  iss_json = json_object_get (data_json, "issuer");
370  if (NULL == iss_json)
371  {
373  "Unable to parse issuer\n");
374  json_decref (data_json);
376  return;
377  }
378  identity_json = json_object_get (data_json, "identity");
379  if (NULL == identity_json)
380  {
382  "Unable to parse identity\n");
383  json_decref (data_json);
385  return;
386  }
387  idtoken_json = json_object_get (data_json, "id_token");
388  if (NULL == idtoken_json)
389  {
391  "Unable to parse id_token\n");
392  json_decref (data_json);
394  return;
395  }
396  pp_json = json_object_get (data_json, "public_params");
397  if (NULL == pp_json)
398  {
400  "Unable to parse public parameters\n");
401  json_decref (data_json);
403  return;
404  }
405 
406  PABC_ASSERT (pabc_new_ctx (&ctx));
407  char *pp_str = json_dumps (pp_json, JSON_ENCODE_ANY);
408  status = pabc_decode_and_new_public_parameters (ctx,
409  &pp,
410  pp_str);
411  char *ppid;
412  GNUNET_assert (PABC_OK == pabc_cred_get_ppid_from_pp (pp_str, &ppid));
413  GNUNET_free (pp_str);
414  if (status != PABC_OK)
415  {
417  "Failed to read public parameters: %s\n",
418  pp_str);
419  json_decref (data_json);
421  return;
422  }
423  // (Over)write parameters
424  status = PABC_write_public_parameters (json_string_value (iss_json),
425  pp);
426  if (status != PABC_OK)
427  {
429  "Failed to write public parameters.\n");
430  json_decref (data_json);
432  return;
433  }
434  status = PABC_read_usr_ctx (json_string_value (identity_json),
435  json_string_value (iss_json),
436  ctx, pp, &usr_ctx);
437  if (PABC_OK != status)
438  {
439  if (GNUNET_OK != setup_new_user_context (ctx, pp, &usr_ctx))
440  {
441  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to setup user context.\n");
442  pabc_free_public_parameters (ctx, &pp);
443  json_decref (data_json);
445  return;
446  }
447  PABC_write_usr_ctx (json_string_value (identity_json),
448  json_string_value (iss_json),
449  ctx, pp, usr_ctx);
450  }
451 
452  // Set attributes from JWT to context
454  pp,
455  usr_ctx,
456  json_string_value (idtoken_json));
457  if (status != PABC_OK)
458  {
459  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to set attributes.\n");
460  pabc_free_user_context (ctx, pp, &usr_ctx);
461  pabc_free_public_parameters (ctx, &pp);
462  json_decref (data_json);
464  return;
465  }
466 
467 
468  // nonce
469  status = pabc_new_nonce (ctx, &nonce);
470  if (status != PABC_OK)
471  {
472  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to allocate nonce.\n");
473  pabc_free_user_context (ctx, pp, &usr_ctx);
474  pabc_free_public_parameters (ctx, &pp);
475  json_decref (data_json);
477  return;
478  }
479  char *nonce_str = json_dumps (nonce_json, JSON_ENCODE_ANY);
480  status = pabc_decode_nonce (ctx, nonce, nonce_str);
481  if (status != PABC_OK)
482  {
483  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to decode nonce.\n");
484  pabc_free_nonce (ctx, &nonce);
485  pabc_free_user_context (ctx, pp, &usr_ctx);
486  pabc_free_public_parameters (ctx, &pp);
487  json_decref (data_json);
489  return;
490  }
491 
492  // cr
493  status = pabc_new_credential_request (ctx, pp, &cr);
494  if (PABC_OK != status)
495  {
496  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to allocate cr.\n");
497  pabc_free_nonce (ctx, &nonce);
498  pabc_free_user_context (ctx, pp, &usr_ctx);
499  pabc_free_public_parameters (ctx, &pp);
500  json_decref (data_json);
502  return;
503  }
504 
505  status = pabc_gen_credential_request (ctx, pp, usr_ctx, nonce, cr);
506  if (PABC_OK != status)
507  {
508  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to generate cr.\n");
509  pabc_free_nonce (ctx, &nonce);
510  pabc_free_credential_request (ctx, pp, &cr);
511  pabc_free_user_context (ctx, pp, &usr_ctx);
512  pabc_free_public_parameters (ctx, &pp);
513  json_decref (data_json);
515  return;
516  }
517  handle->resp_object = json_object ();
518  GNUNET_assert (PABC_OK == pabc_cred_encode_cr (ctx, pp, cr,
519  json_string_value (
520  identity_json),
521  ppid, &response_str));
522  if (PABC_OK != status)
523  {
524  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to serialize cr.\n");
525  pabc_free_nonce (ctx, &nonce);
526  pabc_free_credential_request (ctx, pp, &cr);
527  pabc_free_user_context (ctx, pp, &usr_ctx);
528  pabc_free_public_parameters (ctx, &pp);
529  json_decref (data_json);
531  return;
532  }
533  json_decref (handle->resp_object);
534  handle->resp_object = json_loads (response_str, JSON_DECODE_ANY, &err);
535  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s\n", response_str);
536  GNUNET_free (response_str);
537 
538  // clean up
539  pabc_free_nonce (ctx, &nonce);
540  pabc_free_credential_request (ctx, pp, &cr);
541  pabc_free_user_context (ctx, pp, &usr_ctx);
542  pabc_free_public_parameters (ctx, &pp);
544  json_decref (data_json);
545 }
546 
547 
555 static void
557  const char *url,
558  void *cls)
559 {
560  struct MHD_Response *resp;
561  struct RequestHandle *handle = cls;
562 
563  // For now, independent of path return all options
564  resp = GNUNET_REST_create_response (NULL);
565  MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
566  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
568  return;
569 }
570 
571 
572 static enum GNUNET_GenericReturnValue
575  void *proc_cls)
576 {
577  struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
579  static const struct GNUNET_REST_RequestHandler handlers[] = {
580  {MHD_HTTP_METHOD_POST,
582  { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_PABC, &options_cont },
584  };
585 
586  handle->response_code = 0;
588  handle->proc_cls = proc_cls;
589  handle->proc = proc;
590  handle->rest_handle = rest_handle;
591 
592  handle->url = GNUNET_strdup (rest_handle->url);
593  if (handle->url[strlen (handle->url) - 1] == '/')
594  handle->url[strlen (handle->url) - 1] = '\0';
595  handle->timeout_task =
599  handle);
600  if (GNUNET_NO ==
601  GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
602  {
604  return GNUNET_NO;
605  }
606 
607  return GNUNET_YES;
608 }
609 
610 
617 void *
619 {
620  static struct Plugin plugin;
621  struct GNUNET_REST_Plugin *api;
622 
623  cfg = cls;
624  if (NULL != plugin.cfg)
625  return NULL; /* can only initialize once! */
626  memset (&plugin, 0, sizeof(struct Plugin));
627  plugin.cfg = cfg;
628  api = GNUNET_new (struct GNUNET_REST_Plugin);
629  api->cls = &plugin;
633  "%s, %s",
634  MHD_HTTP_METHOD_POST,
635  MHD_HTTP_METHOD_OPTIONS);
637  _ ("Identity Provider REST API initialized\n"));
638  return api;
639 }
640 
641 
648 void *
650 {
651  struct GNUNET_REST_Plugin *api = cls;
652  struct Plugin *plugin = api->cls;
653  struct RequestHandle *request;
654 
655  plugin->cfg = NULL;
656  while (NULL != (request = requests_head))
657  do_error (request);
658 
660  GNUNET_free (api);
662  "PABC REST plugin is finished\n");
663  return NULL;
664 }
665 
666 
667 /* end of plugin_rest_reclaim.c */
static struct GNUNET_CADET_MessageHandler handlers[]
Handlers, for diverse services.
struct TestcasePlugin * plugin
The process handle to the testbed service.
struct GNUNET_HashCode key
The key used in the DHT.
static struct GNUNET_DNS_Handle * handle
Handle to transport service.
uint16_t status
See PRISM_STATUS_*-constants.
static char * value
Value of the record to add/remove.
static struct GNUNET_VPN_RedirectionRequest * request
Opaque redirection request handle.
Definition: gnunet-vpn.c:40
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
Identity attribute definitions.
reclaim service; implements identity and personal data sharing for GNUnet
API for helper library to parse/create REST.
GNUnet service REST plugin header.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
struct MHD_Response * GNUNET_REST_create_response(const char *data)
Create REST MHD response.
Definition: rest.c:44
int GNUNET_REST_handle_request(struct GNUNET_REST_RequestHandle *conn, const struct GNUNET_REST_RequestHandler *handlers, struct GNUNET_REST_RequestHandlerError *err, void *cls)
Definition: rest.c:64
void(* GNUNET_REST_ResultProcessor)(void *cls, struct MHD_Response *resp, int status)
Iterator called on obtained result for a REST result.
#define GNUNET_REST_HANDLER_END
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1299
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:975
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1272
size_t GNUNET_STRINGS_base64url_decode(const char *data, size_t len, void **out)
Decode from Base64url.
Definition: strings.c:1760
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
@ MHD_HTTP_BAD_REQUEST
Bad Request [RFC7231, Section 6.5.1].
@ MHD_HTTP_OK
OK [RFC7231, Section 6.3.1].
enum GNUNET_GenericReturnValue PABC_write_public_parameters(char const *const pp_name, struct pabc_public_parameters *const pp)
Definition: pabc_helper.c:171
enum GNUNET_GenericReturnValue PABC_write_usr_ctx(char const *const usr_name, char const *const pp_name, struct pabc_context const *const ctx, struct pabc_public_parameters const *const pp, struct pabc_user_context *const usr_ctx)
Definition: pabc_helper.c:223
enum GNUNET_GenericReturnValue PABC_read_usr_ctx(char const *const usr_name, char const *const pp_name, struct pabc_context const *const ctx, struct pabc_public_parameters const *const pp, struct pabc_user_context **usr_ctx)
Definition: pabc_helper.c:295
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
void * libgnunet_plugin_rest_reclaim_done(void *cls)
Exit point from the plugin.
#define GNUNET_REST_API_NS_PABC
REST root namespace.
#define GNUNET_REST_API_NS_PABC_CR
Credential request endpoint.
static void do_timeout(void *cls)
Task run on timeout, sends error message.
static void return_response(void *cls)
const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration handle.
static void cr_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
static struct RequestHandle * requests_head
DLL.
static void options_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Respond to OPTIONS request.
static enum GNUNET_GenericReturnValue setup_new_user_context(struct pabc_context *ctx, struct pabc_public_parameters *pp, struct pabc_user_context **usr_ctx)
static char * allow_methods
HTTP methods allows for this plugin.
static struct RequestHandle * requests_tail
DLL.
static enum pabc_status set_attributes_from_idtoken(const struct pabc_context *ctx, const struct pabc_public_parameters *pp, struct pabc_user_context *usr_ctx, const char *id_token)
void * libgnunet_plugin_rest_pabc_init(void *cls)
Entry point for the plugin.
static enum GNUNET_GenericReturnValue rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
static void do_error(void *cls)
Task run on error, sends error message.
static void cleanup_handle(void *cls)
Cleanup lookup handle.
void * cls
Closure for all of the callbacks.
struct returned by the initialization function of the plugin
char * name
Plugin name.
void * cls
The closure of the plugin.
enum GNUNET_GenericReturnValue(* process_request)(struct GNUNET_REST_RequestHandle *handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function to process a REST call.
const char * url
The url as string.
void(* proc)(struct GNUNET_REST_RequestHandle *handle, const char *url, void *cls)
Namespace to handle.
Entry in list of pending tasks.
Definition: scheduler.c:136
Time for relative time used by GNUnet, in microseconds.
Handle for a plugin.
Definition: block.c:38
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:47
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
The request handle.
char * emsg
Error response message.
struct RequestHandle * prev
DLL.
int response_code
Response code.
struct GNUNET_SCHEDULER_Task * timeout_task
ID of a task associated with the resolution process.
void * proc_cls
The closure of the result processor.
GNUNET_REST_ResultProcessor proc
The plugin result processor.
struct RequestHandle * next
DLL.
json_t * resp_object
Response object.
struct GNUNET_REST_RequestHandle * rest_handle
Rest connection.
char * url
The url.
struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).