GNUnet  0.11.x
plugin_rest_openid_connect.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2012-2018 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  */
27 #include "platform.h"
28 #include <inttypes.h>
29 #include <jansson.h>
30 
31 #include "gnunet_gns_service.h"
32 #include "gnunet_gnsrecord_lib.h"
36 #include "gnunet_reclaim_service.h"
37 #include "gnunet_rest_lib.h"
38 #include "gnunet_rest_plugin.h"
39 #include "gnunet_signatures.h"
40 #include "microhttpd.h"
41 #include "oidc_helper.h"
45 #define GNUNET_REST_API_NS_OIDC "/openid"
46 
50 #define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize"
51 
55 #define GNUNET_REST_API_NS_TOKEN "/openid/token"
56 
60 #define GNUNET_REST_API_NS_USERINFO "/openid/userinfo"
61 
65 #define GNUNET_REST_API_NS_LOGIN "/openid/login"
66 
70 #define ID_REST_STATE_INIT 0
71 
75 #define ID_REST_STATE_POST_INIT 1
76 
80 #define OIDC_GRANT_TYPE_KEY "grant_type"
81 
85 #define OIDC_GRANT_TYPE_VALUE "authorization_code"
86 
90 #define OIDC_CODE_KEY "code"
91 
95 #define OIDC_RESPONSE_TYPE_KEY "response_type"
96 
100 #define OIDC_CLIENT_ID_KEY "client_id"
101 
105 #define OIDC_SCOPE_KEY "scope"
106 
110 #define OIDC_REDIRECT_URI_KEY "redirect_uri"
111 
115 #define OIDC_STATE_KEY "state"
116 
120 #define OIDC_NONCE_KEY "nonce"
121 
125 #define OIDC_CLAIMS_KEY "claims"
126 
130 #define OIDC_CODE_CHALLENGE_KEY "code_challenge"
131 
135 #define OIDC_CODE_VERIFIER_KEY "code_verifier"
136 
140 #define OIDC_COOKIE_EXPIRATION 3
141 
145 #define OIDC_COOKIE_HEADER_KEY "cookie"
146 
150 #define OIDC_AUTHORIZATION_HEADER_KEY "authorization"
151 
155 #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
156 
160 #define OIDC_COOKIE_HEADER_ACCESS_DENIED "Identity=Denied"
161 
165 #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
166 
170 #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
171 
175 #define OIDC_ERROR_KEY_INVALID_CLIENT "invalid_client"
176 
180 #define OIDC_ERROR_KEY_INVALID_SCOPE "invalid_scope"
181 
185 #define OIDC_ERROR_KEY_INVALID_REQUEST "invalid_request"
186 
190 #define OIDC_ERROR_KEY_INVALID_TOKEN "invalid_token"
191 
195 #define OIDC_ERROR_KEY_INVALID_COOKIE "invalid_cookie"
196 
200 #define OIDC_ERROR_KEY_SERVER_ERROR "server_error"
201 
205 #define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE "unsupported_grant_type"
206 
210 #define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE "unsupported_response_type"
211 
215 #define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT "unauthorized_client"
216 
220 #define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied"
221 
222 
226 static char *OIDC_ignored_parameter_array[] = { "display",
227  "prompt",
228  "ui_locales",
229  "response_mode",
230  "id_token_hint",
231  "login_hint",
232  "acr_values" };
233 
238 
244 
249 
253 static char *allow_methods;
254 
258 struct Plugin
259 {
260  const struct GNUNET_CONFIGURATION_Handle *cfg;
261 };
262 
267 {
271  struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
272 
276  char *client_id;
277 
282 
286  char *scope;
287 
291  char *state;
292 
296  char *nonce;
297 
301  char *claims;
302 
307 
312 
317 
322 
327 
331  json_t *response;
332 };
333 
337 struct EgoEntry
338 {
342  struct EgoEntry *next;
343 
347  struct EgoEntry *prev;
348 
352  char *identifier;
353 
357  char *keystring;
358 
362  struct GNUNET_IDENTITY_Ego *ego;
363 };
364 
365 
366 struct RequestHandle
367 {
371  struct EgoEntry *ego_head;
372 
376  struct EgoEntry *ego_tail;
377 
381  struct EgoEntry *ego_entry;
382 
387 
392 
396  int state;
397 
402 
406  struct GNUNET_REST_RequestHandle *rest_handle;
407 
412 
417 
422 
427 
432 
437 
442 
447 
452 
457 
462 
467 
472 
477 
481  void *proc_cls;
482 
486  char *url;
487 
491  char *tld;
492 
497 
502 
506  char *emsg;
507 
511  char *edesc;
512 
516  int response_code;
517 };
518 
523 static void
525 {
526  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry;
527  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
528  struct EgoEntry *ego_entry;
529  struct EgoEntry *ego_tmp;
530 
531  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
532  if (NULL != handle->timeout_task)
534  if (NULL != handle->identity_handle)
536  if (NULL != handle->attr_it)
538  if (NULL != handle->ticket_it)
540  if (NULL != handle->idp)
541  GNUNET_RECLAIM_disconnect (handle->idp);
542  GNUNET_free_non_null (handle->url);
543  GNUNET_free_non_null (handle->tld);
546  GNUNET_free_non_null (handle->emsg);
547  GNUNET_free_non_null (handle->edesc);
548  if (NULL != handle->gns_op)
550  if (NULL != handle->gns_handle)
552 
553  if (NULL != handle->namestore_handle)
555  if (NULL != handle->oidc)
556  {
559  GNUNET_free_non_null (handle->oidc->nonce);
562  GNUNET_free_non_null (handle->oidc->scope);
563  GNUNET_free_non_null (handle->oidc->state);
564  json_decref (handle->oidc->response);
565  GNUNET_free (handle->oidc);
566  }
567  if (NULL != handle->attr_list)
568  {
569  for (claim_entry = handle->attr_list->list_head; NULL != claim_entry;)
570  {
571  claim_tmp = claim_entry;
572  claim_entry = claim_entry->next;
573  if (NULL != claim_tmp->claim)
574  GNUNET_free (claim_tmp->claim);
575  if (NULL != claim_tmp->attest)
576  GNUNET_free (claim_tmp->attest);
577  if (NULL != claim_tmp->reference)
578  GNUNET_free (claim_tmp->reference);
579  GNUNET_free (claim_tmp);
580  }
581  GNUNET_free (handle->attr_list);
582  }
583  for (ego_entry = handle->ego_head; NULL != ego_entry;)
584  {
585  ego_tmp = ego_entry;
586  ego_entry = ego_entry->next;
587  GNUNET_free (ego_tmp->identifier);
588  GNUNET_free (ego_tmp->keystring);
589  GNUNET_free (ego_tmp);
590  }
591  GNUNET_free (handle);
592 }
593 
594 
595 static void
597 {
598  cleanup_handle (cls);
599 }
600 
601 
607 static void
608 do_error (void *cls)
609 {
610  struct RequestHandle *handle = cls;
611  struct MHD_Response *resp;
612  char *json_error;
613 
614  GNUNET_asprintf (&json_error,
615  "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
616  handle->emsg,
617  (NULL != handle->edesc) ? handle->edesc : "",
618  (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
619  (NULL != handle->oidc->state) ? handle->oidc->state : "",
620  (NULL != handle->oidc->state) ? "\"" : "");
621  if (0 == handle->response_code)
622  handle->response_code = MHD_HTTP_BAD_REQUEST;
623  resp = GNUNET_REST_create_response (json_error);
624  if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
625  MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Basic");
626  MHD_add_response_header (resp,
627  MHD_HTTP_HEADER_CONTENT_TYPE,
628  "application/json");
629  handle->proc (handle->proc_cls, resp, handle->response_code);
631  GNUNET_free (json_error);
632 }
633 
634 
641 static void
642 do_userinfo_error (void *cls)
643 {
644  struct RequestHandle *handle = cls;
645  struct MHD_Response *resp;
646  char *error;
647 
648  GNUNET_asprintf (&error,
649  "error=\"%s\", error_description=\"%s\"",
650  handle->emsg,
651  (NULL != handle->edesc) ? handle->edesc : "");
652  resp = GNUNET_REST_create_response ("");
653  MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Bearer");
654  handle->proc (handle->proc_cls, resp, handle->response_code);
656  GNUNET_free (error);
657 }
658 
659 
665 static void
666 do_redirect_error (void *cls)
667 {
668  struct RequestHandle *handle = cls;
669  struct MHD_Response *resp;
670  char *redirect;
671 
672  GNUNET_asprintf (&redirect,
673  "%s?error=%s&error_description=%s%s%s",
674  handle->oidc->redirect_uri,
675  handle->emsg,
676  handle->edesc,
677  (NULL != handle->oidc->state) ? "&state=" : "",
678  (NULL != handle->oidc->state) ? handle->oidc->state : "");
679  resp = GNUNET_REST_create_response ("");
680  MHD_add_response_header (resp, "Location", redirect);
681  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
683  GNUNET_free (redirect);
684 }
685 
686 
692 static void
693 do_timeout (void *cls)
694 {
695  struct RequestHandle *handle = cls;
696 
697  handle->timeout_task = NULL;
698  do_error (handle);
699 }
700 
701 
707 static void
709 {
710  char *result_str;
711  struct RequestHandle *handle = cls;
712  struct MHD_Response *resp;
713 
714  result_str = json_dumps (handle->oidc->response, 0);
715  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"ID-Token: %s\n",result_str);
716  resp = GNUNET_REST_create_response (result_str);
717  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
718  GNUNET_free (result_str);
719  cleanup_handle (handle);
720 }
721 
722 
730 static void
732  const char *url,
733  void *cls)
734 {
735  struct MHD_Response *resp;
736  struct RequestHandle *handle = cls;
737 
738  // For now, independent of path return all options
739  resp = GNUNET_REST_create_response (NULL);
740  MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
741  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
742  cleanup_handle (handle);
743  return;
744 }
745 
746 
750 static void
752 {
753  struct GNUNET_HashCode cache_key;
754  char *cookies;
755  struct GNUNET_TIME_Absolute current_time, *relog_time;
756  char delimiter[] = "; ";
757  char *tmp_cookies;
758  char *token;
759  char *value;
760 
761  // gets identity of login try with cookie
763  strlen (OIDC_COOKIE_HEADER_KEY),
764  &cache_key);
767  &cache_key))
768  {
769  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cookie found\n");
770  return;
771  }
772  // splits cookies and find 'Identity' cookie
773  tmp_cookies =
775  &cache_key);
776  cookies = GNUNET_strdup (tmp_cookies);
777  token = strtok (cookies, delimiter);
778  handle->oidc->user_cancelled = GNUNET_NO;
779  handle->oidc->login_identity = NULL;
780  if (NULL == token)
781  {
783  "Unable to parse cookie: %s\n",
784  cookies);
785  GNUNET_free (cookies);
786  return;
787  }
788 
789  while (NULL != token)
790  {
791  if (0 == strcmp (token, OIDC_COOKIE_HEADER_ACCESS_DENIED))
792  {
793  handle->oidc->user_cancelled = GNUNET_YES;
794  GNUNET_free (cookies);
795  return;
796  }
797  if (NULL != strstr (token, OIDC_COOKIE_HEADER_INFORMATION_KEY))
798  break;
799  token = strtok (NULL, delimiter);
800  }
801  if (NULL == token)
802  {
804  "No cookie value to process: %s\n",
805  cookies);
806  GNUNET_free (cookies);
807  return;
808  }
809  GNUNET_CRYPTO_hash (token, strlen (token), &cache_key);
810  if (GNUNET_NO ==
811  GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
812  {
813  GNUNET_log (
815  "Found cookie `%s', but no corresponding expiration entry present...\n",
816  token);
817  GNUNET_free (cookies);
818  return;
819  }
820  relog_time =
821  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
822  current_time = GNUNET_TIME_absolute_get ();
823  // 30 min after old login -> redirect to login
824  if (current_time.abs_value_us > relog_time->abs_value_us)
825  {
827  "Found cookie `%s', but it is expired.\n",
828  token);
829  GNUNET_free (cookies);
830  return;
831  }
832  value = strtok (token, OIDC_COOKIE_HEADER_INFORMATION_KEY);
833  GNUNET_assert (NULL != value);
834  handle->oidc->login_identity = GNUNET_strdup (value);
835  GNUNET_free (cookies);
836 }
837 
838 
842 static void
843 login_redirect (void *cls)
844 {
845  char *login_base_url;
846  char *new_redirect;
847  struct MHD_Response *resp;
848  struct RequestHandle *handle = cls;
849 
851  "reclaim-rest-plugin",
852  "address",
853  &login_base_url))
854  {
855  GNUNET_asprintf (&new_redirect,
856  "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
857  login_base_url,
859  handle->oidc->response_type,
861  handle->oidc->client_id,
863  handle->oidc->redirect_uri,
865  handle->oidc->scope,
867  (NULL != handle->oidc->state) ? handle->oidc->state : "",
869  (NULL != handle->oidc->code_challenge) ?
870  handle->oidc->code_challenge : "",
872  (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "",
874  (NULL != handle->oidc->claims) ? handle->oidc->claims :
875  "");
876  resp = GNUNET_REST_create_response ("");
877  MHD_add_response_header (resp, "Location", new_redirect);
878  GNUNET_free (login_base_url);
879  }
880  else
881  {
883  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
884  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
886  return;
887  }
888  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
889  GNUNET_free (new_redirect);
891 }
892 
893 
897 static void
899 {
900  struct RequestHandle *handle = cls;
901 
903  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
905 }
906 
907 
912 static void
914 {
915  struct RequestHandle *handle = cls;
916  struct MHD_Response *resp;
917  char *ticket_str;
918  char *redirect_uri;
919  char *code_string;
920 
921  handle->idp_op = NULL;
922  if (NULL == ticket)
923  {
925  handle->edesc = GNUNET_strdup ("Server cannot generate ticket.");
927  return;
928  }
929  handle->ticket = *ticket;
930  ticket_str =
932  sizeof(struct GNUNET_RECLAIM_Ticket));
933  // TODO change if more attributes are needed (see max_age)
934  code_string = OIDC_build_authz_code (&handle->priv_key,
935  &handle->ticket,
936  handle->attr_list,
937  handle->oidc->nonce,
938  handle->oidc->code_challenge);
939  if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
940  (NULL != handle->tld))
941  {
942  GNUNET_asprintf (&redirect_uri,
943  "%s.%s/%s?%s=%s&state=%s",
944  handle->redirect_prefix,
945  handle->tld,
946  handle->redirect_suffix,
947  handle->oidc->response_type,
948  code_string,
949  handle->oidc->state);
950  }
951  else
952  {
953  GNUNET_asprintf (&redirect_uri,
954  "%s?%s=%s&state=%s",
955  handle->oidc->redirect_uri,
956  handle->oidc->response_type,
957  code_string,
958  handle->oidc->state);
959  }
960  resp = GNUNET_REST_create_response ("");
961  MHD_add_response_header (resp, "Location", redirect_uri);
962  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
964  GNUNET_free (redirect_uri);
965  GNUNET_free (ticket_str);
966  GNUNET_free (code_string);
967 }
968 
969 
970 static void
972 {
973  struct RequestHandle *handle = cls;
974 
975  handle->attr_it = NULL;
976  handle->ticket_it = NULL;
977  if (NULL == handle->attr_list->list_head)
978  {
980  handle->edesc = GNUNET_strdup ("The requested scope is not available.");
982  return;
983  }
984  handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp,
985  &handle->priv_key,
986  &handle->oidc->client_pkey,
987  handle->attr_list,
989  handle);
990 }
991 
992 
996 static void
997 oidc_attr_collect (void *cls,
999  const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
1000  const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest,
1001  const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference)
1002 {
1003  struct RequestHandle *handle = cls;
1005  char *scope_variables;
1006  char *scope_variable;
1007  char delimiter[] = " ";
1008 
1009  if ((NULL == attr) && (NULL == reference))
1010  {
1012  return;
1013  }
1014  if (NULL != reference)
1015  {
1016  if ((NULL == reference->name) || (NULL == reference->reference_value))
1017  {
1018  return;
1019  }
1020  scope_variables = GNUNET_strdup (handle->oidc->scope);
1021  scope_variable = strtok (scope_variables, delimiter);
1022  while (NULL != scope_variable)
1023  {
1024  if (0 == strcmp (reference->name, scope_variable))
1025  break;
1026  scope_variable = strtok (NULL, delimiter);
1027  }
1028  if (NULL == scope_variable)
1029  {
1030  GNUNET_free (scope_variables);
1031  return;
1032  }
1033  GNUNET_free (scope_variables);
1037  le->claim = NULL;
1038  le->reference = NULL;
1040  attest->type,
1041  attest->data,
1042  attest->data_size);
1043  le->attest->id = attest->id;
1044  le2->attest = NULL;
1045  le2->claim = NULL;
1047  reference->
1048  reference_value);
1049  le2->reference->id = reference->id;
1050  le2->reference->id_attest = reference->id_attest;
1052  handle->attr_list->list_tail,
1053  le);
1055  handle->attr_list->list_tail,
1056  le2);
1057  }
1058  else if (NULL != attr)
1059  {
1060  if ((NULL == attr->name) || (NULL == attr->data))
1061  {
1063  return;
1064  }
1065  scope_variables = GNUNET_strdup (handle->oidc->scope);
1066  scope_variable = strtok (scope_variables, delimiter);
1067  while (NULL != scope_variable)
1068  {
1069  if (0 == strcmp (attr->name, scope_variable))
1070  break;
1071  scope_variable = strtok (NULL, delimiter);
1072  }
1073  if (NULL == scope_variable)
1074  {
1076  GNUNET_free (scope_variables);
1077  return;
1078  }
1079  GNUNET_free (scope_variables);
1081  le->reference = NULL;
1082  le->attest = NULL;
1084  attr->type,
1085  attr->data,
1086  attr->data_size);
1087  le->claim->id = attr->id;
1088  le->claim->flag = attr->flag;
1089 
1091  handle->attr_list->list_tail,
1092  le);
1094  }
1095 }
1096 
1097 
1101 static void
1102 code_redirect (void *cls)
1103 {
1104  struct RequestHandle *handle = cls;
1105  struct GNUNET_TIME_Absolute current_time;
1106  struct GNUNET_TIME_Absolute *relog_time;
1107  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
1108  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pkey;
1109  struct GNUNET_HashCode cache_key;
1110  char *identity_cookie;
1111 
1112  GNUNET_asprintf (&identity_cookie,
1113  "Identity=%s",
1114  handle->oidc->login_identity);
1115  GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1116  GNUNET_free (identity_cookie);
1117  // No login time for identity -> redirect to login
1118  if (GNUNET_YES ==
1119  GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
1120  {
1121  relog_time =
1122  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
1123  current_time = GNUNET_TIME_absolute_get ();
1124  // 30 min after old login -> redirect to login
1125  if (current_time.abs_value_us <= relog_time->abs_value_us)
1126  {
1127  if (GNUNET_OK !=
1129  ->login_identity,
1130  strlen (
1131  handle->oidc
1132  ->login_identity),
1133  &pubkey))
1134  {
1136  handle->edesc =
1137  GNUNET_strdup ("The cookie of a login identity is not valid");
1139  return;
1140  }
1141  // iterate over egos and compare their public key
1142  for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
1143  handle->ego_entry = handle->ego_entry->next)
1144  {
1145  GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1146  if (0 == GNUNET_memcmp (&ego_pkey, &pubkey))
1147  {
1148  handle->priv_key =
1150  handle->idp = GNUNET_RECLAIM_connect (cfg);
1151  handle->attr_list =
1153  handle->attr_it =
1155  &handle->priv_key,
1157  handle,
1159  handle,
1161  handle);
1162  return;
1163  }
1164  }
1166  return;
1167  }
1168  }
1169 }
1170 
1171 
1172 static void
1173 build_redirect (void *cls)
1174 {
1175  struct RequestHandle *handle = cls;
1176  struct MHD_Response *resp;
1177  char *redirect_uri;
1178 
1179  if (GNUNET_YES == handle->oidc->user_cancelled)
1180  {
1181  if ((NULL != handle->redirect_prefix) &&
1182  (NULL != handle->redirect_suffix) && (NULL != handle->tld))
1183  {
1184  GNUNET_asprintf (&redirect_uri,
1185  "%s.%s/%s?error=%s&error_description=%s&state=%s",
1186  handle->redirect_prefix,
1187  handle->tld,
1188  handle->redirect_suffix,
1189  "access_denied",
1190  "User denied access",
1191  handle->oidc->state);
1192  }
1193  else
1194  {
1195  GNUNET_asprintf (&redirect_uri,
1196  "%s?error=%s&error_description=%s&state=%s",
1197  handle->oidc->redirect_uri,
1198  "access_denied",
1199  "User denied access",
1200  handle->oidc->state);
1201  }
1202  resp = GNUNET_REST_create_response ("");
1203  MHD_add_response_header (resp, "Location", redirect_uri);
1204  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1206  GNUNET_free (redirect_uri);
1207  return;
1208  }
1210 }
1211 
1212 
1213 static void
1215  uint32_t rd_count,
1216  const struct GNUNET_GNSRECORD_Data *rd)
1217 {
1218  struct RequestHandle *handle = cls;
1219  char *tmp;
1220  char *tmp_key_str;
1221  char *pos;
1222  struct GNUNET_CRYPTO_EcdsaPublicKey redirect_zone;
1223 
1224  handle->gns_op = NULL;
1225  if (0 == rd_count)
1226  {
1228  handle->edesc =
1229  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1231  return;
1232  }
1233  for (int i = 0; i < rd_count; i++)
1234  {
1235  if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type)
1236  continue;
1237  if (0 != strncmp (rd[i].data, handle->oidc->redirect_uri, rd[i].data_size))
1238  continue;
1239  tmp = GNUNET_strndup (rd[i].data, rd[i].data_size);
1240  if (NULL == strstr (tmp, handle->oidc->client_id))
1241  {
1243  "Redirect uri %s does not contain client_id %s\n",
1244  tmp,
1245  handle->oidc->client_id);
1246  }
1247  else
1248  {
1249  pos = strrchr (tmp, (unsigned char) '.');
1250  if (NULL == pos)
1251  {
1253  "Redirect uri %s contains client_id but is malformed\n",
1254  tmp);
1255  GNUNET_free (tmp);
1256  continue;
1257  }
1258  *pos = '\0';
1259  handle->redirect_prefix = GNUNET_strdup (tmp);
1260  tmp_key_str = pos + 1;
1261  pos = strchr (tmp_key_str, (unsigned char) '/');
1262  if (NULL == pos)
1263  {
1265  "Redirect uri %s contains client_id but is malformed\n",
1266  tmp);
1267  GNUNET_free (tmp);
1268  continue;
1269  }
1270  *pos = '\0';
1271  handle->redirect_suffix = GNUNET_strdup (pos + 1);
1272 
1273  GNUNET_STRINGS_string_to_data (tmp_key_str,
1274  strlen (tmp_key_str),
1275  &redirect_zone,
1276  sizeof(redirect_zone));
1277  }
1279  GNUNET_free (tmp);
1280  return;
1281  }
1283  handle->edesc =
1284  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1286 }
1287 
1288 
1292 static void
1293 client_redirect (void *cls)
1294 {
1295  struct RequestHandle *handle = cls;
1296 
1297  /* Lookup client redirect uri to verify request */
1298  handle->gns_op =
1299  GNUNET_GNS_lookup (handle->gns_handle,
1301  &handle->oidc->client_pkey,
1305  handle);
1306 }
1307 
1308 
1309 static char *
1310 get_url_parameter_copy (const struct RequestHandle *handle, const char *key)
1311 {
1312  struct GNUNET_HashCode hc;
1313  char *value;
1314 
1315  GNUNET_CRYPTO_hash (key, strlen (key), &hc);
1317  ->url_param_map,
1318  &hc))
1319  return NULL;
1320  value =
1322  if (NULL == value)
1323  return NULL;
1324  return GNUNET_strdup (value);
1325 }
1326 
1327 
1334 static void
1336 {
1337  struct RequestHandle *handle = cls;
1338  struct GNUNET_HashCode cache_key;
1339 
1340  char *expected_scope;
1341  char delimiter[] = " ";
1342  int number_of_ignored_parameter, iterator;
1343 
1344 
1345  // REQUIRED value: redirect_uri
1346  handle->oidc->redirect_uri =
1348  if (NULL == handle->oidc->redirect_uri)
1349  {
1351  handle->edesc = GNUNET_strdup ("missing parameter redirect_uri");
1353  return;
1354  }
1355 
1356  // REQUIRED value: response_type
1357  handle->oidc->response_type =
1359  if (NULL == handle->oidc->response_type)
1360  {
1362  handle->edesc = GNUNET_strdup ("missing parameter response_type");
1364  return;
1365  }
1366 
1367  // REQUIRED value: scope
1368  handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
1369  if (NULL == handle->oidc->scope)
1370  {
1372  handle->edesc = GNUNET_strdup ("missing parameter scope");
1374  return;
1375  }
1376 
1377  // OPTIONAL value: nonce
1378  handle->oidc->nonce = get_url_parameter_copy (handle, OIDC_NONCE_KEY);
1379 
1380  // OPTIONAL value: claims
1381  handle->oidc->claims = get_url_parameter_copy (handle, OIDC_CLAIMS_KEY);
1382 
1383  // TODO check other values if needed
1384  number_of_ignored_parameter =
1385  sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1386  for (iterator = 0; iterator < number_of_ignored_parameter; iterator++)
1387  {
1389  strlen (OIDC_ignored_parameter_array[iterator]),
1390  &cache_key);
1391  if (GNUNET_YES ==
1393  ->url_param_map,
1394  &cache_key))
1395  {
1397  GNUNET_asprintf (&handle->edesc,
1398  "Server will not handle parameter: %s",
1399  OIDC_ignored_parameter_array[iterator]);
1401  return;
1402  }
1403  }
1404 
1405  // We only support authorization code flows.
1406  if (0 != strcmp (handle->oidc->response_type,
1408  {
1410  handle->edesc = GNUNET_strdup ("The authorization server does not support "
1411  "obtaining this authorization code.");
1413  return;
1414  }
1415 
1416  // Checks if scope contains 'openid'
1417  expected_scope = GNUNET_strdup (handle->oidc->scope);
1418  char *test;
1419  test = strtok (expected_scope, delimiter);
1420  while (NULL != test)
1421  {
1422  if (0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope))
1423  break;
1424  test = strtok (NULL, delimiter);
1425  }
1426  if (NULL == test)
1427  {
1429  handle->edesc =
1430  GNUNET_strdup ("The requested scope is invalid, unknown, or malformed.");
1432  GNUNET_free (expected_scope);
1433  return;
1434  }
1435 
1436  GNUNET_free (expected_scope);
1437  if ((NULL == handle->oidc->login_identity) &&
1438  (GNUNET_NO == handle->oidc->user_cancelled))
1440  else
1442 }
1443 
1444 
1448 static void
1449 tld_iter (void *cls, const char *section, const char *option, const char *value)
1450 {
1451  struct RequestHandle *handle = cls;
1452  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1453 
1454  if (GNUNET_OK !=
1455  GNUNET_CRYPTO_ecdsa_public_key_from_string (value, strlen (value), &pkey))
1456  {
1457  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping non key %s\n", value);
1458  return;
1459  }
1460  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1461  handle->tld = GNUNET_strdup (option + 1);
1462 }
1463 
1464 
1472 static void
1474  const char *url,
1475  void *cls)
1476 {
1477  struct RequestHandle *handle = cls;
1478  struct EgoEntry *tmp_ego;
1479  const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1480  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1481 
1483 
1484  // RECOMMENDED value: state - REQUIRED for answers
1485  handle->oidc->state = get_url_parameter_copy (handle, OIDC_STATE_KEY);
1486 
1487  // REQUIRED value: client_id
1489  if (NULL == handle->oidc->client_id)
1490  {
1492  handle->edesc = GNUNET_strdup ("missing parameter client_id");
1493  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1495  return;
1496  }
1497 
1498  // OPTIONAL value: code_challenge
1499  handle->oidc->code_challenge = get_url_parameter_copy (handle,
1501  if (NULL == handle->oidc->code_challenge)
1502  {
1504  "OAuth authorization request does not contain PKCE parameters!\n");
1505  }
1506 
1507  if (GNUNET_OK !=
1509  strlen (
1510  handle->oidc->client_id),
1511  &handle->oidc->client_pkey))
1512  {
1514  handle->edesc = GNUNET_strdup ("The client is not authorized to request an "
1515  "authorization code using this method.");
1516  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1518  return;
1519  }
1520 
1521  // If we know this identity, translated the corresponding TLD
1522  // TODO: We might want to have a reverse lookup functionality for TLDs?
1523  for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
1524  {
1525  priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
1526  GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, &pkey);
1527  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1528  {
1529  handle->tld = GNUNET_strdup (tmp_ego->identifier);
1530  handle->ego_entry = handle->ego_tail;
1531  }
1532  }
1533  handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
1535  handle->oidc->scope));
1536  if (NULL == handle->tld)
1538  if (NULL == handle->tld)
1539  handle->tld = GNUNET_strdup (handle->oidc->client_id);
1541 }
1542 
1543 
1551 static void
1553  const char *url,
1554  void *cls)
1555 {
1556  struct MHD_Response *resp = GNUNET_REST_create_response ("");
1557  struct RequestHandle *handle = cls;
1558  struct GNUNET_HashCode cache_key;
1559  struct GNUNET_TIME_Absolute *current_time;
1560  struct GNUNET_TIME_Absolute *last_time;
1561  char *cookie;
1562  char *header_val;
1563  json_t *root;
1564  json_error_t error;
1565  json_t *identity;
1566  char term_data[handle->rest_handle->data_size + 1];
1567 
1568  term_data[handle->rest_handle->data_size] = '\0';
1569  GNUNET_memcpy (term_data,
1570  handle->rest_handle->data,
1571  handle->rest_handle->data_size);
1572  root = json_loads (term_data, JSON_DECODE_ANY, &error);
1573  identity = json_object_get (root, "identity");
1574  if (! json_is_string (identity))
1575  {
1577  "Error parsing json string from %s\n",
1578  term_data);
1579  handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1580  json_decref (root);
1582  return;
1583  }
1584  GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1585  GNUNET_asprintf (&header_val,
1586  "%s;Max-Age=%d",
1587  cookie,
1589  MHD_add_response_header (resp, "Set-Cookie", header_val);
1590  MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST");
1591  GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1592 
1593  if (0 != strcmp (json_string_value (identity), "Denied"))
1594  {
1595  current_time = GNUNET_new (struct GNUNET_TIME_Absolute);
1596  *current_time = GNUNET_TIME_relative_to_absolute (
1599  last_time =
1600  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
1601  GNUNET_free_non_null (last_time);
1602  GNUNET_CONTAINER_multihashmap_put (OIDC_cookie_jar_map,
1603  &cache_key,
1604  current_time,
1606  }
1607  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1608  GNUNET_free (cookie);
1609  GNUNET_free (header_val);
1610  json_decref (root);
1612 }
1613 
1614 
1615 static int
1617  struct GNUNET_CRYPTO_EcdsaPublicKey *cid)
1618 {
1619  struct GNUNET_HashCode cache_key;
1620  char *authorization;
1621  char *credentials;
1622  char *basic_authorization;
1623  char *client_id;
1624  char *pass;
1625  char *expected_pass;
1626 
1629  &cache_key);
1631  ->header_param_map,
1632  &cache_key))
1633  {
1635  handle->edesc = GNUNET_strdup ("missing authorization");
1636  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1637  return GNUNET_SYSERR;
1638  }
1639  authorization =
1641  &cache_key);
1642 
1643  // split header in "Basic" and [content]
1644  credentials = strtok (authorization, " ");
1645  if ((NULL == credentials) || (0 != strcmp ("Basic", credentials)))
1646  {
1648  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1649  return GNUNET_SYSERR;
1650  }
1651  credentials = strtok (NULL, " ");
1652  if (NULL == credentials)
1653  {
1655  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1656  return GNUNET_SYSERR;
1657  }
1658  GNUNET_STRINGS_base64_decode (credentials,
1659  strlen (credentials),
1660  (void **) &basic_authorization);
1661 
1662  if (NULL == basic_authorization)
1663  {
1665  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1666  return GNUNET_SYSERR;
1667  }
1668  client_id = strtok (basic_authorization, ":");
1669  if (NULL == client_id)
1670  {
1671  GNUNET_free_non_null (basic_authorization);
1673  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1674  return GNUNET_SYSERR;
1675  }
1676  pass = strtok (NULL, ":");
1677  if (NULL == pass)
1678  {
1679  GNUNET_free_non_null (basic_authorization);
1681  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1682  return GNUNET_SYSERR;
1683  }
1684 
1685  // check client password
1687  "reclaim-rest-plugin",
1688  "OIDC_CLIENT_SECRET",
1689  &expected_pass))
1690  {
1691  if (0 != strcmp (expected_pass, pass))
1692  {
1693  GNUNET_free_non_null (basic_authorization);
1694  GNUNET_free (expected_pass);
1696  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1697  return GNUNET_SYSERR;
1698  }
1699  GNUNET_free (expected_pass);
1700  }
1701  else
1702  {
1703  GNUNET_free_non_null (basic_authorization);
1705  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1706  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1707  return GNUNET_SYSERR;
1708  }
1709 
1710  // check client_id
1711  for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
1712  handle->ego_entry = handle->ego_entry->next)
1713  {
1714  if (0 == strcmp (handle->ego_entry->keystring, client_id))
1715  break;
1716  }
1717  if (NULL == handle->ego_entry)
1718  {
1719  GNUNET_free_non_null (basic_authorization);
1721  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1722  return GNUNET_SYSERR;
1723  }
1724  GNUNET_STRINGS_string_to_data (client_id,
1725  strlen (client_id),
1726  cid,
1727  sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
1728 
1729  GNUNET_free (basic_authorization);
1730  return GNUNET_OK;
1731 }
1732 
1733 
1734 const struct EgoEntry *
1736  struct GNUNET_CRYPTO_EcdsaPublicKey *test_key)
1737 {
1738  struct EgoEntry *ego_entry;
1739  struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1740 
1741  for (ego_entry = handle->ego_head; NULL != ego_entry;
1742  ego_entry = ego_entry->next)
1743  {
1744  GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
1745  if (0 == GNUNET_memcmp (&pub_key, test_key))
1746  return ego_entry;
1747  }
1748  return NULL;
1749 }
1750 
1751 
1752 static void
1754  const char *access_token,
1755  const struct GNUNET_RECLAIM_Ticket *ticket)
1756 {
1757  struct GNUNET_HashCode hc;
1758  struct GNUNET_RECLAIM_Ticket *ticketbuf;
1759 
1760  GNUNET_CRYPTO_hash (access_token, strlen (access_token), &hc);
1761  ticketbuf = GNUNET_new (struct GNUNET_RECLAIM_Ticket);
1762  *ticketbuf = *ticket;
1765  OIDC_access_token_map,
1766  &hc,
1767  ticketbuf,
1769 }
1770 
1771 
1779 static void
1781  const char *url,
1782  void *cls)
1783 {
1784  struct RequestHandle *handle = cls;
1785  const struct EgoEntry *ego_entry;
1786  struct GNUNET_TIME_Relative expiration_time;
1788  struct GNUNET_RECLAIM_Ticket ticket;
1789  struct GNUNET_CRYPTO_EcdsaPublicKey cid;
1790  const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
1791  struct GNUNET_HashCode cache_key;
1792  struct MHD_Response *resp;
1793  char *grant_type;
1794  char *code;
1795  char *json_response;
1796  char *id_token;
1797  char *access_token;
1798  char *jwt_secret;
1799  char *nonce;
1800  char *code_verifier;
1801 
1802  /*
1803  * Check Authorization
1804  */
1805  if (GNUNET_SYSERR == check_authorization (handle, &cid))
1806  {
1808  "OIDC authorization for token endpoint failed\n");
1810  return;
1811  }
1812 
1813  /*
1814  * Check parameter
1815  */
1816 
1817  // TODO Do not allow multiple equal parameter names
1818  // REQUIRED grant_type
1820  strlen (OIDC_GRANT_TYPE_KEY),
1821  &cache_key);
1822  grant_type = get_url_parameter_copy (handle, OIDC_GRANT_TYPE_KEY);
1823  if (NULL == grant_type)
1824  {
1826  handle->edesc = GNUNET_strdup ("missing parameter grant_type");
1827  handle->response_code = MHD_HTTP_BAD_REQUEST;
1829  return;
1830  }
1831 
1832  // Check parameter grant_type == "authorization_code"
1833  if (0 != strcmp (OIDC_GRANT_TYPE_VALUE, grant_type))
1834  {
1836  handle->response_code = MHD_HTTP_BAD_REQUEST;
1837  GNUNET_free (grant_type);
1839  return;
1840  }
1841  GNUNET_free (grant_type);
1842  // REQUIRED code
1843  code = get_url_parameter_copy (handle, OIDC_CODE_KEY);
1844  if (NULL == code)
1845  {
1847  handle->edesc = GNUNET_strdup ("missing parameter code");
1848  handle->response_code = MHD_HTTP_BAD_REQUEST;
1850  return;
1851  }
1852  ego_entry = find_ego (handle, &cid);
1853  if (NULL == ego_entry)
1854  {
1856  handle->edesc = GNUNET_strdup ("Unknown client");
1857  handle->response_code = MHD_HTTP_BAD_REQUEST;
1858  GNUNET_free (code);
1860  return;
1861  }
1862  privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1863 
1864  // REQUIRED code verifier
1865  code_verifier = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY);
1866  if (NULL == code_verifier)
1867  {
1869  "OAuth authorization request does not contain PKCE parameters!\n");
1870 
1871  }
1872 
1873  // decode code
1874  if (GNUNET_OK != OIDC_parse_authz_code (privkey, code, code_verifier, &ticket,
1875  &cl, &nonce))
1876  {
1878  handle->edesc = GNUNET_strdup ("invalid code");
1879  handle->response_code = MHD_HTTP_BAD_REQUEST;
1880  GNUNET_free (code);
1882  return;
1883  }
1884  GNUNET_free (code);
1885 
1886  // create jwt
1888  "reclaim-rest-plugin",
1889  "expiration_time",
1890  &expiration_time))
1891  {
1893  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1894  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1896  return;
1897  }
1898 
1899 
1900  // TODO OPTIONAL acr,amr,azp
1902  "reclaim-rest-plugin",
1903  "jwt_secret",
1904  &jwt_secret))
1905  {
1907  handle->edesc = GNUNET_strdup ("No signing secret configured!");
1908  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1910  return;
1911  }
1912  id_token = OIDC_id_token_new (&ticket.audience,
1913  &ticket.identity,
1914  cl,
1915  &expiration_time,
1916  (NULL != nonce) ? nonce : NULL,
1917  jwt_secret);
1918  access_token = OIDC_access_token_new ();
1919  OIDC_build_token_response (access_token,
1920  id_token,
1921  &expiration_time,
1922  &json_response);
1923 
1924  persist_access_token (handle, access_token, &ticket);
1925  resp = GNUNET_REST_create_response (json_response);
1926  MHD_add_response_header (resp, "Cache-Control", "no-store");
1927  MHD_add_response_header (resp, "Pragma", "no-cache");
1928  MHD_add_response_header (resp, "Content-Type", "application/json");
1929  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1931  GNUNET_free (access_token);
1932  GNUNET_free (json_response);
1933  GNUNET_free (id_token);
1935 }
1936 
1937 
1941 static void
1942 consume_ticket (void *cls,
1943  const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1944  const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
1945  const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest,
1946  const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference)
1947 {
1948  struct RequestHandle *handle = cls;
1949  if (NULL == identity)
1950  {
1952  return;
1953  }
1954  if (NULL != attr)
1955  {
1956  char *tmp_value;
1957  json_t *value;
1959  attr->data,
1960  attr->data_size);
1961  value = json_string (tmp_value);
1962  json_object_set_new (handle->oidc->response, attr->name, value);
1963  GNUNET_free (tmp_value);
1964  }
1965  else if ((NULL != attest) && (NULL != reference))
1966  {
1967  json_t *claim_sources;
1968  json_t *claim_sources_jwt;
1969  json_t *claim_names;
1970  char *attest_val_str;
1971  claim_sources=json_object_get(handle->oidc->response,"_claim_sources");
1972  claim_names=json_object_get(handle->oidc->response,"_claim_names");
1973  attest_val_str = GNUNET_RECLAIM_ATTESTATION_value_to_string (attest->type,
1974  attest->data,
1975  attest->
1976  data_size);
1977  if ((NULL == claim_sources) && (NULL == claim_names) )
1978  {
1979  claim_sources = json_object ();
1980  claim_names = json_object ();
1981  }
1982  char *source_name;
1983  int i = 0;
1984  GNUNET_asprintf (&source_name,"src%d",i);
1985  while (NULL != (claim_sources_jwt = json_object_get (claim_sources,
1986  source_name)))
1987  {
1988  if (0 == strcmp (json_string_value (json_object_get (claim_sources_jwt,
1989  "JWT")),
1990  attest_val_str))
1991  {
1992  // Adapt only the claim names
1993  json_object_set_new (claim_names, reference->name, json_string (
1994  source_name));
1995  json_object_set (handle->oidc->response, "_claim_names",claim_names);
1996  handle->oidc->response = json_deep_copy(handle->oidc->response);
1997  break;
1998  }
1999  i++;
2000  GNUNET_asprintf (&source_name,"src%d",i);
2001  }
2002 
2003  // Create new one
2004  if (NULL == claim_sources_jwt)
2005  {
2006  claim_sources_jwt = json_object ();
2007  // Set the JWT for names
2008  json_object_set_new (claim_names, reference->name, json_string (
2009  source_name));
2010  // Set the JWT for the inner source
2011  json_object_set_new (claim_sources_jwt, "JWT", json_string (
2012  attest_val_str));
2013  // Set the JWT for the source
2014  json_object_set_new (claim_sources, source_name,claim_sources_jwt);
2015  // Set as claims
2016  json_object_set (handle->oidc->response, "_claim_names", claim_names);
2017  json_object_set (handle->oidc->response, "_claim_sources",claim_sources);
2018  handle->oidc->response = json_deep_copy(handle->oidc->response);
2019  }
2020 
2021  json_decref (claim_sources);
2022  json_decref (claim_names);
2023  json_decref (claim_sources_jwt);
2024  GNUNET_free (attest_val_str);
2025  }
2026  else
2027  {
2028  // REMARK: We should not find any claim, one of attest/ref is NULL
2029  }
2030 }
2031 
2032 
2040 static void
2042  const char *url,
2043  void *cls)
2044 {
2045  // TODO expiration time
2046  struct RequestHandle *handle = cls;
2047  char delimiter[] = " ";
2048  struct GNUNET_HashCode cache_key;
2049  char *authorization;
2050  char *authorization_type;
2051  char *authorization_access_token;
2052  struct GNUNET_RECLAIM_Ticket *ticket;
2053  const struct EgoEntry *ego_entry;
2054  const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
2055 
2058  &cache_key);
2060  ->header_param_map,
2061  &cache_key))
2062  {
2064  handle->edesc = GNUNET_strdup ("No Access Token");
2065  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2067  return;
2068  }
2069  authorization =
2071  &cache_key);
2072 
2073  // split header in "Bearer" and access_token
2074  authorization = GNUNET_strdup (authorization);
2075  authorization_type = strtok (authorization, delimiter);
2076  if ((NULL == authorization_type) ||
2077  (0 != strcmp ("Bearer", authorization_type)))
2078  {
2080  handle->edesc = GNUNET_strdup ("No Access Token");
2081  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2083  GNUNET_free (authorization);
2084  return;
2085  }
2086  authorization_access_token = strtok (NULL, delimiter);
2087  if (NULL == authorization_access_token)
2088  {
2090  handle->edesc = GNUNET_strdup ("Access token missing");
2091  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2093  GNUNET_free (authorization);
2094  return;
2095  }
2096 
2097  GNUNET_CRYPTO_hash (authorization_access_token,
2098  strlen (authorization_access_token),
2099  &cache_key);
2100  if (GNUNET_NO ==
2101  GNUNET_CONTAINER_multihashmap_contains (OIDC_access_token_map,
2102  &cache_key))
2103  {
2105  handle->edesc = GNUNET_strdup ("The access token expired");
2106  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2108  GNUNET_free (authorization);
2109  return;
2110  }
2111  ticket =
2112  GNUNET_CONTAINER_multihashmap_get (OIDC_access_token_map, &cache_key);
2113  GNUNET_assert (NULL != ticket);
2114  ego_entry = find_ego (handle, &ticket->audience);
2115  if (NULL == ego_entry)
2116  {
2118  handle->edesc = GNUNET_strdup ("The access token expired");
2119  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2121  GNUNET_free (authorization);
2122  return;
2123  }
2124 
2125  handle->idp = GNUNET_RECLAIM_connect (cfg);
2126  handle->oidc->response = json_object ();
2127  json_object_set_new (handle->oidc->response,
2128  "sub",
2129  json_string (ego_entry->keystring));
2130  privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
2131  handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
2132  privkey,
2133  ticket,
2135  handle);
2136  GNUNET_free (authorization);
2137 }
2138 
2139 
2145 static void
2147 {
2149  static const struct GNUNET_REST_RequestHandler handlers[] =
2150  { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint },
2151  { MHD_HTTP_METHOD_POST,
2153  &authorize_endpoint }, // url-encoded
2154  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont },
2155  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
2156  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2157  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2158  { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, &options_cont },
2160 
2161  if (GNUNET_NO ==
2162  GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
2163  {
2164  handle->response_code = err.error_code;
2166  }
2167 }
2168 
2169 
2203 static void
2204 list_ego (void *cls,
2205  struct GNUNET_IDENTITY_Ego *ego,
2206  void **ctx,
2207  const char *identifier)
2208 {
2209  struct RequestHandle *handle = cls;
2210  struct EgoEntry *ego_entry;
2211  struct GNUNET_CRYPTO_EcdsaPublicKey pk;
2212 
2213  if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
2214  {
2215  handle->state = ID_REST_STATE_POST_INIT;
2216  init_cont (handle);
2217  return;
2218  }
2219  GNUNET_assert (NULL != ego);
2220  if (ID_REST_STATE_INIT == handle->state)
2221 
2222  {
2223  ego_entry = GNUNET_new (struct EgoEntry);
2226  ego_entry->ego = ego;
2227  ego_entry->identifier = GNUNET_strdup (identifier);
2229  handle->ego_tail,
2230  ego_entry);
2231  return;
2232  }
2233  /* Ego renamed or added */
2234  if (identifier != NULL)
2235  {
2236  for (ego_entry = handle->ego_head; NULL != ego_entry;
2237  ego_entry = ego_entry->next)
2238  {
2239  if (ego_entry->ego == ego)
2240  {
2241  /* Rename */
2242  GNUNET_free (ego_entry->identifier);
2243  ego_entry->identifier = GNUNET_strdup (identifier);
2244  break;
2245  }
2246  }
2247  if (NULL == ego_entry)
2248  {
2249  /* Add */
2250  ego_entry = GNUNET_new (struct EgoEntry);
2253  ego_entry->ego = ego;
2254  ego_entry->identifier = GNUNET_strdup (identifier);
2256  handle->ego_tail,
2257  ego_entry);
2258  }
2259  }
2260  else
2261  {
2262  /* Delete */
2263  for (ego_entry = handle->ego_head; NULL != ego_entry;
2264  ego_entry = ego_entry->next)
2265  {
2266  if (ego_entry->ego == ego)
2267  break;
2268  }
2269  if (NULL != ego_entry)
2271  handle->ego_tail,
2272  ego_entry);
2273  }
2274 }
2275 
2276 
2277 static void
2280  void *proc_cls)
2281 {
2282  struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
2283 
2284  handle->oidc = GNUNET_new (struct OIDC_Variables);
2285  if (NULL == OIDC_cookie_jar_map)
2286  OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2287  if (NULL == OIDC_access_token_map)
2288  OIDC_access_token_map =
2290  handle->response_code = 0;
2292  handle->proc_cls = proc_cls;
2293  handle->proc = proc;
2294  handle->state = ID_REST_STATE_INIT;
2295  handle->rest_handle = rest_handle;
2296 
2297  handle->url = GNUNET_strdup (rest_handle->url);
2298  if (handle->url[strlen (handle->url) - 1] == '/')
2299  handle->url[strlen (handle->url) - 1] = '\0';
2300  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
2301  handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
2302  handle->gns_handle = GNUNET_GNS_connect (cfg);
2304  handle->timeout_task =
2305  GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
2306  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
2307 }
2308 
2309 
2316 void *
2318 {
2319  static struct Plugin plugin;
2320  struct GNUNET_REST_Plugin *api;
2321 
2322  cfg = cls;
2323  if (NULL != plugin.cfg)
2324  return NULL; /* can only initialize once! */
2325  memset (&plugin, 0, sizeof(struct Plugin));
2326  plugin.cfg = cfg;
2327  api = GNUNET_new (struct GNUNET_REST_Plugin);
2328  api->cls = &plugin;
2332  "%s, %s, %s, %s, %s",
2333  MHD_HTTP_METHOD_GET,
2334  MHD_HTTP_METHOD_POST,
2335  MHD_HTTP_METHOD_PUT,
2336  MHD_HTTP_METHOD_DELETE,
2337  MHD_HTTP_METHOD_OPTIONS);
2338 
2340  _ ("OpenID Connect REST API initialized\n"));
2341  return api;
2342 }
2343 
2344 
2351 void *
2353 {
2354  struct GNUNET_REST_Plugin *api = cls;
2355  struct Plugin *plugin = api->cls;
2356 
2357  plugin->cfg = NULL;
2358 
2359  struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2360  void *value = NULL;
2361  hashmap_it =
2362  GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_cookie_jar_map);
2363  while (GNUNET_YES ==
2364  GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2365  GNUNET_free_non_null (value);
2367  GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map);
2368 
2369  hashmap_it =
2370  GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_access_token_map);
2371  while (GNUNET_YES ==
2372  GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2373  GNUNET_free_non_null (value);
2374  GNUNET_CONTAINER_multihashmap_destroy (OIDC_access_token_map);
2377  GNUNET_free (api);
2379  "OpenID Connect REST plugin is finished\n");
2380  return NULL;
2381 }
2382 
2383 
2384 /* end of plugin_rest_openid_connect.c */
struct GNUNET_IDENTITY_Handle * GNUNET_IDENTITY_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_IDENTITY_Callback cb, void *cb_cls)
Connect to the identity service.
Definition: identity_api.c:527
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static void build_redirect(void *cls)
static int iterator(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Iterator over hash map entries.
const char * name
The name of the attribute.
struct GNUNET_RECLAIM_ATTRIBUTE_Claim * claim
The attribute claim.
Connection to the GNS service.
Definition: gns_api.h:35
struct GNUNET_RECLAIM_ATTESTATION_Claim * GNUNET_RECLAIM_ATTESTATION_claim_new(const char *attr_name, uint32_t type, const void *data, size_t data_size)
Create a new attestation.
void GNUNET_CONTAINER_multihashmap_iterator_destroy(struct GNUNET_CONTAINER_MultiHashMapIterator *iter)
Destroy a multihashmap iterator.
char * GNUNET_RECLAIM_ATTRIBUTE_value_to_string(uint32_t type, const void *data, size_t data_size)
Convert the &#39;claim&#39; of an attribute to a string.
char * redirect_uri
The OIDC redirect uri.
char * scope
The list of oidc scopes.
Handle to the service.
Definition: reclaim_api.c:235
The authorization ticket.
#define OIDC_NONCE_KEY
OIDC nonce key.
void(* GNUNET_REST_ResultProcessor)(void *cls, struct MHD_Response *resp, int status)
Iterator called on obtained result for a REST result.
int GNUNET_CONTAINER_multihashmap_iterator_next(struct GNUNET_CONTAINER_MultiHashMapIterator *iter, struct GNUNET_HashCode *key, const void **value)
Retrieve the next element from the hash map at the iterator&#39;s position.
#define OIDC_CODE_CHALLENGE_KEY
OIDC PKCE code challenge.
struct GNUNET_RECLAIM_AttributeIterator * GNUNET_RECLAIM_get_attributes_start(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls, GNUNET_RECLAIM_AttributeResult proc, void *proc_cls, GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls)
List all attributes for a local identity.
Definition: reclaim_api.c:1358
int GNUNET_CONFIGURATION_get_value_time(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, struct GNUNET_TIME_Relative *time)
Get a configuration value that should be a relative time.
struct EgoEntry * ego_tail
Ego list.
void GNUNET_CONFIGURATION_iterate_section_values(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, GNUNET_CONFIGURATION_Iterator iter, void *iter_cls)
Iterate over values of a section in the configuration.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
If a value with the given key exists, replace it.
char * nonce
The OIDC nonce.
size_t data_size
Number of bytes in data.
#define GNUNET_GNS_EMPTY_LABEL_AT
String we use to indicate an empty label (top-level entry in the zone).
#define OIDC_GRANT_TYPE_KEY
OIDC grant_type key.
#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE
OIDC expected response_type while authorizing.
struct GNUNET_CONTAINER_MultiHashMapIterator * GNUNET_CONTAINER_multihashmap_iterator_create(const struct GNUNET_CONTAINER_MultiHashMap *map)
Create an iterator for a multihashmap.
void * cls
The closure of the plugin.
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry * list_tail
List tail.
size_t data_size
The POST data size.
struct GNUNET_RECLAIM_AttributeIterator * attr_it
Attribute iterator.
struct GNUNET_RECLAIM_ATTESTATION_REFERENCE * reference
The reference.
static void cookie_identity_interpretation(struct RequestHandle *handle)
Interprets cookie header and pass its identity keystring to handle.
static void persist_access_token(const struct RequestHandle *handle, const char *access_token, const struct GNUNET_RECLAIM_Ticket *ticket)
#define OIDC_CODE_KEY
OIDC code key.
GNUNET_REST_ResultProcessor proc
The plugin result processor.
#define OIDC_ERROR_KEY_SERVER_ERROR
OIDC error key for generic server errors.
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition: time.c:246
static size_t data_size
Number of bytes in data.
Definition: gnunet-abd.c:187
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define OIDC_REDIRECT_URI_KEY
OIDC redirect_uri key.
#define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT
OIDC error key for unauthorized clients.
struct GNUNET_GNS_LookupRequest * gns_op
GNS lookup op.
static void oidc_attr_collect(void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest, const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference)
Collects all attributes/references for an ego if in scope parameter.
#define OIDC_CLAIMS_KEY
OIDC claims key.
char * key
TLS key.
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Handle to a lookup request.
Definition: gns_api.c:48
const struct GNUNET_CRYPTO_EcdsaPrivateKey * GNUNET_IDENTITY_ego_get_private_key(const struct GNUNET_IDENTITY_Ego *ego)
Obtain the ECC key associated with a ego.
Definition: identity_api.c:555
void GNUNET_RECLAIM_disconnect(struct GNUNET_RECLAIM_Handle *h)
Disconnect from identity provider service.
Definition: reclaim_api.c:1044
#define OIDC_COOKIE_EXPIRATION
OIDC cookie expiration (in seconds)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
struct returned by the initialization function of the plugin
const char * reference_value
The name of the attribute/attestation reference value.
static void oidc_ticket_issue_cb(void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
Issues ticket and redirects to relying party with the authorization code as parameter.
helper library for OIDC related functions
#define GNUNET_NO
Definition: gnunet_common.h:86
#define OIDC_COOKIE_HEADER_INFORMATION_KEY
OIDC cookie header information key.
void GNUNET_RECLAIM_ticket_iteration_stop(struct GNUNET_RECLAIM_TicketIterator *it)
Stops iteration and releases the handle for further calls.
Definition: reclaim_api.c:1613
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:83
size_t data_size
Number of bytes in data.
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
static void tld_iter(void *cls, const char *section, const char *option, const char *value)
Iterate over tlds in config.
#define OIDC_COOKIE_HEADER_ACCESS_DENIED
OIDC cookie header if user cancelled.
int user_cancelled
User cancelled authorization/login.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
static void rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Private ECC key encoded for transmission.
void GNUNET_RECLAIM_get_attributes_next(struct GNUNET_RECLAIM_AttributeIterator *it)
Calls the record processor specified in GNUNET_RECLAIM_get_attributes_start for the next record...
Definition: reclaim_api.c:1404
#define OIDC_ERROR_KEY_INVALID_TOKEN
OIDC error key for invalid tokens.
void * libgnunet_plugin_rest_openid_connect_init(void *cls)
Entry point for the plugin.
uint64_t id_attest
Referenced ID of Attestation.
Handle for an operation with the service.
Definition: reclaim_api.c:41
int GNUNET_CONTAINER_multihashmap_contains(const struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key)
Check if the map contains any value under the given key (including values that are NULL)...
void(* process_request)(struct GNUNET_REST_RequestHandle *handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function to process a REST call.
void OIDC_build_token_response(const char *access_token, const char *id_token, const struct GNUNET_TIME_Relative *expiration_time, char **token_response)
Build a token response for a token request TODO: Maybe we should add the scope here?
Definition: oidc_helper.c:851
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
static void login_redirect(void *cls)
Redirects to login page stored in configuration file.
void * proc_cls
The closure of the result processor.
uint64_t abs_value_us
The actual value.
char * edesc
Error response description.
struct OIDC_Variables * oidc
OIDC variables.
Internal representation of the hash map.
Handle for an operation with the identity service.
Definition: identity_api.c:39
#define GNUNET_REST_HANDLER_END
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:47
#define OIDC_STATE_KEY
OIDC state key.
struct GNUNET_RECLAIM_ATTESTATION_Claim * attest
The attestation claim.
The request handle.
void * GNUNET_CONTAINER_multihashmap_get(const struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key)
Given a key find a value in the map matching the key.
#define _(String)
GNU gettext support macro.
Definition: platform.h:180
static char * section
Name of the section.
Definition: gnunet-config.c:33
const void * data
Binary value stored as attribute value.
#define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE
OIDC error key for unsupported grants.
The ego list.
char * response_type
The OIDC response type.
#define OIDC_RESPONSE_TYPE_KEY
OIDC response_type key.
static struct GNUNET_RECLAIM_Ticket ticket
Ticket to consume.
struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey
The RP client public key.
struct GNUNET_IDENTITY_Ego * ego
The Ego.
void GNUNET_NAMESTORE_disconnect(struct GNUNET_NAMESTORE_Handle *h)
Disconnect from the namestore service (and free associated resources).
OIDC needed variables.
void GNUNET_RECLAIM_ATTRIBUTE_list_destroy(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
Destroy claim list.
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
Handle for a zone iterator operation.
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:1253
Handle for an ego.
Definition: identity.h:245
struct GNUNET_RECLAIM_ATTESTATION_REFERENCE * GNUNET_RECLAIM_ATTESTATION_reference_new(const char *attr_name, const char *ref_value)
Create a new attestation reference.
Handle for a attribute iterator operation.
Definition: reclaim_api.c:167
enum State state
current state of profiling
static void do_timeout(void *cls)
Task run on timeout, sends error message.
const struct EgoEntry * find_ego(struct RequestHandle *handle, struct GNUNET_CRYPTO_EcdsaPublicKey *test_key)
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
static char * value
Value of the record to add/remove.
char * emsg
Error response message.
struct GNUNET_CONTAINER_MultiHashMap * url_param_map
Map of url parameters.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:48
const char * url
The url as string.
char * client_id
The OIDC client id of the RP.
Connection to the NAMESTORE service.
Handle for the service.
Definition: identity_api.c:95
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
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:1280
char * name
Plugin name.
void GNUNET_GNS_disconnect(struct GNUNET_GNS_Handle *handle)
Shutdown connection with the GNS service.
Definition: gns_api.c:290
#define OIDC_ERROR_KEY_INVALID_COOKIE
OIDC error key for invalid cookies.
#define OIDC_ERROR_KEY_INVALID_REQUEST
OIDC error key for invalid requests.
struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
static void lookup_redirect_uri_result(void *cls, uint32_t rd_count, const struct GNUNET_GNSRECORD_Data *rd)
struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_ticket_issue(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss, const struct GNUNET_CRYPTO_EcdsaPublicKey *rp, const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, GNUNET_RECLAIM_TicketCallback cb, void *cb_cls)
Issues a ticket to a relying party.
Definition: reclaim_api.c:1456
struct GNUNET_RECLAIM_TicketIterator * ticket_it
Ticket iterator.
char * tld
The tld for redirect.
static char * get_url_parameter_copy(const struct RequestHandle *handle, const char *key)
static char * option
Name of the option.
Definition: gnunet-config.c:38
static struct GNUNET_IDENTITY_Handle * identity_handle
Identity handle.
size_t data_size
Number of bytes in data.
#define GNUNET_REST_API_NS_AUTHORIZE
Authorize endpoint.
static struct GNUNET_DNS_Handle * handle
Handle to transport service.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Multiply relative time by a given factor.
Definition: time.c:442
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
void GNUNET_IDENTITY_disconnect(struct GNUNET_IDENTITY_Handle *h)
Disconnect from identity service.
Definition: identity_api.c:837
struct GNUNET_GNS_Handle * GNUNET_GNS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Initialize the connection with the GNS service.
Definition: gns_api.c:268
#define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE
OIDC error key for unsupported response types.
#define OIDC_CODE_VERIFIER_KEY
OIDC PKCE code verifier.
static void init_cont(struct RequestHandle *handle)
Handle rest request.
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:77
static void cleanup_handle(struct RequestHandle *handle)
Cleanup lookup handle.
struct GNUNET_REST_RequestHandle * rest_handle
Rest connection.
A 512-bit hashcode.
int response_code
Response code.
int state
The processing state.
static void login_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Combines an identity with a login time and responds OK to login request.
static void code_redirect(void *cls)
Checks time and cookie and redirects accordingly.
static char * plugin
Solver plugin name as string.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:118
size_t GNUNET_STRINGS_base64_decode(const char *data, size_t len, void **output)
Decode from Base64.
Definition: strings.c:1920
char * GNUNET_CRYPTO_ecdsa_public_key_to_string(const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
Convert a public key to a string.
Definition: crypto_ecc.c:223
int GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
const char * data
The POST data.
char * claims
The OIDC claims.
struct GNUNET_CRYPTO_EcdsaPublicKey identity
The ticket issuer (= the user)
char * keystring
Public key string.
struct GNUNET_RECLAIM_Handle * idp
Identity Provider.
static struct GNUNET_IDENTITY_Handle * identity
Which namespace do we publish to? NULL if we do not publish to a namespace.
struct GNUNET_CONTAINER_MultiHashMap * OIDC_access_token_map
Hash map that links the issued access token to the corresponding ticket and ego.
There must only be one value per key; storing a value should fail if a value under the same key alrea...
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList * attr_list
Attribute claim list.
static void return_userinfo_response(void *cls)
Return attributes for claim.
#define GNUNET_SYSERR
Definition: gnunet_common.h:84
void GNUNET_CRYPTO_ecdsa_key_get_public(const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv, struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
Extract the public key for the given private key.
Definition: crypto_ecc.c:172
#define OIDC_ERROR_KEY_ACCESS_DENIED
OIDC error key for denied access.
static void userinfo_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Responds to userinfo GET and url-encoded POST request.
struct GNUNET_NAMESTORE_Handle * GNUNET_NAMESTORE_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Connect to the namestore service.
#define OIDC_AUTHORIZATION_HEADER_KEY
OIDC cookie header information key.
int OIDC_parse_authz_code(const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv, const char *code, const char *code_verifier, struct GNUNET_RECLAIM_Ticket *ticket, struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList **attrs, char **nonce_str)
Parse reclaim ticket and nonce from authorization code.
Definition: oidc_helper.c:708
#define OIDC_EXPECTED_AUTHORIZATION_SCOPE
OIDC expected scope part while authorizing.
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
#define GNUNET_REST_API_NS_LOGIN
Login namespace.
static struct GNUNET_SCHEDULER_Task * timeout_task
Task to be run on timeout.
Definition: gnunet-arm.c:124
static char * OIDC_ignored_parameter_array[]
OIDC ignored parameter array.
static struct Ego * ego_head
Head of DLL of all egos.
static int check_authorization(struct RequestHandle *handle, struct GNUNET_CRYPTO_EcdsaPublicKey *cid)
static void build_authz_response(void *cls)
Iteration over all results finished, build final response.
static void consume_ticket(void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest, const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference)
Collects claims and stores them in handle.
char * state
The OIDC state.
int GNUNET_CONTAINER_multihashmap_put(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
void GNUNET_IDENTITY_ego_get_public_key(const struct GNUNET_IDENTITY_Ego *ego, struct GNUNET_CRYPTO_EcdsaPublicKey *pk)
Get the identifier (public key) of an ego.
Definition: identity_api.c:568
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
#define GNUNET_REST_API_NS_OIDC
REST root namespace.
char * GNUNET_RECLAIM_ATTESTATION_value_to_string(uint32_t type, const void *data, size_t data_size)
Convert the &#39;claim&#39; of an attestation to a string.
static void client_redirect(void *cls)
Initiate redirect back to client.
char * OIDC_id_token_new(const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, const struct GNUNET_TIME_Relative *expiration_time, const char *nonce, const char *secret_key)
Create a JWT from attributes.
Definition: oidc_helper.c:119
static void authorize_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Responds to authorization GET and url-encoded POST request.
char * identifier
Ego Identifier.
static void do_error(void *cls)
Task run on error, sends error message.
#define GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT
Record type for reclaim OIDC redirect URIs.
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
static void cleanup_handle_delayed(void *cls)
char * redirect_prefix
The redirect prefix.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_second_(void)
Return relative time of 1s.
Definition: time.c:183
static char * allow_methods
HTTP methods allows for this plugin.
struct GNUNET_RECLAIM_Ticket ticket
A ticket.
char * OIDC_access_token_new()
Generate a new access token.
Definition: oidc_helper.c:879
int GNUNET_CRYPTO_ecdsa_public_key_from_string(const char *enc, size_t enclen, struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
Convert a string representing a public key to a public key.
Definition: crypto_ecc.c:357
struct GNUNET_GNS_Handle * gns_handle
GNS handle.
const char * name
The name of the attribute.
configuration data
Definition: configuration.c:84
struct EgoEntry * ego_head
Ego list.
Handle for a plugin.
Definition: block.c:37
static void options_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Respond to OPTIONS request.
void GNUNET_RECLAIM_get_attributes_stop(struct GNUNET_RECLAIM_AttributeIterator *it)
Stops iteration and releases the handle for further calls.
Definition: reclaim_api.c:1425
struct GNUNET_RECLAIM_ATTRIBUTE_Claim * GNUNET_RECLAIM_ATTRIBUTE_claim_new(const char *attr_name, uint32_t type, const void *data, size_t data_size)
Create a new attribute claim.
struct GNUNET_CRYPTO_EcdsaPublicKey audience
The ticket audience (= relying party)
struct GNUNET_SCHEDULER_Task * timeout_task
ID of a task associated with the resolution process.
static void list_ego(void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, const char *identifier)
If listing is enabled, prints information about the egos.
static void token_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Responds to token url-encoded POST request.
char * redirect_suffix
The redirect suffix.
#define OIDC_ERROR_KEY_INVALID_CLIENT
OIDC error key for invalid client.
struct MHD_Response * GNUNET_REST_create_response(const char *data)
Create REST MHD response.
Definition: rest.c:57
Public ECC key (always for Curve25519) encoded in a format suitable for network transmission and ECDS...
const char * name
The name of the attribute/attestation reference value.
A list of GNUNET_RECLAIM_ATTRIBUTE_Claim structures.
Handle for a ticket iterator operation.
Definition: reclaim_api.c:104
#define GNUNET_log(kind,...)
const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration handle.
Entry in list of pending tasks.
Definition: scheduler.c:134
#define OIDC_SCOPE_KEY
OIDC scope key.
struct GNUNET_RECLAIM_Operation * idp_op
Idp Operation.
void * GNUNET_GNS_lookup_cancel(struct GNUNET_GNS_LookupRequest *lr)
Cancel pending lookup request.
Definition: gns_api.c:314
#define OIDC_GRANT_TYPE_VALUE
OIDC grant_type key.
#define ID_REST_STATE_INIT
State while collecting all egos.
struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
struct GNUNET_NAMESTORE_ZoneIterator * namestore_handle_it
Iterator for NAMESTORE.
#define OIDC_CLIENT_ID_KEY
OIDC client_id key.
char * code_verifier
The PKCE code_verifier.
struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_ticket_consume(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, const struct GNUNET_RECLAIM_Ticket *ticket, GNUNET_RECLAIM_AttributeResult cb, void *cb_cls)
Consumes an issued ticket.
Definition: reclaim_api.c:1505
Time for absolute times used by GNUnet, in microseconds.
json_t * response
The response JSON.
#define GNUNET_YES
Definition: gnunet_common.h:85
struct GNUNET_CONTAINER_MultiHashMap * header_param_map
Map of headers.
Defaults, look in cache, then in DHT.
struct EgoEntry * prev
DLL.
struct GNUNET_CONTAINER_MultiHashMap * OIDC_cookie_jar_map
OIDC Hash map that keeps track of issued cookies.
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:920
static void oidc_collect_finished_cb(void *cls)
void * libgnunet_plugin_rest_openid_connect_done(void *cls)
Exit point from the plugin.
static struct Ego * ego_tail
Tail of DLL of all egos.
static struct GNUNET_ARM_Operation * op
Current operation.
Definition: gnunet-arm.c:144
char * OIDC_build_authz_code(const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, const struct GNUNET_RECLAIM_Ticket *ticket, struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, const char *nonce_str, const char *code_challenge)
Builds an OIDC authorization code including a reclaim ticket and nonce.
Definition: oidc_helper.c:573
char * code_challenge
The PKCE code_challenge.
struct EgoEntry * ego_entry
IDENTITY Operation.
struct GNUNET_GNS_LookupRequest * GNUNET_GNS_lookup(struct GNUNET_GNS_Handle *handle, const char *name, const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, uint32_t type, enum GNUNET_GNS_LocalOptions options, GNUNET_GNS_LookupResultProcessor proc, void *proc_cls)
Perform an asynchronous lookup operation on the GNS.
Definition: gns_api.c:412
static void oidc_iteration_error(void *cls)
Does internal server error when iteration failed.
struct GNUNET_RECLAIM_Handle * GNUNET_RECLAIM_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Connect to the re:claimID service.
Definition: reclaim_api.c:1004
uint32_t data
The data value.
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry * next
DLL.
#define OIDC_COOKIE_HEADER_KEY
OIDC cookie header key.
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry * list_head
List head.
struct EgoEntry * next
DLL.
#define GNUNET_REST_API_NS_USERINFO
UserInfo endpoint.
int GNUNET_STRINGS_string_to_data(const char *enc, size_t enclen, void *out, size_t out_size)
Convert CrockfordBase32 encoding back to data.
Definition: strings.c:952
struct GNUNET_IDENTITY_Handle * identity_handle
Handle to Identity service.
#define ID_REST_STATE_POST_INIT
Done collecting egos.
#define GNUNET_free(ptr)
Wrapper around free.
Time for relative time used by GNUnet, in microseconds.
const void * data
Binary value stored as attribute value.
#define OIDC_ERROR_KEY_INVALID_SCOPE
OIDC error key for invalid scopes.
#define GNUNET_REST_API_NS_TOKEN
Token endpoint.
struct GNUNET_NAMESTORE_Handle * namestore_handle
Handle to NAMESTORE.
char * login_identity
The identity chosen by the user to login.
struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key
Pointer to ego private key.
static void do_userinfo_error(void *cls)
Task run on error in userinfo endpoint, sends error header.
static void do_redirect_error(void *cls)
Task run on error, sends error message and redirects.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:966
char * url
The url.