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