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"
35 #include "gnunet_reclaim_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 
443 
448 
453 
458 
463 
468 
469 
474 
479 
484 
489 
494 
498  void *proc_cls;
499 
503  char *url;
504 
508  char *tld;
509 
514 
519 
523  char *emsg;
524 
528  char *edesc;
529 
533  int response_code;
534 };
535 
540 static void
542 {
543  struct EgoEntry *ego_entry;
544 
545  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
546  if (NULL != handle->timeout_task)
548  if (NULL != handle->identity_handle)
550  if (NULL != handle->attr_it)
552  if (NULL != handle->attest_it)
554  if (NULL != handle->ticket_it)
556  if (NULL != handle->idp_op)
557  GNUNET_RECLAIM_cancel (handle->idp_op);
558  if (NULL != handle->idp)
559  GNUNET_RECLAIM_disconnect (handle->idp);
560  GNUNET_free (handle->url);
561  GNUNET_free (handle->tld);
562  GNUNET_free (handle->redirect_prefix);
563  GNUNET_free (handle->redirect_suffix);
564  GNUNET_free (handle->emsg);
565  GNUNET_free (handle->edesc);
566  if (NULL != handle->gns_op)
568  if (NULL != handle->gns_handle)
570 
571  if (NULL != handle->namestore_handle)
573  if (NULL != handle->oidc)
574  {
575  GNUNET_free (handle->oidc->client_id);
576  GNUNET_free (handle->oidc->login_identity);
577  GNUNET_free (handle->oidc->nonce);
578  GNUNET_free (handle->oidc->redirect_uri);
579  GNUNET_free (handle->oidc->response_type);
580  GNUNET_free (handle->oidc->scope);
581  GNUNET_free (handle->oidc->state);
582  json_decref (handle->oidc->response);
583  GNUNET_free (handle->oidc);
584  }
585  if (NULL!=handle->attr_idtoken_list)
587  if (NULL!=handle->attr_userinfo_list)
589  if (NULL!=handle->attests_list)
591 
592  while (NULL != (ego_entry = handle->ego_head))
593  {
595  handle->ego_tail,
596  ego_entry);
597  GNUNET_free (ego_entry->identifier);
598  GNUNET_free (ego_entry->keystring);
599  GNUNET_free (ego_entry);
600  }
601  GNUNET_free (handle);
602 }
603 
604 
605 static void
607 {
608  cleanup_handle (cls);
609 }
610 
611 
617 static void
618 do_error (void *cls)
619 {
620  struct RequestHandle *handle = cls;
621  struct MHD_Response *resp;
622  char *json_error;
623 
624  GNUNET_asprintf (&json_error,
625  "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
626  handle->emsg,
627  (NULL != handle->edesc) ? handle->edesc : "",
628  (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
629  (NULL != handle->oidc->state) ? handle->oidc->state : "",
630  (NULL != handle->oidc->state) ? "\"" : "");
631  if (0 == handle->response_code)
632  handle->response_code = MHD_HTTP_BAD_REQUEST;
633  resp = GNUNET_REST_create_response (json_error);
634  if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
635  MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Basic");
636  MHD_add_response_header (resp,
637  MHD_HTTP_HEADER_CONTENT_TYPE,
638  "application/json");
639  handle->proc (handle->proc_cls, resp, handle->response_code);
641  GNUNET_free (json_error);
642 }
643 
644 
651 static void
652 do_userinfo_error (void *cls)
653 {
654  struct RequestHandle *handle = cls;
655  struct MHD_Response *resp;
656  char *error;
657 
658  GNUNET_asprintf (&error,
659  "error=\"%s\", error_description=\"%s\"",
660  handle->emsg,
661  (NULL != handle->edesc) ? handle->edesc : "");
662  resp = GNUNET_REST_create_response ("");
663  MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Bearer");
664  handle->proc (handle->proc_cls, resp, handle->response_code);
666  GNUNET_free (error);
667 }
668 
669 
675 static void
676 do_redirect_error (void *cls)
677 {
678  struct RequestHandle *handle = cls;
679  struct MHD_Response *resp;
680  char *redirect;
681 
682  GNUNET_asprintf (&redirect,
683  "%s?error=%s&error_description=%s%s%s",
684  handle->oidc->redirect_uri,
685  handle->emsg,
686  handle->edesc,
687  (NULL != handle->oidc->state) ? "&state=" : "",
688  (NULL != handle->oidc->state) ? handle->oidc->state : "");
689  resp = GNUNET_REST_create_response ("");
690  MHD_add_response_header (resp, "Location", redirect);
691  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
693  GNUNET_free (redirect);
694 }
695 
696 
702 static void
703 do_timeout (void *cls)
704 {
705  struct RequestHandle *handle = cls;
706 
707  handle->timeout_task = NULL;
708  do_error (handle);
709 }
710 
711 
717 static void
719 {
720  char *result_str;
721  struct RequestHandle *handle = cls;
722  struct MHD_Response *resp;
723 
724  result_str = json_dumps (handle->oidc->response, 0);
725  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"ID-Token: %s\n",result_str);
726  resp = GNUNET_REST_create_response (result_str);
727  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
728  GNUNET_free (result_str);
729  cleanup_handle (handle);
730 }
731 
732 
740 static void
742  const char *url,
743  void *cls)
744 {
745  struct MHD_Response *resp;
746  struct RequestHandle *handle = cls;
747 
748  // For now, independent of path return all options
749  resp = GNUNET_REST_create_response (NULL);
750  MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
751  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
752  cleanup_handle (handle);
753  return;
754 }
755 
756 
760 static void
762 {
763  struct GNUNET_HashCode cache_key;
764  char *cookies;
765  struct GNUNET_TIME_Absolute current_time, *relog_time;
766  char delimiter[] = "; ";
767  char *tmp_cookies;
768  char *token;
769  char *value;
770 
771  // gets identity of login try with cookie
773  strlen (OIDC_COOKIE_HEADER_KEY),
774  &cache_key);
777  &cache_key))
778  {
779  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cookie found\n");
780  return;
781  }
782  // splits cookies and find 'Identity' cookie
783  tmp_cookies =
785  &cache_key);
786  cookies = GNUNET_strdup (tmp_cookies);
787  token = strtok (cookies, delimiter);
788  handle->oidc->user_cancelled = GNUNET_NO;
789  handle->oidc->login_identity = NULL;
790  if (NULL == token)
791  {
793  "Unable to parse cookie: %s\n",
794  cookies);
795  GNUNET_free (cookies);
796  return;
797  }
798 
799  while (NULL != token)
800  {
801  if (0 == strcmp (token, OIDC_COOKIE_HEADER_ACCESS_DENIED))
802  {
803  handle->oidc->user_cancelled = GNUNET_YES;
804  GNUNET_free (cookies);
805  return;
806  }
807  if (NULL != strstr (token, OIDC_COOKIE_HEADER_INFORMATION_KEY))
808  break;
809  token = strtok (NULL, delimiter);
810  }
811  if (NULL == token)
812  {
814  "No cookie value to process: %s\n",
815  cookies);
816  GNUNET_free (cookies);
817  return;
818  }
819  GNUNET_CRYPTO_hash (token, strlen (token), &cache_key);
820  if (GNUNET_NO ==
821  GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
822  {
823  GNUNET_log (
825  "Found cookie `%s', but no corresponding expiration entry present...\n",
826  token);
827  GNUNET_free (cookies);
828  return;
829  }
830  relog_time =
831  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
832  current_time = GNUNET_TIME_absolute_get ();
833  // 30 min after old login -> redirect to login
834  if (current_time.abs_value_us > relog_time->abs_value_us)
835  {
837  "Found cookie `%s', but it is expired.\n",
838  token);
839  GNUNET_free (cookies);
840  return;
841  }
842  value = strtok (token, OIDC_COOKIE_HEADER_INFORMATION_KEY);
843  GNUNET_assert (NULL != value);
844  handle->oidc->login_identity = GNUNET_strdup (value);
845  GNUNET_free (cookies);
846 }
847 
848 
852 static void
853 login_redirect (void *cls)
854 {
855  char *login_base_url;
856  char *new_redirect;
857  struct MHD_Response *resp;
858  struct RequestHandle *handle = cls;
859 
861  "reclaim-rest-plugin",
862  "address",
863  &login_base_url))
864  {
865  GNUNET_asprintf (&new_redirect,
866  "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
867  login_base_url,
869  handle->oidc->response_type,
871  handle->oidc->client_id,
873  handle->oidc->redirect_uri,
875  handle->oidc->scope,
877  (NULL != handle->oidc->state) ? handle->oidc->state : "",
879  (NULL != handle->oidc->code_challenge) ?
880  handle->oidc->code_challenge : "",
882  (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "",
884  (NULL != handle->oidc->claims) ? handle->oidc->claims :
885  "");
886  resp = GNUNET_REST_create_response ("");
887  MHD_add_response_header (resp, "Location", new_redirect);
888  GNUNET_free (login_base_url);
889  }
890  else
891  {
893  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
894  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
896  return;
897  }
898  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
899  GNUNET_free (new_redirect);
901 }
902 
903 
907 static void
909 {
910  struct RequestHandle *handle = cls;
911 
913  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
915 }
916 
917 
922 static void
924 {
925  struct RequestHandle *handle = cls;
926  struct MHD_Response *resp;
927  char *ticket_str;
928  char *redirect_uri;
929  char *code_string;
930 
931  handle->idp_op = NULL;
932  if (NULL == ticket)
933  {
935  handle->edesc = GNUNET_strdup ("Server cannot generate ticket.");
937  return;
938  }
939  handle->ticket = *ticket;
940  ticket_str =
942  sizeof(struct GNUNET_RECLAIM_Ticket));
943  code_string = OIDC_build_authz_code (&handle->priv_key,
944  &handle->ticket,
945  handle->attr_idtoken_list,
946  handle->attests_list,
947  handle->oidc->nonce,
948  handle->oidc->code_challenge);
949  if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
950  (NULL != handle->tld))
951  {
952  GNUNET_asprintf (&redirect_uri,
953  "%s.%s/%s?%s=%s&state=%s",
954  handle->redirect_prefix,
955  handle->tld,
956  handle->redirect_suffix,
957  handle->oidc->response_type,
958  code_string,
959  handle->oidc->state);
960  }
961  else
962  {
963  GNUNET_asprintf (&redirect_uri,
964  "%s?%s=%s&state=%s",
965  handle->oidc->redirect_uri,
966  handle->oidc->response_type,
967  code_string,
968  handle->oidc->state);
969  }
970  resp = GNUNET_REST_create_response ("");
971  MHD_add_response_header (resp, "Location", redirect_uri);
972  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
974  GNUNET_free (redirect_uri);
975  GNUNET_free (ticket_str);
976  GNUNET_free (code_string);
977 }
978 
979 
980 static struct GNUNET_RECLAIM_AttributeList*
982  struct GNUNET_RECLAIM_AttributeList *list_b)
983 {
984  struct GNUNET_RECLAIM_AttributeList *merged_list;
988 
989  merged_list = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
990  for (le_a = list_a->list_head; NULL != le_a; le_a = le_a->next)
991  {
994  &le_a->attribute->
995  attestation,
996  le_a->attribute->type,
997  le_a->attribute->data,
998  le_a->attribute->data_size);
999  le_m->attribute->id = le_a->attribute->id;
1000  le_m->attribute->flag = le_a->attribute->flag;
1001  le_m->attribute->attestation = le_a->attribute->attestation;
1002  GNUNET_CONTAINER_DLL_insert (merged_list->list_head,
1003  merged_list->list_tail,
1004  le_m);
1005  }
1006  le_m = NULL;
1007  for (le_b = list_b->list_head; NULL != le_b; le_b = le_b->next)
1008  {
1009  for (le_m = merged_list->list_head; NULL != le_m; le_m = le_m->next)
1010  {
1012  &le_b->attribute->id))
1013  break;
1014  }
1015  if (NULL != le_m)
1016  continue;
1019  &le_b->attribute->
1020  attestation,
1021  le_b->attribute->type,
1022  le_b->attribute->data,
1023  le_b->attribute->data_size);
1024  le_m->attribute->id = le_b->attribute->id;
1025  le_m->attribute->flag = le_b->attribute->flag;
1026  le_m->attribute->attestation = le_b->attribute->attestation;
1027  GNUNET_CONTAINER_DLL_insert (merged_list->list_head,
1028  merged_list->list_tail,
1029  le_m);
1030  }
1031  return merged_list;
1032 }
1033 
1034 
1035 static void
1037 {
1038  struct RequestHandle *handle = cls;
1039  struct GNUNET_RECLAIM_AttributeList *merged_list;
1040 
1041  handle->attest_it = NULL;
1042  merged_list = attribute_list_merge (handle->attr_idtoken_list,
1043  handle->attr_userinfo_list);
1044  handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp,
1045  &handle->priv_key,
1046  &handle->oidc->client_pkey,
1047  merged_list,
1049  handle);
1051 }
1052 
1053 
1057 static void
1059  const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1060  const struct GNUNET_RECLAIM_Attestation *attest)
1061 {
1062  struct RequestHandle *handle = cls;
1065 
1066  for (ale = handle->attests_list->list_head; NULL != ale; ale = ale->next)
1067  {
1069  &attest->id))
1070  continue;
1073  return;
1074  }
1075 
1076  for (le = handle->attr_idtoken_list->list_head; NULL != le; le = le->next)
1077  {
1079  &attest->id))
1080  continue;
1084  attest->type,
1085  attest->data,
1086  attest->data_size);
1088  handle->attests_list->list_tail,
1089  ale);
1090  }
1092 }
1093 
1094 
1095 static void
1097 {
1098  struct RequestHandle *handle = cls;
1099 
1100  handle->attr_it = NULL;
1101  handle->ticket_it = NULL;
1102  if (NULL == handle->attr_idtoken_list->list_head)
1103  {
1105  handle->edesc = GNUNET_strdup ("The requested scope is not available.");
1107  return;
1108  }
1110  handle->attest_it =
1112  &handle->priv_key,
1114  handle,
1116  handle,
1118  handle);
1119 
1120 }
1121 
1122 
1123 static int
1125  const char *attr_name,
1126  const char *claims_parameter)
1127 {
1128  char *scope_variables;
1129  char *scope_variable;
1130  char delimiter[] = " ";
1131  int ret = GNUNET_NO;
1132  json_t *root;
1133  json_error_t error;
1134  json_t *claims_j;
1135  const char *key;
1136  json_t *value;
1137 
1138  scope_variables = GNUNET_strdup (handle->oidc->scope);
1139  scope_variable = strtok (scope_variables, delimiter);
1140  while (NULL != scope_variable)
1141  {
1142  if (0 == strcmp (attr_name, scope_variable))
1143  break;
1144  scope_variable = strtok (NULL, delimiter);
1145  }
1146  if (NULL != scope_variable)
1147  ret = GNUNET_YES;
1148  GNUNET_free (scope_variables);
1149 
1151  if ((NULL != handle->oidc->claims) &&
1152  (GNUNET_YES != ret))
1153  {
1154  root = json_loads (handle->oidc->claims, JSON_DECODE_ANY, &error);
1155  claims_j = json_object_get (root, claims_parameter);
1156  /* obj is a JSON object */
1157  if (NULL != claims_j)
1158  {
1159  json_object_foreach (claims_j, key, value) {
1160  if (0 != strcmp (attr_name, key))
1161  continue;
1162  ret = GNUNET_YES;
1163  break;
1164  }
1165  }
1166  json_decref (root);
1167  }
1168  return ret;
1169 }
1170 
1171 
1172 static int
1174  const char *attr_name)
1175 {
1176  return attr_in_claims_request (handle, attr_name, "id_token");
1177 }
1178 
1179 
1180 static int
1182  const char *attr_name)
1183 {
1184  return attr_in_claims_request (handle, attr_name, "userinfo");
1185 }
1186 
1187 
1191 static void
1193  const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1194  const struct GNUNET_RECLAIM_Attribute *attr)
1195 {
1196  struct RequestHandle *handle = cls;
1198  if (GNUNET_YES == attr_in_idtoken_request (handle, attr->name))
1199  {
1202  &attr->attestation,
1203  attr->type,
1204  attr->data,
1205  attr->data_size);
1206  le->attribute->id = attr->id;
1207  le->attribute->flag = attr->flag;
1208  le->attribute->attestation = attr->attestation;
1210  handle->attr_idtoken_list->list_tail,
1211  le);
1212  }
1213  if (GNUNET_YES == attr_in_userinfo_request (handle, attr->name))
1214  {
1217  &attr->attestation,
1218  attr->type,
1219  attr->data,
1220  attr->data_size);
1221  le->attribute->id = attr->id;
1222  le->attribute->flag = attr->flag;
1223  le->attribute->attestation = attr->attestation;
1225  handle->attr_userinfo_list->list_tail,
1226  le);
1227  }
1228 
1230 }
1231 
1232 
1236 static void
1237 code_redirect (void *cls)
1238 {
1239  struct RequestHandle *handle = cls;
1240  struct GNUNET_TIME_Absolute current_time;
1241  struct GNUNET_TIME_Absolute *relog_time;
1242  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
1243  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pkey;
1244  struct GNUNET_HashCode cache_key;
1245  char *identity_cookie;
1246 
1247  GNUNET_asprintf (&identity_cookie,
1248  "Identity=%s",
1249  handle->oidc->login_identity);
1250  GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1251  GNUNET_free (identity_cookie);
1252  // No login time for identity -> redirect to login
1253  if (GNUNET_YES ==
1254  GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
1255  {
1256  relog_time =
1257  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
1258  current_time = GNUNET_TIME_absolute_get ();
1259  // 30 min after old login -> redirect to login
1260  if (current_time.abs_value_us <= relog_time->abs_value_us)
1261  {
1262  if (GNUNET_OK !=
1264  ->login_identity,
1265  strlen (
1266  handle->oidc
1267  ->login_identity),
1268  &pubkey))
1269  {
1271  handle->edesc =
1272  GNUNET_strdup ("The cookie of a login identity is not valid");
1274  return;
1275  }
1276  // iterate over egos and compare their public key
1277  for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
1278  handle->ego_entry = handle->ego_entry->next)
1279  {
1280  GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1281  if (0 == GNUNET_memcmp (&ego_pkey, &pubkey))
1282  {
1283  handle->priv_key =
1285  handle->idp = GNUNET_RECLAIM_connect (cfg);
1286  handle->attr_idtoken_list =
1288  handle->attr_userinfo_list =
1290  handle->attr_it =
1292  &handle->priv_key,
1294  handle,
1296  handle,
1298  handle);
1299  return;
1300  }
1301  }
1303  return;
1304  }
1305  }
1306 }
1307 
1308 
1309 static void
1310 build_redirect (void *cls)
1311 {
1312  struct RequestHandle *handle = cls;
1313  struct MHD_Response *resp;
1314  char *redirect_uri;
1315 
1316  if (GNUNET_YES == handle->oidc->user_cancelled)
1317  {
1318  if ((NULL != handle->redirect_prefix) &&
1319  (NULL != handle->redirect_suffix) && (NULL != handle->tld))
1320  {
1321  GNUNET_asprintf (&redirect_uri,
1322  "%s.%s/%s?error=%s&error_description=%s&state=%s",
1323  handle->redirect_prefix,
1324  handle->tld,
1325  handle->redirect_suffix,
1326  "access_denied",
1327  "User denied access",
1328  handle->oidc->state);
1329  }
1330  else
1331  {
1332  GNUNET_asprintf (&redirect_uri,
1333  "%s?error=%s&error_description=%s&state=%s",
1334  handle->oidc->redirect_uri,
1335  "access_denied",
1336  "User denied access",
1337  handle->oidc->state);
1338  }
1339  resp = GNUNET_REST_create_response ("");
1340  MHD_add_response_header (resp, "Location", redirect_uri);
1341  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1343  GNUNET_free (redirect_uri);
1344  return;
1345  }
1347 }
1348 
1349 
1350 static void
1352  uint32_t rd_count,
1353  const struct GNUNET_GNSRECORD_Data *rd)
1354 {
1355  struct RequestHandle *handle = cls;
1356  char *tmp;
1357  char *tmp_key_str;
1358  char *pos;
1359  struct GNUNET_CRYPTO_EcdsaPublicKey redirect_zone;
1360 
1361  handle->gns_op = NULL;
1362  if (0 == rd_count)
1363  {
1365  handle->edesc =
1366  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1368  return;
1369  }
1370  for (int i = 0; i < rd_count; i++)
1371  {
1372  if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type)
1373  continue;
1374  if (0 != strncmp (rd[i].data, handle->oidc->redirect_uri, rd[i].data_size))
1375  continue;
1376  tmp = GNUNET_strndup (rd[i].data, rd[i].data_size);
1377  if (NULL == strstr (tmp, handle->oidc->client_id))
1378  {
1380  "Redirect uri %s does not contain client_id %s\n",
1381  tmp,
1382  handle->oidc->client_id);
1383  }
1384  else
1385  {
1386  pos = strrchr (tmp, (unsigned char) '.');
1387  if (NULL == pos)
1388  {
1390  "Redirect uri %s contains client_id but is malformed\n",
1391  tmp);
1392  GNUNET_free (tmp);
1393  continue;
1394  }
1395  *pos = '\0';
1396  handle->redirect_prefix = GNUNET_strdup (tmp);
1397  tmp_key_str = pos + 1;
1398  pos = strchr (tmp_key_str, (unsigned char) '/');
1399  if (NULL == pos)
1400  {
1402  "Redirect uri %s contains client_id but is malformed\n",
1403  tmp);
1404  GNUNET_free (tmp);
1405  continue;
1406  }
1407  *pos = '\0';
1408  handle->redirect_suffix = GNUNET_strdup (pos + 1);
1409 
1410  GNUNET_STRINGS_string_to_data (tmp_key_str,
1411  strlen (tmp_key_str),
1412  &redirect_zone,
1413  sizeof(redirect_zone));
1414  }
1416  GNUNET_free (tmp);
1417  return;
1418  }
1420  handle->edesc =
1421  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1423 }
1424 
1425 
1429 static void
1430 client_redirect (void *cls)
1431 {
1432  struct RequestHandle *handle = cls;
1433 
1434  /* Lookup client redirect uri to verify request */
1435  handle->gns_op =
1436  GNUNET_GNS_lookup (handle->gns_handle,
1438  &handle->oidc->client_pkey,
1442  handle);
1443 }
1444 
1445 
1446 static char *
1447 get_url_parameter_copy (const struct RequestHandle *handle, const char *key)
1448 {
1449  struct GNUNET_HashCode hc;
1450  char *value;
1451 
1452  GNUNET_CRYPTO_hash (key, strlen (key), &hc);
1454  ->url_param_map,
1455  &hc))
1456  return NULL;
1457  value =
1459  if (NULL == value)
1460  return NULL;
1461  return GNUNET_strdup (value);
1462 }
1463 
1464 
1471 static void
1473 {
1474  struct RequestHandle *handle = cls;
1475  struct GNUNET_HashCode cache_key;
1476 
1477  char *expected_scope;
1478  char delimiter[] = " ";
1479  int number_of_ignored_parameter, iterator;
1480 
1481 
1482  // REQUIRED value: redirect_uri
1483  handle->oidc->redirect_uri =
1485  if (NULL == handle->oidc->redirect_uri)
1486  {
1488  handle->edesc = GNUNET_strdup ("missing parameter redirect_uri");
1490  return;
1491  }
1492 
1493  // REQUIRED value: response_type
1494  handle->oidc->response_type =
1496  if (NULL == handle->oidc->response_type)
1497  {
1499  handle->edesc = GNUNET_strdup ("missing parameter response_type");
1501  return;
1502  }
1503 
1504  // REQUIRED value: scope
1505  handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
1506  if (NULL == handle->oidc->scope)
1507  {
1509  handle->edesc = GNUNET_strdup ("missing parameter scope");
1511  return;
1512  }
1513 
1514  // OPTIONAL value: nonce
1515  handle->oidc->nonce = get_url_parameter_copy (handle, OIDC_NONCE_KEY);
1516 
1517  // OPTIONAL value: claims
1518  handle->oidc->claims = get_url_parameter_copy (handle, OIDC_CLAIMS_KEY);
1519 
1520  // TODO check other values if needed
1521  number_of_ignored_parameter =
1522  sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1523  for (iterator = 0; iterator < number_of_ignored_parameter; iterator++)
1524  {
1526  strlen (OIDC_ignored_parameter_array[iterator]),
1527  &cache_key);
1528  if (GNUNET_YES ==
1530  ->url_param_map,
1531  &cache_key))
1532  {
1534  GNUNET_asprintf (&handle->edesc,
1535  "Server will not handle parameter: %s",
1536  OIDC_ignored_parameter_array[iterator]);
1538  return;
1539  }
1540  }
1541 
1542  // We only support authorization code flows.
1543  if (0 != strcmp (handle->oidc->response_type,
1545  {
1547  handle->edesc = GNUNET_strdup ("The authorization server does not support "
1548  "obtaining this authorization code.");
1550  return;
1551  }
1552 
1553  // Checks if scope contains 'openid'
1554  expected_scope = GNUNET_strdup (handle->oidc->scope);
1555  char *test;
1556  test = strtok (expected_scope, delimiter);
1557  while (NULL != test)
1558  {
1559  if (0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope))
1560  break;
1561  test = strtok (NULL, delimiter);
1562  }
1563  if (NULL == test)
1564  {
1566  handle->edesc =
1567  GNUNET_strdup ("The requested scope is invalid, unknown, or malformed.");
1569  GNUNET_free (expected_scope);
1570  return;
1571  }
1572 
1573  GNUNET_free (expected_scope);
1574  if ((NULL == handle->oidc->login_identity) &&
1575  (GNUNET_NO == handle->oidc->user_cancelled))
1577  else
1579 }
1580 
1581 
1585 static void
1586 tld_iter (void *cls, const char *section, const char *option, const char *value)
1587 {
1588  struct RequestHandle *handle = cls;
1589  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1590 
1591  if (GNUNET_OK !=
1592  GNUNET_CRYPTO_ecdsa_public_key_from_string (value, strlen (value), &pkey))
1593  {
1594  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping non key %s\n", value);
1595  return;
1596  }
1597  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1598  handle->tld = GNUNET_strdup (option + 1);
1599 }
1600 
1601 
1609 static void
1611  const char *url,
1612  void *cls)
1613 {
1614  struct RequestHandle *handle = cls;
1615  struct EgoEntry *tmp_ego;
1616  const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1617  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1618 
1620 
1621  // RECOMMENDED value: state - REQUIRED for answers
1622  handle->oidc->state = get_url_parameter_copy (handle, OIDC_STATE_KEY);
1623 
1624  // REQUIRED value: client_id
1626  if (NULL == handle->oidc->client_id)
1627  {
1629  handle->edesc = GNUNET_strdup ("missing parameter client_id");
1630  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1632  return;
1633  }
1634 
1635  // OPTIONAL value: code_challenge
1636  handle->oidc->code_challenge = get_url_parameter_copy (handle,
1638  if (NULL == handle->oidc->code_challenge)
1639  {
1641  "OAuth authorization request does not contain PKCE parameters!\n");
1642  }
1643 
1644  if (GNUNET_OK !=
1646  strlen (
1647  handle->oidc->client_id),
1648  &handle->oidc->client_pkey))
1649  {
1651  handle->edesc = GNUNET_strdup ("The client is not authorized to request an "
1652  "authorization code using this method.");
1653  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1655  return;
1656  }
1657 
1658  // If we know this identity, translated the corresponding TLD
1659  // TODO: We might want to have a reverse lookup functionality for TLDs?
1660  for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
1661  {
1662  priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
1663  GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, &pkey);
1664  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1665  {
1666  handle->tld = GNUNET_strdup (tmp_ego->identifier);
1667  handle->ego_entry = handle->ego_tail;
1668  }
1669  }
1670  handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
1671  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scope: %s\n", handle->oidc->scope);
1672  if (NULL == handle->tld)
1674  if (NULL == handle->tld)
1675  handle->tld = GNUNET_strdup (handle->oidc->client_id);
1677 }
1678 
1679 
1687 static void
1689  const char *url,
1690  void *cls)
1691 {
1692  struct MHD_Response *resp = GNUNET_REST_create_response ("");
1693  struct RequestHandle *handle = cls;
1694  struct GNUNET_HashCode cache_key;
1695  struct GNUNET_TIME_Absolute *current_time;
1696  struct GNUNET_TIME_Absolute *last_time;
1697  char *cookie;
1698  char *header_val;
1699  json_t *root;
1700  json_error_t error;
1701  json_t *identity;
1702  char term_data[handle->rest_handle->data_size + 1];
1703 
1704  term_data[handle->rest_handle->data_size] = '\0';
1705  GNUNET_memcpy (term_data,
1706  handle->rest_handle->data,
1707  handle->rest_handle->data_size);
1708  root = json_loads (term_data, JSON_DECODE_ANY, &error);
1709  identity = json_object_get (root, "identity");
1710  if (! json_is_string (identity))
1711  {
1713  "Error parsing json string from %s\n",
1714  term_data);
1715  handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1716  json_decref (root);
1718  return;
1719  }
1720  GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1721  GNUNET_asprintf (&header_val,
1722  "%s;Max-Age=%d",
1723  cookie,
1725  MHD_add_response_header (resp, "Set-Cookie", header_val);
1726  MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST");
1727  GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1728 
1729  if (0 != strcmp (json_string_value (identity), "Denied"))
1730  {
1731  current_time = GNUNET_new (struct GNUNET_TIME_Absolute);
1732  *current_time = GNUNET_TIME_relative_to_absolute (
1735  last_time =
1736  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
1737  GNUNET_free (last_time);
1738  GNUNET_CONTAINER_multihashmap_put (OIDC_cookie_jar_map,
1739  &cache_key,
1740  current_time,
1742  }
1743  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1744  GNUNET_free (cookie);
1745  GNUNET_free (header_val);
1746  json_decref (root);
1748 }
1749 
1750 
1751 static int
1753  struct GNUNET_CRYPTO_EcdsaPublicKey *cid)
1754 {
1755  struct GNUNET_HashCode cache_key;
1756  char *authorization;
1757  char *credentials;
1758  char *basic_authorization;
1759  char *client_id;
1760  char *pass;
1761  char *expected_pass;
1762 
1765  &cache_key);
1767  ->header_param_map,
1768  &cache_key))
1769  {
1771  handle->edesc = GNUNET_strdup ("missing authorization");
1772  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1773  return GNUNET_SYSERR;
1774  }
1775  authorization =
1777  &cache_key);
1778 
1779  // split header in "Basic" and [content]
1780  credentials = strtok (authorization, " ");
1781  if ((NULL == credentials) || (0 != strcmp ("Basic", credentials)))
1782  {
1784  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1785  return GNUNET_SYSERR;
1786  }
1787  credentials = strtok (NULL, " ");
1788  if (NULL == credentials)
1789  {
1791  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1792  return GNUNET_SYSERR;
1793  }
1794  GNUNET_STRINGS_base64_decode (credentials,
1795  strlen (credentials),
1796  (void **) &basic_authorization);
1797 
1798  if (NULL == basic_authorization)
1799  {
1801  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1802  return GNUNET_SYSERR;
1803  }
1804  client_id = strtok (basic_authorization, ":");
1805  if (NULL == client_id)
1806  {
1807  GNUNET_free (basic_authorization);
1809  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1810  return GNUNET_SYSERR;
1811  }
1812  pass = strtok (NULL, ":");
1813  if (NULL == pass)
1814  {
1815  GNUNET_free (basic_authorization);
1817  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1818  return GNUNET_SYSERR;
1819  }
1820 
1821  // check client password
1823  "reclaim-rest-plugin",
1824  "OIDC_CLIENT_SECRET",
1825  &expected_pass))
1826  {
1827  if (0 != strcmp (expected_pass, pass))
1828  {
1829  GNUNET_free (basic_authorization);
1830  GNUNET_free (expected_pass);
1832  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1833  return GNUNET_SYSERR;
1834  }
1835  GNUNET_free (expected_pass);
1836  }
1837  else
1838  {
1839  GNUNET_free (basic_authorization);
1841  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1842  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1843  return GNUNET_SYSERR;
1844  }
1845 
1846  // check client_id
1847  for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
1848  handle->ego_entry = handle->ego_entry->next)
1849  {
1850  if (0 == strcmp (handle->ego_entry->keystring, client_id))
1851  break;
1852  }
1853  if (NULL == handle->ego_entry)
1854  {
1855  GNUNET_free (basic_authorization);
1857  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1858  return GNUNET_SYSERR;
1859  }
1860  GNUNET_STRINGS_string_to_data (client_id,
1861  strlen (client_id),
1862  cid,
1863  sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
1864 
1865  GNUNET_free (basic_authorization);
1866  return GNUNET_OK;
1867 }
1868 
1869 
1870 const struct EgoEntry *
1872  struct GNUNET_CRYPTO_EcdsaPublicKey *test_key)
1873 {
1874  struct EgoEntry *ego_entry;
1875  struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1876 
1877  for (ego_entry = handle->ego_head; NULL != ego_entry;
1878  ego_entry = ego_entry->next)
1879  {
1880  GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
1881  if (0 == GNUNET_memcmp (&pub_key, test_key))
1882  return ego_entry;
1883  }
1884  return NULL;
1885 }
1886 
1887 
1888 static void
1890  const char *access_token,
1891  const struct GNUNET_RECLAIM_Ticket *ticket)
1892 {
1893  struct GNUNET_HashCode hc;
1894  struct GNUNET_RECLAIM_Ticket *ticketbuf;
1895 
1896  GNUNET_CRYPTO_hash (access_token, strlen (access_token), &hc);
1897  ticketbuf = GNUNET_new (struct GNUNET_RECLAIM_Ticket);
1898  *ticketbuf = *ticket;
1901  OIDC_access_token_map,
1902  &hc,
1903  ticketbuf,
1905 }
1906 
1907 
1915 static void
1917  const char *url,
1918  void *cls)
1919 {
1920  struct RequestHandle *handle = cls;
1921  const struct EgoEntry *ego_entry;
1922  struct GNUNET_TIME_Relative expiration_time;
1923  struct GNUNET_RECLAIM_AttributeList *cl = NULL;
1924  struct GNUNET_RECLAIM_AttestationList *al = NULL;
1925  struct GNUNET_RECLAIM_Ticket ticket;
1926  struct GNUNET_CRYPTO_EcdsaPublicKey cid;
1927  const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
1928  struct GNUNET_HashCode cache_key;
1929  struct MHD_Response *resp;
1930  char *grant_type;
1931  char *code;
1932  char *json_response;
1933  char *id_token;
1934  char *access_token;
1935  char *jwt_secret;
1936  char *nonce;
1937  char *code_verifier;
1938 
1939  /*
1940  * Check Authorization
1941  */
1942  if (GNUNET_SYSERR == check_authorization (handle, &cid))
1943  {
1945  "OIDC authorization for token endpoint failed\n");
1947  return;
1948  }
1949 
1950  /*
1951  * Check parameter
1952  */
1953 
1954  // TODO Do not allow multiple equal parameter names
1955  // REQUIRED grant_type
1957  strlen (OIDC_GRANT_TYPE_KEY),
1958  &cache_key);
1959  grant_type = get_url_parameter_copy (handle, OIDC_GRANT_TYPE_KEY);
1960  if (NULL == grant_type)
1961  {
1963  handle->edesc = GNUNET_strdup ("missing parameter grant_type");
1964  handle->response_code = MHD_HTTP_BAD_REQUEST;
1966  return;
1967  }
1968 
1969  // Check parameter grant_type == "authorization_code"
1970  if (0 != strcmp (OIDC_GRANT_TYPE_VALUE, grant_type))
1971  {
1973  handle->response_code = MHD_HTTP_BAD_REQUEST;
1974  GNUNET_free (grant_type);
1976  return;
1977  }
1978  GNUNET_free (grant_type);
1979  // REQUIRED code
1980  code = get_url_parameter_copy (handle, OIDC_CODE_KEY);
1981  if (NULL == code)
1982  {
1984  handle->edesc = GNUNET_strdup ("missing parameter code");
1985  handle->response_code = MHD_HTTP_BAD_REQUEST;
1987  return;
1988  }
1989  ego_entry = find_ego (handle, &cid);
1990  if (NULL == ego_entry)
1991  {
1993  handle->edesc = GNUNET_strdup ("Unknown client");
1994  handle->response_code = MHD_HTTP_BAD_REQUEST;
1995  GNUNET_free (code);
1997  return;
1998  }
1999  privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
2000 
2001  // REQUIRED code verifier
2002  code_verifier = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY);
2003  if (NULL == code_verifier)
2004  {
2006  "OAuth authorization request does not contain PKCE parameters!\n");
2007 
2008  }
2009 
2010  // decode code
2011  if (GNUNET_OK != OIDC_parse_authz_code (privkey, code, code_verifier, &ticket,
2012  &cl, &al, &nonce))
2013  {
2015  handle->edesc = GNUNET_strdup ("invalid code");
2016  handle->response_code = MHD_HTTP_BAD_REQUEST;
2017  GNUNET_free (code);
2019  return;
2020  }
2021  GNUNET_free (code);
2022 
2023  // create jwt
2025  "reclaim-rest-plugin",
2026  "expiration_time",
2027  &expiration_time))
2028  {
2030  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2031  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2033  return;
2034  }
2035 
2036 
2037  // TODO OPTIONAL acr,amr,azp
2039  "reclaim-rest-plugin",
2040  "jwt_secret",
2041  &jwt_secret))
2042  {
2044  handle->edesc = GNUNET_strdup ("No signing secret configured!");
2045  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2047  return;
2048  }
2049  id_token = OIDC_id_token_new (&ticket.audience,
2050  &ticket.identity,
2051  cl,
2052  al,
2053  &expiration_time,
2054  (NULL != nonce) ? nonce : NULL,
2055  jwt_secret);
2056  access_token = OIDC_access_token_new ();
2057  OIDC_build_token_response (access_token,
2058  id_token,
2059  &expiration_time,
2060  &json_response);
2061 
2062  persist_access_token (handle, access_token, &ticket);
2063  resp = GNUNET_REST_create_response (json_response);
2064  MHD_add_response_header (resp, "Cache-Control", "no-store");
2065  MHD_add_response_header (resp, "Pragma", "no-cache");
2066  MHD_add_response_header (resp, "Content-Type", "application/json");
2067  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2070  GNUNET_free (access_token);
2071  GNUNET_free (json_response);
2072  GNUNET_free (id_token);
2074 }
2075 
2076 
2080 static void
2081 consume_ticket (void *cls,
2082  const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
2083  const struct GNUNET_RECLAIM_Attribute *attr,
2084  const struct GNUNET_RECLAIM_Attestation *attest)
2085 {
2086  struct RequestHandle *handle = cls;
2087  handle->idp_op = NULL;
2088 
2089  if (NULL == identity)
2090  {
2092  return;
2093  }
2095  {
2096  char *tmp_value;
2097  json_t *value;
2099  attr->data,
2100  attr->data_size);
2101  value = json_string (tmp_value);
2102  json_object_set_new (handle->oidc->response, attr->name, value);
2103  GNUNET_free (tmp_value);
2104  return;
2105  }
2106  json_t *claim_sources;
2107  json_t *claim_sources_jwt;
2108  json_t *claim_names;
2109  char *attest_val_str;
2110  claim_sources = json_object_get (handle->oidc->response,"_claim_sources");
2111  claim_names = json_object_get (handle->oidc->response,"_claim_names");
2112  attest_val_str =
2114  attest->data,
2115  attest->data_size);
2116  if ((NULL == claim_sources) && (NULL == claim_names) )
2117  {
2118  claim_sources = json_object ();
2119  claim_names = json_object ();
2120  }
2121  char *source_name;
2122  int i = 0;
2123  GNUNET_asprintf (&source_name, "src%d", i);
2124  while (NULL != (claim_sources_jwt = json_object_get (claim_sources,
2125  source_name)))
2126  {
2127  if (0 == strcmp (json_string_value (json_object_get (claim_sources_jwt,
2128  "JWT")),
2129  attest_val_str))
2130  {
2131  // Adapt only the claim names
2132  json_object_set_new (claim_names, attr->data,
2133  json_string (source_name));
2134  json_object_set (handle->oidc->response,
2135  "_claim_names", claim_names);
2136  break;
2137  }
2138  i++;
2139  GNUNET_free (source_name);
2140  GNUNET_asprintf (&source_name, "src%d", i);
2141  }
2142 
2143  // Create new one
2144  if (NULL == claim_sources_jwt)
2145  {
2146  claim_sources_jwt = json_object ();
2147  // Set the JWT for names
2148  json_object_set_new (claim_names, attr->data,
2149  json_string (source_name));
2150  // Set the JWT for the inner source
2151  json_object_set_new (claim_sources_jwt, "JWT",
2152  json_string (attest_val_str));
2153  // Set the JWT for the source
2154  json_object_set_new (claim_sources, source_name, claim_sources_jwt);
2155  // Set as claims
2156  json_object_set (handle->oidc->response, "_claim_names", claim_names);
2157  json_object_set (handle->oidc->response, "_claim_sources",claim_sources);
2158  }
2159 
2160  json_decref (claim_sources);
2161  json_decref (claim_names);
2162  json_decref (claim_sources_jwt);
2163  GNUNET_free (attest_val_str);
2164 }
2165 
2166 
2174 static void
2176  const char *url,
2177  void *cls)
2178 {
2179  // TODO expiration time
2180  struct RequestHandle *handle = cls;
2181  char delimiter[] = " ";
2182  struct GNUNET_HashCode cache_key;
2183  char *authorization;
2184  char *authorization_type;
2185  char *authorization_access_token;
2186  struct GNUNET_RECLAIM_Ticket *ticket;
2187  const struct EgoEntry *ego_entry;
2188  const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
2189 
2192  &cache_key);
2194  ->header_param_map,
2195  &cache_key))
2196  {
2198  handle->edesc = GNUNET_strdup ("No Access Token");
2199  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2201  return;
2202  }
2203  authorization =
2205  &cache_key);
2206 
2207  // split header in "Bearer" and access_token
2208  authorization = GNUNET_strdup (authorization);
2209  authorization_type = strtok (authorization, delimiter);
2210  if ((NULL == authorization_type) ||
2211  (0 != strcmp ("Bearer", authorization_type)))
2212  {
2214  handle->edesc = GNUNET_strdup ("No Access Token");
2215  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2217  GNUNET_free (authorization);
2218  return;
2219  }
2220  authorization_access_token = strtok (NULL, delimiter);
2221  if (NULL == authorization_access_token)
2222  {
2224  handle->edesc = GNUNET_strdup ("Access token missing");
2225  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2227  GNUNET_free (authorization);
2228  return;
2229  }
2230 
2231  GNUNET_CRYPTO_hash (authorization_access_token,
2232  strlen (authorization_access_token),
2233  &cache_key);
2234  if (GNUNET_NO ==
2235  GNUNET_CONTAINER_multihashmap_contains (OIDC_access_token_map,
2236  &cache_key))
2237  {
2239  handle->edesc = GNUNET_strdup ("The access token expired");
2240  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2242  GNUNET_free (authorization);
2243  return;
2244  }
2245  ticket =
2246  GNUNET_CONTAINER_multihashmap_get (OIDC_access_token_map, &cache_key);
2247  GNUNET_assert (NULL != ticket);
2248  ego_entry = find_ego (handle, &ticket->audience);
2249  if (NULL == ego_entry)
2250  {
2252  handle->edesc = GNUNET_strdup ("The access token expired");
2253  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2255  GNUNET_free (authorization);
2256  return;
2257  }
2258 
2259  handle->idp = GNUNET_RECLAIM_connect (cfg);
2260  handle->oidc->response = json_object ();
2261  json_object_set_new (handle->oidc->response,
2262  "sub",
2263  json_string (ego_entry->keystring));
2264  privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
2265  handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
2266  privkey,
2267  ticket,
2269  handle);
2270  GNUNET_free (authorization);
2271 }
2272 
2273 
2279 static void
2281 {
2283  static const struct GNUNET_REST_RequestHandler handlers[] =
2284  { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint },
2285  { MHD_HTTP_METHOD_POST,
2287  &authorize_endpoint }, // url-encoded
2288  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont },
2289  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
2290  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2291  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2292  { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, &options_cont },
2294 
2295  if (GNUNET_NO ==
2296  GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
2297  {
2298  handle->response_code = err.error_code;
2300  }
2301 }
2302 
2303 
2337 static void
2338 list_ego (void *cls,
2339  struct GNUNET_IDENTITY_Ego *ego,
2340  void **ctx,
2341  const char *identifier)
2342 {
2343  struct RequestHandle *handle = cls;
2344  struct EgoEntry *ego_entry;
2345  struct GNUNET_CRYPTO_EcdsaPublicKey pk;
2346 
2347  if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
2348  {
2349  handle->state = ID_REST_STATE_POST_INIT;
2350  init_cont (handle);
2351  return;
2352  }
2353  GNUNET_assert (NULL != ego);
2354  if (ID_REST_STATE_INIT == handle->state)
2355 
2356  {
2357  ego_entry = GNUNET_new (struct EgoEntry);
2360  ego_entry->ego = ego;
2361  ego_entry->identifier = GNUNET_strdup (identifier);
2363  handle->ego_tail,
2364  ego_entry);
2365  return;
2366  }
2367  /* Ego renamed or added */
2368  if (identifier != NULL)
2369  {
2370  for (ego_entry = handle->ego_head; NULL != ego_entry;
2371  ego_entry = ego_entry->next)
2372  {
2373  if (ego_entry->ego == ego)
2374  {
2375  /* Rename */
2376  GNUNET_free (ego_entry->identifier);
2377  ego_entry->identifier = GNUNET_strdup (identifier);
2378  break;
2379  }
2380  }
2381  if (NULL == ego_entry)
2382  {
2383  /* Add */
2384  ego_entry = GNUNET_new (struct EgoEntry);
2387  ego_entry->ego = ego;
2388  ego_entry->identifier = GNUNET_strdup (identifier);
2390  handle->ego_tail,
2391  ego_entry);
2392  }
2393  }
2394  else
2395  {
2396  /* Delete */
2397  for (ego_entry = handle->ego_head; NULL != ego_entry;
2398  ego_entry = ego_entry->next)
2399  {
2400  if (ego_entry->ego == ego)
2401  break;
2402  }
2403  if (NULL == ego_entry)
2404  return; /* Not found */
2405 
2407  handle->ego_tail,
2408  ego_entry);
2409  GNUNET_free (ego_entry->identifier);
2410  GNUNET_free (ego_entry->keystring);
2411  GNUNET_free (ego_entry);
2412  return;
2413  }
2414 }
2415 
2416 
2417 static void
2420  void *proc_cls)
2421 {
2422  struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
2423 
2424  handle->oidc = GNUNET_new (struct OIDC_Variables);
2425  if (NULL == OIDC_cookie_jar_map)
2426  OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10,
2427  GNUNET_NO);
2428  if (NULL == OIDC_access_token_map)
2429  OIDC_access_token_map =
2431  handle->response_code = 0;
2433  handle->proc_cls = proc_cls;
2434  handle->proc = proc;
2435  handle->state = ID_REST_STATE_INIT;
2436  handle->rest_handle = rest_handle;
2437 
2438  handle->url = GNUNET_strdup (rest_handle->url);
2439  if (handle->url[strlen (handle->url) - 1] == '/')
2440  handle->url[strlen (handle->url) - 1] = '\0';
2441  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
2442  handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
2443  handle->gns_handle = GNUNET_GNS_connect (cfg);
2445  handle->timeout_task =
2446  GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
2447  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
2448 }
2449 
2450 
2457 void *
2459 {
2460  static struct Plugin plugin;
2461  struct GNUNET_REST_Plugin *api;
2462 
2463  cfg = cls;
2464  if (NULL != plugin.cfg)
2465  return NULL; /* can only initialize once! */
2466  memset (&plugin, 0, sizeof(struct Plugin));
2467  plugin.cfg = cfg;
2468  api = GNUNET_new (struct GNUNET_REST_Plugin);
2469  api->cls = &plugin;
2473  "%s, %s, %s, %s, %s",
2474  MHD_HTTP_METHOD_GET,
2475  MHD_HTTP_METHOD_POST,
2476  MHD_HTTP_METHOD_PUT,
2477  MHD_HTTP_METHOD_DELETE,
2478  MHD_HTTP_METHOD_OPTIONS);
2479 
2481  _ ("OpenID Connect REST API initialized\n"));
2482  return api;
2483 }
2484 
2485 
2492 void *
2494 {
2495  struct GNUNET_REST_Plugin *api = cls;
2496  struct Plugin *plugin = api->cls;
2497 
2498  plugin->cfg = NULL;
2499 
2500  struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2501  void *value = NULL;
2502  hashmap_it =
2503  GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_cookie_jar_map);
2504  while (GNUNET_YES ==
2506  value))
2507  GNUNET_free (value);
2509  GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map);
2510 
2511  hashmap_it =
2512  GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_access_token_map);
2513  while (GNUNET_YES ==
2515  value))
2516  GNUNET_free (value);
2517  GNUNET_CONTAINER_multihashmap_destroy (OIDC_access_token_map);
2520  GNUNET_free (api);
2522  "OpenID Connect REST plugin is finished\n");
2523  return NULL;
2524 }
2525 
2526 
2527 /* 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:566
static void build_redirect(void *cls)
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static int iterator(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Iterator over hash map entries.
struct GNUNET_RECLAIM_AttributeList * attr_userinfo_list
Attribute claim list for userinfo.
Connection to the GNS service.
Definition: gns_api.h:35
void GNUNET_CONTAINER_multihashmap_iterator_destroy(struct GNUNET_CONTAINER_MultiHashMapIterator *iter)
Destroy a multihashmap iterator.
char * redirect_uri
The OIDC redirect uri.
char * scope
The list of oidc scopes.
Handle to the service.
Definition: reclaim_api.c:312
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:1293
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.
char * OIDC_id_token_new(const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, struct GNUNET_RECLAIM_AttributeList *attrs, struct GNUNET_RECLAIM_AttestationList *attests, const struct GNUNET_TIME_Relative *expiration_time, const char *nonce, const char *secret_key)
Create a JWT from attributes.
Definition: oidc_helper.c:124
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_AttributeTicketResult cb, void *cb_cls)
Consumes an issued ticket.
Definition: reclaim_api.c:1553
struct EgoEntry * ego_tail
Ego list.
struct GNUNET_RECLAIM_AttestationIterator * GNUNET_RECLAIM_get_attestations_start(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls, GNUNET_RECLAIM_AttestationResult proc, void *proc_cls, GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls)
List all attestations for a local identity.
Definition: reclaim_api.c:1402
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.
static struct GNUNET_RECLAIM_AttributeList * attribute_list_merge(struct GNUNET_RECLAIM_AttributeList *list_a, struct GNUNET_RECLAIM_AttributeList *list_b)
char * nonce
The OIDC nonce.
void GNUNET_RECLAIM_attribute_list_destroy(struct GNUNET_RECLAIM_AttributeList *attrs)
Destroy claim list.
#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.
void GNUNET_RECLAIM_attestation_list_destroy(struct GNUNET_RECLAIM_AttestationList *attestations)
Destroy claim list.
#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE
OIDC expected response_type while authorizing.
char * OIDC_build_authz_code(const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, const struct GNUNET_RECLAIM_Ticket *ticket, struct GNUNET_RECLAIM_AttributeList *attrs, struct GNUNET_RECLAIM_AttestationList *attests, const char *nonce_str, const char *code_challenge)
Builds an OIDC authorization code including a reclaim ticket and nonce.
Definition: oidc_helper.c:424
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.
size_t data_size
The POST data size.
struct GNUNET_RECLAIM_AttributeIterator * attr_it
Attribute iterator.
const char * name
The name of the attribute.
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.
struct GNUNET_RECLAIM_AttestationIterator * attest_it
Attestation iterator.
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.
#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:595
void GNUNET_RECLAIM_disconnect(struct GNUNET_RECLAIM_Handle *h)
Disconnect from identity provider service.
Definition: reclaim_api.c:1066
#define OIDC_COOKIE_EXPIRATION
OIDC cookie expiration (in seconds)
void GNUNET_RECLAIM_cancel(struct GNUNET_RECLAIM_Operation *op)
Cancel an identity provider operation.
Definition: reclaim_api.c:1051
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
struct returned by the initialization function of the plugin
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.
struct GNUNET_RECLAIM_Attestation * attestation
The attestation.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
helper library for OIDC related functions
#define OIDC_COOKIE_HEADER_INFORMATION_KEY
OIDC cookie header information key.
A list of GNUNET_RECLAIM_Attribute structures.
void GNUNET_RECLAIM_ticket_iteration_stop(struct GNUNET_RECLAIM_TicketIterator *it)
Stops iteration and releases the handle for further calls.
Definition: reclaim_api.c:1661
size_t data_size
Number of bytes in data.
A list of GNUNET_RECLAIM_Attestation structures.
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:1339
#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.
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:732
#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.
void GNUNET_RECLAIM_get_attestations_next(struct GNUNET_RECLAIM_AttestationIterator *ait)
Calls the record processor specified in #GNUNET_RECLAIM_get_attestation_start for the next record...
Definition: reclaim_api.c:1449
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_Attribute * attribute
The attribute 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:184
static char * section
Name of the section.
Definition: gnunet-config.c:33
#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.
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.
struct GNUNET_RECLAIM_Identifier attestation
Referenced ID of Attestation (may be 0 if self-attested)
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.
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:1269
Handle for an ego.
Definition: identity.h:245
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_AttributeList **attrs, struct GNUNET_RECLAIM_AttestationList **attests, char **nonce_str)
Parse reclaim ticket and nonce from authorization code.
Definition: oidc_helper.c:580
Handle for a attribute iterator operation.
Definition: reclaim_api.c:177
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.
static void oidc_attr_collect(void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, const struct GNUNET_RECLAIM_Attribute *attr)
Collects all attributes for an ego if in scope parameter.
struct GNUNET_CONTAINER_MultiHashMap * url_param_map
Map of url parameters.
static char * attr_name
The attribute.
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_RECLAIM_AttributeListEntry * list_tail
List tail.
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:1296
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_TicketIterator * ticket_it
Ticket iterator.
char * tld
The tld for redirect.
static int attr_in_userinfo_request(struct RequestHandle *handle, const char *attr_name)
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 void consume_ticket(void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, const struct GNUNET_RECLAIM_Attribute *attr, const struct GNUNET_RECLAIM_Attestation *attest)
Collects claims and stores them in handle.
static struct GNUNET_IDENTITY_Handle * identity_handle
Identity handle.
#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".
static void oidc_attest_collect(void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, const struct GNUNET_RECLAIM_Attestation *attest)
Collects all attributes for an ego if in scope parameter.
void GNUNET_IDENTITY_disconnect(struct GNUNET_IDENTITY_Handle *h)
Disconnect from identity service.
Definition: identity_api.c:884
struct GNUNET_RECLAIM_Identifier id
ID.
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
size_t data_size
Number of bytes in data.
#define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE
OIDC error key for unsupported response types.
#define OIDC_CODE_VERIFIER_KEY
OIDC PKCE code verifier.
size_t data_size
Number of bytes in data.
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.
struct GNUNET_RECLAIM_Attestation * GNUNET_RECLAIM_attestation_new(const char *name, uint32_t type, const void *data, size_t data_size)
Create a new attestation.
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:1976
const char * name
The name of the attribute.
struct GNUNET_RECLAIM_Identifier id
ID.
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:232
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)
uint32_t type
Type/Format of Claim.
char * keystring
Public key string.
static void oidc_attest_collect_finished_cb(void *cls)
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...
static void return_userinfo_response(void *cls)
Return attributes for claim.
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:176
#define OIDC_ERROR_KEY_ACCESS_DENIED
OIDC error key for denied access.
struct GNUNET_RECLAIM_AttestationListEntry * list_head
List head.
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.
struct GNUNET_RECLAIM_AttributeListEntry * next
DLL.
#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.
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.
struct GNUNET_RECLAIM_Attribute * GNUNET_RECLAIM_attribute_new(const char *attr_name, const struct GNUNET_RECLAIM_Identifier *attestation, uint32_t type, const void *data, size_t data_size)
Create a new attribute claim.
#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.
static void client_redirect(void *cls)
Initiate redirect back to client.
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.
const void * data
Binary value stored as attribute value.
#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 struct GNUNET_RECLAIM_Identifier attestation
Attestation ID.
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:760
struct GNUNET_RECLAIM_AttestationListEntry * list_tail
List tail.
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:366
struct GNUNET_GNS_Handle * gns_handle
GNS handle.
configuration data
Definition: configuration.c:84
struct EgoEntry * ego_head
Ego list.
static int attr_in_claims_request(struct RequestHandle *handle, const char *attr_name, const char *claims_parameter)
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:1360
Handle for a attestation iterator operation.
Definition: reclaim_api.c:244
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.
struct GNUNET_RECLAIM_AttestationList * attests_list
Attestation list.
#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...
#define GNUNET_RECLAIM_id_is_equal(a, b)
Handle for a ticket iterator operation.
Definition: reclaim_api.c:114
#define GNUNET_log(kind,...)
const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration handle.
Entry in list of pending tasks.
Definition: scheduler.c:134
struct GNUNET_RECLAIM_AttributeList * attr_idtoken_list
Attribute claim list for id_token.
const void * data
Binary value stored as attribute value.
#define OIDC_SCOPE_KEY
OIDC scope key.
static int attr_in_idtoken_request(struct RequestHandle *handle, const char *attr_name)
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.
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.
#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.
uint32_t type
Type of Claim.
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.
Time for absolute times used by GNUnet, in microseconds.
json_t * response
The response JSON.
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.
struct GNUNET_RECLAIM_AttestationListEntry * next
DLL.
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:935
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 * 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:1026
uint32_t data
The data value.
#define OIDC_COOKIE_HEADER_KEY
OIDC cookie header key.
void GNUNET_IDENTITY_ego_get_public_key(struct GNUNET_IDENTITY_Ego *ego, struct GNUNET_CRYPTO_EcdsaPublicKey *pk)
Get the identifier (public key) of an ego.
Definition: identity_api.c:608
struct EgoEntry * next
DLL.
#define GNUNET_REST_API_NS_USERINFO
UserInfo endpoint.
void GNUNET_RECLAIM_get_attestations_stop(struct GNUNET_RECLAIM_AttestationIterator *ait)
Stops iteration and releases the handle for further calls.
Definition: reclaim_api.c:1471
struct GNUNET_RECLAIM_AttributeListEntry * list_head
List head.
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:970
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_AttributeList *attrs, GNUNET_RECLAIM_TicketCallback cb, void *cb_cls)
Issues a ticket to a relying party.
Definition: reclaim_api.c:1504
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.
static void oidc_attr_collect_finished_cb(void *cls)
#define OIDC_ERROR_KEY_INVALID_SCOPE
OIDC error key for invalid scopes.
#define GNUNET_RECLAIM_id_is_zero(a)
#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:972
char * url
The url.