aboutsummaryrefslogtreecommitdiff
path: root/src/identity-provider/plugin_rest_identity_provider.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/identity-provider/plugin_rest_identity_provider.c')
-rw-r--r--src/identity-provider/plugin_rest_identity_provider.c1067
1 files changed, 1067 insertions, 0 deletions
diff --git a/src/identity-provider/plugin_rest_identity_provider.c b/src/identity-provider/plugin_rest_identity_provider.c
new file mode 100644
index 000000000..3250a9fbd
--- /dev/null
+++ b/src/identity-provider/plugin_rest_identity_provider.c
@@ -0,0 +1,1067 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20/**
21 * @author Martin Schanzenbach
22 * @file identity/plugin_rest_identity.c
23 * @brief GNUnet Namestore REST plugin
24 *
25 */
26
27#include "platform.h"
28#include "gnunet_rest_plugin.h"
29#include "gnunet_identity_service.h"
30#include "gnunet_gns_service.h"
31#include "gnunet_gnsrecord_lib.h"
32#include "gnunet_namestore_service.h"
33#include "gnunet_rest_lib.h"
34#include "microhttpd.h"
35#include <jansson.h>
36#include "gnunet_signatures.h"
37#include "gnunet_identity_provider_service.h"
38
39/**
40 * REST root namespace
41 */
42#define GNUNET_REST_API_NS_IDENTITY_PROVIDER "/idp"
43
44/**
45 * Issue namespace
46 */
47#define GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE "/idp/issue"
48
49/**
50 * Check namespace TODO
51 */
52#define GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK "/idp/check"
53
54/**
55 * Token namespace
56 */
57#define GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN "/idp/token"
58
59/**
60 * The URL parameter name in which the ticket must be provided
61 */
62#define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET "ticket"
63
64/**
65 * The URL parameter name in which the nonce must be provided
66 */
67#define GNUNET_IDENTITY_TOKEN_REQUEST_NONCE "nonce"
68
69/**
70 * State while collecting all egos
71 */
72#define ID_REST_STATE_INIT 0
73
74/**
75 * Done collecting egos
76 */
77#define ID_REST_STATE_POST_INIT 1
78
79/**
80 * Resource type
81 */
82#define GNUNET_REST_JSONAPI_IDENTITY_TOKEN "token"
83
84/**
85 * URL parameter to create a GNUid token for a specific audience
86 */
87#define GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST "audience"
88
89/**
90 * URL parameter to create a GNUid token for a specific issuer (EGO)
91 */
92#define GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST "issuer"
93
94/**
95 * Attributes passed to issue request
96 */
97#define GNUNET_IDENTITY_TOKEN_ATTR_LIST "requested_attrs"
98
99/**
100 * Token expiration string
101 */
102#define GNUNET_IDENTITY_TOKEN_EXP_STRING "expiration"
103
104/**
105 * Error messages
106 */
107#define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
108#define GNUNET_REST_ERROR_NO_DATA "No data"
109
110/**
111 * GNUid token lifetime
112 */
113#define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
114
115/**
116 * The configuration handle
117 */
118const struct GNUNET_CONFIGURATION_Handle *cfg;
119
120/**
121 * HTTP methods allows for this plugin
122 */
123static char* allow_methods;
124
125/**
126 * @brief struct returned by the initialization function of the plugin
127 */
128struct Plugin
129{
130 const struct GNUNET_CONFIGURATION_Handle *cfg;
131};
132
133/**
134 * The ego list
135 */
136struct EgoEntry
137{
138 /**
139 * DLL
140 */
141 struct EgoEntry *next;
142
143 /**
144 * DLL
145 */
146 struct EgoEntry *prev;
147
148 /**
149 * Ego Identifier
150 */
151 char *identifier;
152
153 /**
154 * Public key string
155 */
156 char *keystring;
157
158 /**
159 * The Ego
160 */
161 struct GNUNET_IDENTITY_Ego *ego;
162};
163
164
165struct RequestHandle
166{
167 /**
168 * Ego list
169 */
170 struct EgoEntry *ego_head;
171
172 /**
173 * Ego list
174 */
175 struct EgoEntry *ego_tail;
176
177 /**
178 * Selected ego
179 */
180 struct EgoEntry *ego_entry;
181
182 /**
183 * Ptr to current ego private key
184 */
185 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
186
187 /**
188 * Handle to the rest connection
189 */
190 struct RestConnectionDataHandle *conndata_handle;
191
192 /**
193 * The processing state
194 */
195 int state;
196
197 /**
198 * Handle to Identity service.
199 */
200 struct GNUNET_IDENTITY_Handle *identity_handle;
201
202 /**
203 * IDENTITY Operation
204 */
205 struct GNUNET_IDENTITY_Operation *op;
206
207 /**
208 * Identity Provider
209 */
210 struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
211
212 /**
213 * Idp Operation
214 */
215 struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
216
217 /**
218 * Handle to NS service
219 */
220 struct GNUNET_NAMESTORE_Handle *ns_handle;
221
222 /**
223 * NS iterator
224 */
225 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
226
227 /**
228 * NS Handle
229 */
230 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
231
232 /**
233 * Desired timeout for the lookup (default is no timeout).
234 */
235 struct GNUNET_TIME_Relative timeout;
236
237 /**
238 * ID of a task associated with the resolution process.
239 */
240 struct GNUNET_SCHEDULER_Task * timeout_task;
241
242 /**
243 * The plugin result processor
244 */
245 GNUNET_REST_ResultProcessor proc;
246
247 /**
248 * The closure of the result processor
249 */
250 void *proc_cls;
251
252 /**
253 * The url
254 */
255 char *url;
256
257 /**
258 * Error response message
259 */
260 char *emsg;
261
262 /**
263 * Response object
264 */
265 struct JsonApiObject *resp_object;
266
267};
268
269
270/**
271 * Cleanup lookup handle
272 * @param handle Handle to clean up
273 */
274static void
275cleanup_handle (struct RequestHandle *handle)
276{
277 struct EgoEntry *ego_entry;
278 struct EgoEntry *ego_tmp;
279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
280 "Cleaning up\n");
281 if (NULL != handle->resp_object)
282 GNUNET_REST_jsonapi_object_delete (handle->resp_object);
283 if (NULL != handle->timeout_task)
284 GNUNET_SCHEDULER_cancel (handle->timeout_task);
285 if (NULL != handle->identity_handle)
286 GNUNET_IDENTITY_disconnect (handle->identity_handle);
287 if (NULL != handle->idp)
288 GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
289 if (NULL != handle->ns_it)
290 GNUNET_NAMESTORE_zone_iteration_stop (handle->ns_it);
291 if (NULL != handle->ns_qe)
292 GNUNET_NAMESTORE_cancel (handle->ns_qe);
293 if (NULL != handle->ns_handle)
294 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
295 if (NULL != handle->url)
296 GNUNET_free (handle->url);
297 if (NULL != handle->emsg)
298 GNUNET_free (handle->emsg);
299 for (ego_entry = handle->ego_head;
300 NULL != ego_entry;)
301 {
302 ego_tmp = ego_entry;
303 ego_entry = ego_entry->next;
304 GNUNET_free (ego_tmp->identifier);
305 GNUNET_free (ego_tmp->keystring);
306 GNUNET_free (ego_tmp);
307 }
308 GNUNET_free (handle);
309}
310
311
312/**
313 * Task run on shutdown. Cleans up everything.
314 *
315 * @param cls unused
316 * @param tc scheduler context
317 */
318static void
319do_error (void *cls,
320 const struct GNUNET_SCHEDULER_TaskContext *tc)
321{
322 struct RequestHandle *handle = cls;
323 struct MHD_Response *resp;
324 char *json_error;
325
326 GNUNET_asprintf (&json_error,
327 "{Error while processing request: %s}",
328 handle->emsg);
329 resp = GNUNET_REST_create_json_response (json_error);
330 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
331 cleanup_handle (handle);
332 GNUNET_free (json_error);
333}
334
335/**
336 * Task run on shutdown. Cleans up everything.
337 *
338 * @param cls unused
339 * @param tc scheduler context
340 */
341static void
342do_cleanup_handle_delayed (void *cls,
343 const struct GNUNET_SCHEDULER_TaskContext *tc)
344{
345 struct RequestHandle *handle = cls;
346 cleanup_handle(handle);
347}
348
349
350/**
351 * Get a ticket for identity
352 * @param cls the handle
353 * @param ticket the ticket returned from the idp
354 */
355static void
356token_creat_cont (void *cls,
357 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
358{
359 struct JsonApiResource *json_resource;
360 struct RequestHandle *handle = cls;
361 struct MHD_Response *resp;
362 json_t *token_ticket_json;
363 char *ticket_str;
364 char *result_str;
365
366 if (NULL == ticket)
367 {
368 handle->emsg = GNUNET_strdup ("Error in token issue");
369 GNUNET_SCHEDULER_add_now (&do_error, handle);
370 return;
371 }
372
373 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
374 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
375 "tmpid"); //TODO
376 ticket_str = GNUNET_IDENTITY_PROVIDER_ticket_to_string (ticket);
377 token_ticket_json = json_string (ticket_str);
378 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
379 GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
380 token_ticket_json);
381 GNUNET_free (ticket_str);
382 json_decref (token_ticket_json);
383 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
384 GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result_str);
385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
386 resp = GNUNET_REST_create_json_response (result_str);
387 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
388 GNUNET_free (result_str);
389 GNUNET_SCHEDULER_add_now (&do_cleanup_handle_delayed, handle);
390
391
392}
393
394/**
395 * Continueationf for token issue request
396 *
397 * @param con the Rest handle
398 * @param url the requested url
399 * @param cls the request handle
400 */
401static void
402issue_token_cont (struct RestConnectionDataHandle *con,
403 const char *url,
404 void *cls)
405{
406 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
407 const char *egoname;
408
409 struct RequestHandle *handle = cls;
410 struct EgoEntry *ego_entry;
411 struct GNUNET_HashCode key;
412 struct MHD_Response *resp;
413 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
414 struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
415 struct GNUNET_TIME_Relative etime_rel;
416 struct GNUNET_TIME_Absolute exp_time;
417 char *ego_val;
418 char *audience;
419 char *exp_str;
420 char *nonce_str;
421 char *scopes;
422 uint64_t time;
423 uint64_t nonce;
424
425 if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url,
426 GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE))
427 {
428 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "URL invalid: %s\n", handle->url);
429 resp = GNUNET_REST_create_json_response (NULL);
430 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
431 cleanup_handle (handle);
432 return;
433 }
434 egoname = NULL;
435 ego_entry = NULL;
436 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
437 strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
438 &key);
439 if ( GNUNET_YES ==
440 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
441 &key) )
442 {
443 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Issuer not found\n");
444 GNUNET_SCHEDULER_add_now (&do_error, handle);
445 return;
446 }
447 ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
448 &key);
449 if (NULL == ego_val)
450 {
451 GNUNET_SCHEDULER_add_now (&do_error, handle);
452 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego invalid: %s\n", ego_val);
453 return;
454 }
455 for (ego_entry = handle->ego_head;
456 NULL != ego_entry;
457 ego_entry = ego_entry->next)
458 {
459 if (0 != strcmp (ego_val, ego_entry->identifier))
460 continue;
461 egoname = ego_entry->identifier;
462 break;
463 }
464 if (NULL == egoname || NULL == ego_entry)
465 {
466 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego not found: %s\n", ego_val);
467 GNUNET_SCHEDULER_add_now (&do_error, handle);
468 return;
469 }
470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego to issue token for: %s\n", egoname);
471
472
473 //Meta info
474 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_ATTR_LIST,
475 strlen (GNUNET_IDENTITY_TOKEN_ATTR_LIST),
476 &key);
477
478 scopes = NULL;
479 if ( GNUNET_YES !=
480 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
481 &key) )
482 {
483 handle->emsg = GNUNET_strdup ("Scopes missing!\n");
484 GNUNET_SCHEDULER_add_now (&do_error, handle);
485 return;
486 }
487 scopes = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
488 &key);
489
490
491 //Token audience
492 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST,
493 strlen (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST),
494 &key);
495 audience = NULL;
496 if ( GNUNET_YES !=
497 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
498 &key) )
499 {
500 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Audience missing!\n");
501 GNUNET_SCHEDULER_add_now (&do_error, handle);
502 return;
503 }
504 audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
505 &key);
506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Audience to issue token for: %s\n", audience);
507
508 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
509 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
510 &pub_key);
511 GNUNET_STRINGS_string_to_data (audience,
512 strlen (audience),
513 &aud_key,
514 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
515
516 //Remote nonce
517 nonce_str = NULL;
518 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE,
519 strlen (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE),
520 &key);
521 if ( GNUNET_YES !=
522 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
523 &key) )
524 {
525 handle->emsg = GNUNET_strdup ("Request nonce missing!\n");
526 GNUNET_SCHEDULER_add_now (&do_error, handle);
527 return;
528 }
529 nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
530 &key);
531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
532 sscanf (nonce_str, "%lu", &nonce);
533
534 //Get expiration for token from URL parameter
535 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_EXP_STRING,
536 strlen (GNUNET_IDENTITY_TOKEN_EXP_STRING),
537 &key);
538
539 exp_str = NULL;
540 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
541 &key))
542 {
543 exp_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
544 &key);
545 }
546 if (NULL == exp_str) {
547 handle->emsg = GNUNET_strdup ("No expiration given!\n");
548 GNUNET_SCHEDULER_add_now (&do_error, handle);
549 return;
550 }
551
552 if (GNUNET_OK !=
553 GNUNET_STRINGS_fancy_time_to_relative (exp_str,
554 &etime_rel))
555 {
556 handle->emsg = GNUNET_strdup ("Expiration invalid!\n");
557 GNUNET_SCHEDULER_add_now (&do_error, handle);
558 return;
559 }
560 time = GNUNET_TIME_absolute_get().abs_value_us;
561 exp_time.abs_value_us = time + etime_rel.rel_value_us;
562
563 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
564 handle->idp_op = GNUNET_IDENTITY_PROVIDER_issue_token (handle->idp,
565 priv_key,
566 &aud_key,
567 scopes,
568 exp_time,
569 nonce,
570 &token_creat_cont,
571 handle);
572
573}
574
575
576/**
577 * Build a GNUid token for identity
578 *
579 * @param cls the request handle
580 * @param tc task context
581 */
582static void
583return_token_list (void *cls,
584 const struct GNUNET_SCHEDULER_TaskContext *tc)
585{
586 char* result_str;
587 struct RequestHandle *handle = cls;
588 struct MHD_Response *resp;
589
590 GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result_str);
591 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
592 resp = GNUNET_REST_create_json_response (result_str);
593 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
594 GNUNET_free (result_str);
595 cleanup_handle (handle);
596}
597
598/**
599 * Collect all tokens for an ego
600 *
601 * TODO move this into the identity-provider service
602 *
603 */
604static void
605token_collect (void *cls,
606 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
607 const char *label,
608 unsigned int rd_count,
609 const struct GNUNET_GNSRECORD_Data *rd)
610{
611 int i;
612 char* data;
613 struct RequestHandle *handle = cls;
614 struct EgoEntry *ego_tmp;
615 struct JsonApiResource *json_resource;
616 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
617 json_t *issuer;
618 json_t *token;
619
620 if (NULL == label)
621 {
622 ego_tmp = handle->ego_head;
623 GNUNET_CONTAINER_DLL_remove (handle->ego_head,
624 handle->ego_tail,
625 ego_tmp);
626 GNUNET_free (ego_tmp->identifier);
627 GNUNET_free (ego_tmp->keystring);
628 GNUNET_free (ego_tmp);
629
630 if (NULL == handle->ego_head)
631 {
632 //Done
633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token END\n");
634 handle->ns_it = NULL;
635 GNUNET_SCHEDULER_add_now (&return_token_list, handle);
636 return;
637 }
638
639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Next ego: %s\n", handle->ego_head->identifier);
640 priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
641 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
642 priv_key,
643 &token_collect,
644 handle);
645 return;
646 }
647
648 for (i = 0; i < rd_count; i++)
649 {
650 if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
651 {
652 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
653 rd[i].data,
654 rd[i].data_size);
655 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token: %s\n", data);
656 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
657 label);
658 issuer = json_string (handle->ego_head->identifier);
659 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
660 GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
661 issuer);
662 json_decref (issuer);
663 token = json_string (data);
664 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
665 GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
666 token);
667 json_decref (token);
668
669 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
670 GNUNET_free (data);
671 }
672 }
673
674 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
675}
676
677
678
679/**
680 * Respond to OPTIONS request
681 *
682 * @param con_handle the connection handle
683 * @param url the url
684 * @param cls the RequestHandle
685 */
686static void
687list_token_cont (struct RestConnectionDataHandle *con_handle,
688 const char* url,
689 void *cls)
690{
691 char* ego_val;
692 struct GNUNET_HashCode key;
693 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
694 struct RequestHandle *handle = cls;
695 struct EgoEntry *ego_entry;
696 struct EgoEntry *ego_tmp;
697
698 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
699 strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
700 &key);
701
702 if ( GNUNET_YES !=
703 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
704 &key) )
705 {
706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No issuer given.\n");
707 GNUNET_SCHEDULER_add_now (&do_error, handle);
708 return;
709 }
710 ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
711 &key);
712 //Remove non-matching egos
713 for (ego_entry = handle->ego_head;
714 NULL != ego_entry;)
715 {
716 ego_tmp = ego_entry;
717 ego_entry = ego_entry->next;
718 if (0 != strcmp (ego_val, ego_tmp->identifier))
719 {
720 GNUNET_CONTAINER_DLL_remove (handle->ego_head,
721 handle->ego_tail,
722 ego_tmp);
723 GNUNET_free (ego_tmp->identifier);
724 GNUNET_free (ego_tmp->keystring);
725 GNUNET_free (ego_tmp);
726 }
727 }
728 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
729 if (NULL == handle->ego_head)
730 {
731 //Done
732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No results.\n");
733 GNUNET_SCHEDULER_add_now (&return_token_list, handle);
734 return;
735 }
736 priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
737 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
738 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
739 priv_key,
740 &token_collect,
741 handle);
742
743}
744
745/**
746 * Return token to requestor
747 *
748 * @param cls request handle
749 * @param token the token
750 */
751static void
752exchange_cont (void *cls,
753 const struct GNUNET_IDENTITY_PROVIDER_Token *token)
754{
755 json_t *root;
756 struct RequestHandle *handle = cls;
757 struct MHD_Response *resp;
758 char* result;
759 char* token_str;
760
761 root = json_object ();
762 token_str = GNUNET_IDENTITY_PROVIDER_token_to_string (token);
763 json_object_set_new (root, "identity_token", json_string (token_str));
764 json_object_set_new (root, "token_type", json_string ("jwt"));
765 GNUNET_free (token_str);
766
767 result = json_dumps (root, JSON_INDENT(1));
768 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", result);
769 resp = GNUNET_REST_create_json_response (result);
770 GNUNET_free (result);
771 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
772 cleanup_handle (handle);
773 json_decref (root);
774}
775
776
777/**
778 *
779 * Callback called when identity for token exchange has been found
780 *
781 * @param cls request handle
782 * @param ego the identity to use as issuer
783 * @param ctx user context
784 * @param name identity name
785 *
786 */
787static void
788exchange_token_ticket_cb (void *cls,
789 struct GNUNET_IDENTITY_Ego *ego,
790 void **ctx,
791 const char *name)
792{
793 struct RequestHandle *handle = cls;
794 struct GNUNET_HashCode key;
795 struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket;
796 char* ticket_str;
797
798 handle->op = NULL;
799
800 if (NULL == ego)
801 {
802 handle->emsg = GNUNET_strdup ("No identity found.");
803 GNUNET_SCHEDULER_add_now (&do_error, handle);
804 return;
805 }
806
807 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
808 strlen (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET),
809 &key);
810
811 if ( GNUNET_NO ==
812 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
813 &key) )
814 {
815 handle->emsg = GNUNET_strdup ("No ticket given.");
816 GNUNET_SCHEDULER_add_now (&do_error, handle);
817 return;
818 }
819 ticket_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
820 &key);
821
822 handle->priv_key = GNUNET_IDENTITY_ego_get_private_key (ego);
823 GNUNET_IDENTITY_PROVIDER_string_to_ticket (ticket_str,
824 &ticket);
825
826 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
827 handle->idp_op = GNUNET_IDENTITY_PROVIDER_exchange_ticket (handle->idp,
828 ticket,
829 handle->priv_key,
830 &exchange_cont,
831 handle);
832 GNUNET_IDENTITY_PROVIDER_ticket_destroy (ticket);
833
834}
835
836
837
838/**
839 * Respond to issue request
840 *
841 * @param con_handle the connection handle
842 * @param url the url
843 * @param cls the RequestHandle
844 */
845static void
846exchange_token_ticket_cont (struct RestConnectionDataHandle *con_handle,
847 const char* url,
848 void *cls)
849{
850 struct RequestHandle *handle = cls;
851
852 //Get token from GNS
853 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
854 "gns-master",
855 &exchange_token_ticket_cb,
856 handle);
857}
858
859/**
860 * Respond to OPTIONS request
861 *
862 * @param con_handle the connection handle
863 * @param url the url
864 * @param cls the RequestHandle
865 */
866static void
867options_cont (struct RestConnectionDataHandle *con_handle,
868 const char* url,
869 void *cls)
870{
871 struct MHD_Response *resp;
872 struct RequestHandle *handle = cls;
873
874 //For now, independent of path return all options
875 resp = GNUNET_REST_create_json_response (NULL);
876 MHD_add_response_header (resp,
877 "Access-Control-Allow-Methods",
878 allow_methods);
879 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
880 cleanup_handle (handle);
881 return;
882}
883
884/**
885 * Handle rest request
886 *
887 * @param handle the request handle
888 */
889static void
890init_cont (struct RequestHandle *handle)
891{
892 static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
893 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE, &issue_token_cont},
894 //{MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK, &check_token_cont},
895 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PROVIDER, &list_token_cont},
896 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER, &options_cont},
897 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN, &exchange_token_ticket_cont},
898 GNUNET_REST_HANDLER_END
899 };
900
901 if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
902 {
903 handle->emsg = GNUNET_strdup ("Request unsupported");
904 GNUNET_SCHEDULER_add_now (&do_error, handle);
905 }
906}
907
908/**
909 * If listing is enabled, prints information about the egos.
910 *
911 * This function is initially called for all egos and then again
912 * whenever a ego's identifier changes or if it is deleted. At the
913 * end of the initial pass over all egos, the function is once called
914 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
915 * be invoked in the future or that there was an error.
916 *
917 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
918 * this function is only called ONCE, and 'NULL' being passed in
919 * 'ego' does indicate an error (i.e. name is taken or no default
920 * value is known). If 'ego' is non-NULL and if '*ctx'
921 * is set in those callbacks, the value WILL be passed to a subsequent
922 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
923 * that one was not NULL).
924 *
925 * When an identity is renamed, this function is called with the
926 * (known) ego but the NEW identifier.
927 *
928 * When an identity is deleted, this function is called with the
929 * (known) ego and "NULL" for the 'identifier'. In this case,
930 * the 'ego' is henceforth invalid (and the 'ctx' should also be
931 * cleaned up).
932 *
933 * @param cls closure
934 * @param ego ego handle
935 * @param ctx context for application to store data for this ego
936 * (during the lifetime of this process, initially NULL)
937 * @param identifier identifier assigned by the user for this ego,
938 * NULL if the user just deleted the ego and it
939 * must thus no longer be used
940 */
941static void
942list_ego (void *cls,
943 struct GNUNET_IDENTITY_Ego *ego,
944 void **ctx,
945 const char *identifier)
946{
947 struct RequestHandle *handle = cls;
948 struct EgoEntry *ego_entry;
949 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
950
951 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
952 {
953 handle->state = ID_REST_STATE_POST_INIT;
954 init_cont (handle);
955 return;
956 }
957 if (ID_REST_STATE_INIT == handle->state) {
958 ego_entry = GNUNET_new (struct EgoEntry);
959 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
960 ego_entry->keystring =
961 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
962 ego_entry->ego = ego;
963 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
964 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
965 }
966
967}
968
969/**
970 * Function processing the REST call
971 *
972 * @param method HTTP method
973 * @param url URL of the HTTP request
974 * @param data body of the HTTP request (optional)
975 * @param data_size length of the body
976 * @param proc callback function for the result
977 * @param proc_cls closure for callback function
978 * @return GNUNET_OK if request accepted
979 */
980static void
981rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
982 GNUNET_REST_ResultProcessor proc,
983 void *proc_cls)
984{
985 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
986
987 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
988 handle->proc_cls = proc_cls;
989 handle->proc = proc;
990 handle->state = ID_REST_STATE_INIT;
991 handle->conndata_handle = conndata_handle;
992
993
994 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
995 if (handle->url[strlen (handle->url)-1] == '/')
996 handle->url[strlen (handle->url)-1] = '\0';
997 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
998 "Connecting...\n");
999 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1000 &list_ego,
1001 handle);
1002 handle->timeout_task =
1003 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1004 &do_error,
1005 handle);
1006
1007
1008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1009 "Connected\n");
1010}
1011
1012/**
1013 * Entry point for the plugin.
1014 *
1015 * @param cls Config info
1016 * @return NULL on error, otherwise the plugin context
1017 */
1018void *
1019libgnunet_plugin_rest_identity_token_init (void *cls)
1020{
1021 static struct Plugin plugin;
1022 struct GNUNET_REST_Plugin *api;
1023
1024 cfg = cls;
1025 if (NULL != plugin.cfg)
1026 return NULL; /* can only initialize once! */
1027 memset (&plugin, 0, sizeof (struct Plugin));
1028 plugin.cfg = cfg;
1029 api = GNUNET_new (struct GNUNET_REST_Plugin);
1030 api->cls = &plugin;
1031 api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1032 api->process_request = &rest_identity_process_request;
1033 GNUNET_asprintf (&allow_methods,
1034 "%s, %s, %s, %s, %s",
1035 MHD_HTTP_METHOD_GET,
1036 MHD_HTTP_METHOD_POST,
1037 MHD_HTTP_METHOD_PUT,
1038 MHD_HTTP_METHOD_DELETE,
1039 MHD_HTTP_METHOD_OPTIONS);
1040
1041 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1042 _("Identity Token REST API initialized\n"));
1043 return api;
1044}
1045
1046
1047/**
1048 * Exit point from the plugin.
1049 *
1050 * @param cls the plugin context (as returned by "init")
1051 * @return always NULL
1052 */
1053void *
1054libgnunet_plugin_rest_identity_token_done (void *cls)
1055{
1056 struct GNUNET_REST_Plugin *api = cls;
1057 struct Plugin *plugin = api->cls;
1058
1059 plugin->cfg = NULL;
1060 GNUNET_free_non_null (allow_methods);
1061 GNUNET_free (api);
1062 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1063 "Identity Token REST plugin is finished\n");
1064 return NULL;
1065}
1066
1067/* end of plugin_rest_gns.c */