GNUnet  0.19.2
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  */
28 #include "platform.h"
29 #include <inttypes.h>
30 #include <jansson.h>
31 #include <jose/jose.h>
32 
33 #include "gnunet_util_lib.h"
34 #include "gnunet_gns_service.h"
35 #include "gnunet_gnsrecord_lib.h"
38 #include "gnunet_reclaim_lib.h"
39 #include "gnunet_reclaim_service.h"
40 #include "gnunet_rest_lib.h"
41 #include "gnunet_rest_plugin.h"
42 #include "gnunet_signatures.h"
43 #include "microhttpd.h"
44 #include "oidc_helper.h"
45 
49 #define GNUNET_REST_API_NS_OIDC "/openid"
50 
54 #define GNUNET_REST_API_NS_OIDC_CONFIG "/.well-known/openid-configuration"
55 
59 #define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize"
60 
64 #define GNUNET_REST_API_NS_TOKEN "/openid/token"
65 
69 #define GNUNET_REST_API_JWKS "/jwks.json"
70 
74 #define GNUNET_REST_API_NS_USERINFO "/openid/userinfo"
75 
79 #define GNUNET_REST_API_NS_LOGIN "/openid/login"
80 
84 #define ID_REST_STATE_INIT 0
85 
89 #define ID_REST_STATE_POST_INIT 1
90 
94 #define OIDC_GRANT_TYPE_KEY "grant_type"
95 
99 #define OIDC_GRANT_TYPE_VALUE "authorization_code"
100 
104 #define OIDC_CODE_KEY "code"
105 
109 #define OIDC_RESPONSE_TYPE_KEY "response_type"
110 
114 #define OIDC_CLIENT_ID_KEY "client_id"
115 
119 #define OIDC_SCOPE_KEY "scope"
120 
124 #define OIDC_REDIRECT_URI_KEY "redirect_uri"
125 
129 #define OIDC_STATE_KEY "state"
130 
134 #define OIDC_NONCE_KEY "nonce"
135 
139 #define OIDC_CLAIMS_KEY "claims"
140 
144 #define OIDC_CODE_CHALLENGE_KEY "code_challenge"
145 
149 #define OIDC_CODE_VERIFIER_KEY "code_verifier"
150 
154 #define OIDC_COOKIE_EXPIRATION 3
155 
159 #define OIDC_COOKIE_HEADER_KEY "cookie"
160 
164 #define OIDC_AUTHORIZATION_HEADER_KEY "authorization"
165 
169 #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
170 
174 #define OIDC_COOKIE_HEADER_ACCESS_DENIED "Identity=Denied"
175 
179 #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
180 
184 #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
185 
189 #define OIDC_ERROR_KEY_INVALID_CLIENT "invalid_client"
190 
194 #define OIDC_ERROR_KEY_INVALID_SCOPE "invalid_scope"
195 
199 #define OIDC_ERROR_KEY_INVALID_REQUEST "invalid_request"
200 
204 #define OIDC_ERROR_KEY_INVALID_TOKEN "invalid_token"
205 
209 #define OIDC_ERROR_KEY_INVALID_COOKIE "invalid_cookie"
210 
214 #define OIDC_ERROR_KEY_SERVER_ERROR "server_error"
215 
219 #define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE "unsupported_grant_type"
220 
224 #define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE "unsupported_response_type"
225 
229 #define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT "unauthorized_client"
230 
234 #define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied"
235 
239 #define OIDC_JWK_RSA_FILENAME "jwk_rsa.json"
240 
244 #define CONSUME_TIMEOUT GNUNET_TIME_relative_multiply ( \
245  GNUNET_TIME_UNIT_SECONDS,2)
246 
250 static char *OIDC_ignored_parameter_array[] = { "display",
251  "prompt",
252  "ui_locales",
253  "response_mode",
254  "id_token_hint",
255  "login_hint",
256  "acr_values" };
257 
262 
267 
272 
276 static char *allow_methods;
277 
281 static struct EgoEntry *ego_head;
282 
286 static struct EgoEntry *ego_tail;
287 
291 static int state;
292 
297 
302 
306 static struct GNUNET_RECLAIM_Handle *idp;
307 
312 
316 struct Plugin
317 {
319 };
320 
324 json_t *oidc_jwk;
325 
330 {
335 
339  char *client_id;
340 
345 
349  char *scope;
350 
354  char *state;
355 
359  char *nonce;
360 
364  char *claims;
365 
370 
375 
380 
385 
390 
391 };
392 
396 struct EgoEntry
397 {
401  struct EgoEntry *next;
402 
406  struct EgoEntry *prev;
407 
411  char *identifier;
412 
416  char *keystring;
417 
421  struct GNUNET_IDENTITY_Ego *ego;
422 };
423 
424 
425 struct RequestHandle
426 {
430  struct RequestHandle *next;
431 
435  struct RequestHandle *prev;
436 
441 
446 
451 
456 
461 
466 
471 
476 
481 
486 
487 
492 
497 
502 
507 
508 
513 
518 
523 
528 
533 
537  void *proc_cls;
538 
542  char *url;
543 
548 
552  char *tld;
553 
558 
563 
567  char *emsg;
568 
572  char *edesc;
573 
577  int response_code;
578 
583 };
584 
589 
594 
595 
600 static void
602 {
603 
604  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
605  if (NULL != handle->timeout_task)
606  GNUNET_SCHEDULER_cancel (handle->timeout_task);
607  if (NULL != handle->attr_it)
609  if (NULL != handle->cred_it)
611  if (NULL != handle->ticket_it)
613  if (NULL != handle->idp_op)
614  GNUNET_RECLAIM_cancel (handle->idp_op);
615  if (NULL != handle->consume_timeout_op)
616  GNUNET_SCHEDULER_cancel (handle->consume_timeout_op);
617  GNUNET_free (handle->url);
618  GNUNET_free (handle->tld);
619  GNUNET_free (handle->redirect_prefix);
620  GNUNET_free (handle->redirect_suffix);
621  GNUNET_free (handle->emsg);
622  GNUNET_free (handle->edesc);
623  if (NULL != handle->gns_op)
625  if (NULL != handle->oidc)
626  {
627  GNUNET_free (handle->oidc->client_id);
628  GNUNET_free (handle->oidc->login_identity);
629  GNUNET_free (handle->oidc->nonce);
630  GNUNET_free (handle->oidc->redirect_uri);
631  GNUNET_free (handle->oidc->response_type);
632  GNUNET_free (handle->oidc->scope);
633  GNUNET_free (handle->oidc->state);
634  if (NULL != handle->oidc->claims)
635  GNUNET_free (handle->oidc->claims);
636  if (NULL != handle->oidc->code_challenge)
637  GNUNET_free (handle->oidc->code_challenge);
638  GNUNET_free (handle->oidc);
639  }
640  if (NULL!=handle->attr_idtoken_list)
641  GNUNET_RECLAIM_attribute_list_destroy (handle->attr_idtoken_list);
642  if (NULL!=handle->attr_userinfo_list)
643  GNUNET_RECLAIM_attribute_list_destroy (handle->attr_userinfo_list);
644  if (NULL!=handle->credentials)
646  if (NULL!=handle->presentations)
650  handle);
651  if (NULL != handle->access_token)
652  GNUNET_free (handle->access_token);
654 }
655 
656 
662 static void
663 do_error (void *cls)
664 {
665  struct RequestHandle *handle = cls;
666  struct MHD_Response *resp;
667  char *json_error;
668 
669  GNUNET_asprintf (&json_error,
670  "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
671  handle->emsg,
672  (NULL != handle->edesc) ? handle->edesc : "",
673  (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
674  (NULL != handle->oidc->state) ? handle->oidc->state : "",
675  (NULL != handle->oidc->state) ? "\"" : "");
676  if (0 == handle->response_code)
677  handle->response_code = MHD_HTTP_BAD_REQUEST;
678  resp = GNUNET_REST_create_response (json_error);
679  if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
680  GNUNET_assert (MHD_NO !=
681  MHD_add_response_header (resp,
682  MHD_HTTP_HEADER_WWW_AUTHENTICATE,
683  "Basic"));
684  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
685  MHD_HTTP_HEADER_CONTENT_TYPE,
686  "application/json"));
687  handle->proc (handle->proc_cls, resp, handle->response_code);
689  GNUNET_free (json_error);
690 }
691 
692 
699 static void
700 do_userinfo_error (void *cls)
701 {
702  struct RequestHandle *handle = cls;
703  struct MHD_Response *resp;
704  char *error;
705 
707  "Error: %s\n", handle->edesc);
708  GNUNET_asprintf (&error,
709  "error=\"%s\", error_description=\"%s\"",
710  handle->emsg,
711  (NULL != handle->edesc) ? handle->edesc : "");
712  resp = GNUNET_REST_create_response ("");
713  GNUNET_assert (MHD_NO !=
714  MHD_add_response_header (resp,
715  MHD_HTTP_HEADER_WWW_AUTHENTICATE,
716  "Bearer"));
717  handle->proc (handle->proc_cls, resp, handle->response_code);
719  GNUNET_free (error);
720 }
721 
722 
728 static void
729 do_redirect_error (void *cls)
730 {
731  struct RequestHandle *handle = cls;
732  struct MHD_Response *resp;
733  char *redirect;
734 
735  GNUNET_asprintf (&redirect,
736  "%s?error=%s&error_description=%s%s%s",
737  handle->oidc->redirect_uri,
738  handle->emsg,
739  handle->edesc,
740  (NULL != handle->oidc->state) ? "&state=" : "",
741  (NULL != handle->oidc->state) ? handle->oidc->state : "");
742  resp = GNUNET_REST_create_response ("");
743  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
744  "Location", redirect));
745  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
747  GNUNET_free (redirect);
748 }
749 
750 
756 static void
757 do_timeout (void *cls)
758 {
759  struct RequestHandle *handle = cls;
760 
761  handle->timeout_task = NULL;
762  do_error (handle);
763 }
764 
765 
773 static void
775  const char *url,
776  void *cls)
777 {
778  struct MHD_Response *resp;
779  struct RequestHandle *handle = cls;
780 
781  // For now, independent of path return all options
782  resp = GNUNET_REST_create_response (NULL);
783  MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
784  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
786  return;
787 }
788 
789 
793 static void
795 {
796  struct GNUNET_HashCode cache_key;
797  char *cookies;
798  struct GNUNET_TIME_Absolute current_time, *relog_time;
799  char delimiter[] = "; ";
800  char *tmp_cookies;
801  char *token;
802  char *value;
803 
804  // gets identity of login try with cookie
806  strlen (OIDC_COOKIE_HEADER_KEY),
807  &cache_key);
809  ->header_param_map,
810  &cache_key))
811  {
812  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cookie found\n");
813  return;
814  }
815  // splits cookies and find 'Identity' cookie
816  tmp_cookies =
817  GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
818  &cache_key);
819  cookies = GNUNET_strdup (tmp_cookies);
820  token = strtok (cookies, delimiter);
821  handle->oidc->user_cancelled = GNUNET_NO;
822  handle->oidc->login_identity = NULL;
823  if (NULL == token)
824  {
826  "Unable to parse cookie: %s\n",
827  cookies);
828  GNUNET_free (cookies);
829  return;
830  }
831 
832  while (NULL != token)
833  {
834  if (0 == strcmp (token, OIDC_COOKIE_HEADER_ACCESS_DENIED))
835  {
836  handle->oidc->user_cancelled = GNUNET_YES;
837  GNUNET_free (cookies);
838  return;
839  }
840  if (NULL != strstr (token, OIDC_COOKIE_HEADER_INFORMATION_KEY))
841  break;
842  token = strtok (NULL, delimiter);
843  }
844  if (NULL == token)
845  {
847  "No cookie value to process: %s\n",
848  cookies);
849  GNUNET_free (cookies);
850  return;
851  }
852  GNUNET_CRYPTO_hash (token, strlen (token), &cache_key);
853  if (GNUNET_NO ==
855  {
856  GNUNET_log (
858  "Found cookie `%s', but no corresponding expiration entry present...\n",
859  token);
860  GNUNET_free (cookies);
861  return;
862  }
863  relog_time =
865  current_time = GNUNET_TIME_absolute_get ();
866  // 30 min after old login -> redirect to login
867  if (current_time.abs_value_us > relog_time->abs_value_us)
868  {
870  "Found cookie `%s', but it is expired.\n",
871  token);
872  GNUNET_free (cookies);
873  return;
874  }
875  value = strtok (token, OIDC_COOKIE_HEADER_INFORMATION_KEY);
876  GNUNET_assert (NULL != value);
877  handle->oidc->login_identity = GNUNET_strdup (value);
878  GNUNET_free (cookies);
879 }
880 
881 
890 json_t *
892 {
893  json_t *jwk;
894  json_error_t error;
895 
896  jwk = json_load_file (filename, JSON_DECODE_ANY, &error);
897 
898  if (! jwk)
899  {
901  ("Could not read OIDC RSA key from config file; %s\n"),
902  error.text);
903  }
904 
905  return jwk;
906 }
907 
915 static int
917  json_t *jwk)
918 {
919  if (json_dump_file (jwk, filename, JSON_INDENT (2)))
920  {
922  ("Could not write OIDC RSA key to file %s\n"),
923  filename);
925  }
926  else
927  return GNUNET_OK;
928 }
929 
935 json_t *
937 {
938  json_t *jwk;
939  jwk = json_pack ("{s:s,s:i}", "kty", "RSA", "bits", 2048);
940  jose_jwk_gen (NULL, jwk);
941  json_incref (jwk);
942  return jwk;
943 }
944 
950 char *
951 get_oidc_dir_path (void *cls)
952 {
953  char *oidc_directory;
954  struct RequestHandle *handle = cls;
955 
956  // Read OIDC directory from config
958  "reclaim-rest-plugin",
959  "oidc_dir",
960  &oidc_directory))
961  {
962  // Could not read Config file
964  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
965  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
967  return NULL;
968  }
969 
970  return oidc_directory;
971 }
972 
978 char *
979 get_oidc_jwk_path (void *cls)
980 {
981  char *oidc_directory;
982  char *oidc_jwk_path;
983 
984  oidc_directory = get_oidc_dir_path (cls);
985 
986  // Create path to file
987  GNUNET_asprintf (&oidc_jwk_path, "%s/%s", oidc_directory,
989 
990  return oidc_jwk_path;
991 }
992 
993 
997 static void
998 login_redirect (void *cls)
999 {
1000  char *login_base_url;
1001  char *new_redirect;
1002  char *tmp;
1003  struct MHD_Response *resp;
1004  struct GNUNET_Buffer buf = { 0 };
1005  struct RequestHandle *handle = cls;
1006 
1008  "reclaim-rest-plugin",
1009  "address",
1010  &login_base_url))
1011  {
1012  GNUNET_buffer_write_str (&buf, login_base_url);
1014  "?%s=%s",
1016  handle->oidc->response_type);
1018  "&%s=%s",
1020  handle->oidc->client_id);
1021  GNUNET_STRINGS_urlencode (handle->oidc->redirect_uri,
1022  strlen (handle->oidc->redirect_uri),
1023  &tmp);
1025  "&%s=%s",
1027  tmp);
1028  GNUNET_free (tmp);
1029  GNUNET_STRINGS_urlencode (handle->oidc->scope,
1030  strlen (handle->oidc->scope),
1031  &tmp);
1033  "&%s=%s",
1035  tmp);
1036  GNUNET_free (tmp);
1037  if (NULL != handle->oidc->state)
1038  {
1039  GNUNET_STRINGS_urlencode (handle->oidc->state,
1040  strlen (handle->oidc->state),
1041  &tmp);
1043  "&%s=%s",
1045  handle->oidc->state);
1046  GNUNET_free (tmp);
1047  }
1048  if (NULL != handle->oidc->code_challenge)
1049  {
1051  "&%s=%s",
1053  handle->oidc->code_challenge);
1054  }
1055  if (NULL != handle->oidc->nonce)
1056  {
1058  "&%s=%s",
1060  handle->oidc->nonce);
1061  }
1062  if (NULL != handle->oidc->claims)
1063  {
1064  GNUNET_STRINGS_urlencode (handle->oidc->claims,
1065  strlen (handle->oidc->claims),
1066  &tmp);
1068  "&%s=%s",
1070  tmp);
1071  GNUNET_free (tmp);
1072  }
1073  new_redirect = GNUNET_buffer_reap_str (&buf);
1074  resp = GNUNET_REST_create_response ("");
1075  MHD_add_response_header (resp, "Location", new_redirect);
1076  GNUNET_free (login_base_url);
1077  }
1078  else
1079  {
1081  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1082  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1084  return;
1085  }
1086  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1087  GNUNET_free (new_redirect);
1089 }
1090 
1091 
1095 static void
1097 {
1098  struct RequestHandle *handle = cls;
1099 
1101  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1103 }
1104 
1105 
1110 static void
1112  const struct GNUNET_RECLAIM_Ticket *ticket,
1113  const struct
1114  GNUNET_RECLAIM_PresentationList *presentation)
1115 {
1116  struct RequestHandle *handle = cls;
1117  struct MHD_Response *resp;
1118  char *ticket_str;
1119  char *redirect_uri;
1120  char *code_string;
1121 
1122  handle->idp_op = NULL;
1123  if (NULL == ticket)
1124  {
1126  handle->edesc = GNUNET_strdup ("Server cannot generate ticket.");
1128  return;
1129  }
1130  handle->ticket = *ticket;
1131  ticket_str =
1133  sizeof(struct GNUNET_RECLAIM_Ticket));
1134  code_string = OIDC_build_authz_code (&handle->priv_key,
1135  &handle->ticket,
1136  handle->attr_idtoken_list,
1137  presentation,
1138  handle->oidc->nonce,
1139  handle->oidc->code_challenge);
1140  if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
1141  (NULL != handle->tld))
1142  {
1143  GNUNET_asprintf (&redirect_uri,
1144  "%s.%s/%s%s%s=%s&state=%s",
1145  handle->redirect_prefix,
1146  handle->tld,
1147  handle->redirect_suffix,
1148  (NULL == strchr (handle->redirect_suffix, '?') ? "?" :
1149  "&"),
1150  handle->oidc->response_type,
1151  code_string,
1152  handle->oidc->state);
1153  }
1154  else
1155  {
1156  GNUNET_asprintf (&redirect_uri,
1157  "%s%s%s=%s&state=%s",
1158  handle->oidc->redirect_uri,
1159  (NULL == strchr (handle->oidc->redirect_uri, '?') ? "?" :
1160  "&"),
1161  handle->oidc->response_type,
1162  code_string,
1163  handle->oidc->state);
1164  }
1165  resp = GNUNET_REST_create_response ("");
1166  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
1167  "Location", redirect_uri));
1168  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1170  GNUNET_free (redirect_uri);
1171  GNUNET_free (ticket_str);
1172  GNUNET_free (code_string);
1173 }
1174 
1175 
1176 static struct GNUNET_RECLAIM_AttributeList*
1178  struct GNUNET_RECLAIM_AttributeList *list_b)
1179 {
1180  struct GNUNET_RECLAIM_AttributeList *merged_list;
1181  struct GNUNET_RECLAIM_AttributeListEntry *le_a;
1182  struct GNUNET_RECLAIM_AttributeListEntry *le_b;
1183  struct GNUNET_RECLAIM_AttributeListEntry *le_m;
1184 
1185  merged_list = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
1186  for (le_a = list_a->list_head; NULL != le_a; le_a = le_a->next)
1187  {
1190  &le_a->attribute->
1191  credential,
1192  le_a->attribute->type,
1193  le_a->attribute->data,
1194  le_a->attribute->data_size);
1195  le_m->attribute->id = le_a->attribute->id;
1196  le_m->attribute->flag = le_a->attribute->flag;
1197  le_m->attribute->credential = le_a->attribute->credential;
1198  GNUNET_CONTAINER_DLL_insert (merged_list->list_head,
1199  merged_list->list_tail,
1200  le_m);
1201  }
1202  le_m = NULL;
1203  for (le_b = list_b->list_head; NULL != le_b; le_b = le_b->next)
1204  {
1205  for (le_m = merged_list->list_head; NULL != le_m; le_m = le_m->next)
1206  {
1208  &le_b->attribute->id))
1209  break;
1210  }
1211  if (NULL != le_m)
1212  continue;
1215  &le_b->attribute->
1216  credential,
1217  le_b->attribute->type,
1218  le_b->attribute->data,
1219  le_b->attribute->data_size);
1220  le_m->attribute->id = le_b->attribute->id;
1221  le_m->attribute->flag = le_b->attribute->flag;
1222  le_m->attribute->credential = le_b->attribute->credential;
1223  GNUNET_CONTAINER_DLL_insert (merged_list->list_head,
1224  merged_list->list_tail,
1225  le_m);
1226  }
1227  return merged_list;
1228 }
1229 
1230 
1231 static void
1233 {
1234  struct RequestHandle *handle = cls;
1235  struct GNUNET_RECLAIM_AttributeList *merged_list;
1236  struct GNUNET_RECLAIM_AttributeListEntry *le_m;
1237 
1238  handle->cred_it = NULL;
1239  merged_list = attribute_list_merge (handle->attr_idtoken_list,
1240  handle->attr_userinfo_list);
1241  for (le_m = merged_list->list_head; NULL != le_m; le_m = le_m->next)
1243  "List Attribute in ticket to issue: %s\n",
1244  le_m->attribute->name);
1246  &handle->priv_key,
1247  &handle->oidc->client_pkey,
1248  merged_list,
1250  handle);
1252 }
1253 
1254 
1258 static void
1260  const struct GNUNET_IDENTITY_PublicKey *identity,
1261  const struct GNUNET_RECLAIM_Credential *cred)
1262 {
1263  struct RequestHandle *handle = cls;
1266 
1267  for (ale = handle->credentials->list_head; NULL != ale; ale = ale->next)
1268  {
1270  &cred->id))
1271  continue;
1274  return;
1275  }
1276 
1277  for (le = handle->attr_idtoken_list->list_head; NULL != le; le = le->next)
1278  {
1280  &cred->id))
1281  continue;
1285  cred->type,
1286  cred->data,
1287  cred->data_size);
1288  GNUNET_CONTAINER_DLL_insert (handle->credentials->list_head,
1289  handle->credentials->list_tail,
1290  ale);
1291  }
1293 }
1294 
1295 
1296 static void
1298 {
1299  struct RequestHandle *handle = cls;
1300 
1301  handle->attr_it = NULL;
1302  handle->ticket_it = NULL;
1303  if (NULL == handle->attr_idtoken_list->list_head)
1304  {
1306  handle->edesc = GNUNET_strdup ("The requested scope is not available.");
1308  return;
1309  }
1310  handle->credentials = GNUNET_new (struct GNUNET_RECLAIM_CredentialList);
1311  handle->cred_it =
1313  &handle->priv_key,
1315  handle,
1317  handle,
1319  handle);
1320 
1321 }
1322 
1323 
1324 static int
1326  const char *attr_name,
1327  const char *claims_parameter)
1328 {
1329  int ret = GNUNET_NO;
1330  json_t *root;
1331  json_error_t error;
1332  json_t *claims_j;
1333  const char *key;
1334  json_t *value;
1335 
1338  attr_name))
1339  return GNUNET_YES;
1340 
1342  if (NULL != handle->oidc->claims)
1343  {
1344  root = json_loads (handle->oidc->claims, JSON_DECODE_ANY, &error);
1345  claims_j = json_object_get (root, claims_parameter);
1346  /* obj is a JSON object */
1347  if (NULL != claims_j)
1348  {
1349  json_object_foreach (claims_j, key, value) {
1350  if (0 != strcmp (attr_name, key))
1351  continue;
1352  ret = GNUNET_YES;
1353  break;
1354  }
1355  }
1356  json_decref (root);
1357  }
1358  return ret;
1359 }
1360 
1361 
1362 static int
1364  const char *attr_name)
1365 {
1366  return attr_in_claims_request (handle, attr_name, "id_token");
1367 }
1368 
1369 
1370 static int
1372  const char *attr_name)
1373 {
1374  return attr_in_claims_request (handle, attr_name, "userinfo");
1375 }
1376 
1377 
1381 static void
1383  const struct GNUNET_IDENTITY_PublicKey *identity,
1384  const struct GNUNET_RECLAIM_Attribute *attr)
1385 {
1386  struct RequestHandle *handle = cls;
1389  {
1392  &attr->credential,
1393  attr->type,
1394  attr->data,
1395  attr->data_size);
1396  le->attribute->id = attr->id;
1397  le->attribute->flag = attr->flag;
1398  le->attribute->credential = attr->credential;
1399  GNUNET_CONTAINER_DLL_insert (handle->attr_idtoken_list->list_head,
1400  handle->attr_idtoken_list->list_tail,
1401  le);
1402  }
1404  {
1407  &attr->credential,
1408  attr->type,
1409  attr->data,
1410  attr->data_size);
1411  le->attribute->id = attr->id;
1412  le->attribute->flag = attr->flag;
1413  le->attribute->credential = attr->credential;
1414  GNUNET_CONTAINER_DLL_insert (handle->attr_userinfo_list->list_head,
1415  handle->attr_userinfo_list->list_tail,
1416  le);
1417  }
1418 
1420 }
1421 
1422 
1426 static void
1427 code_redirect (void *cls)
1428 {
1429  struct RequestHandle *handle = cls;
1430  struct GNUNET_TIME_Absolute current_time;
1431  struct GNUNET_TIME_Absolute *relog_time;
1433  struct GNUNET_IDENTITY_PublicKey ego_pkey;
1434  struct GNUNET_HashCode cache_key;
1435  char *identity_cookie;
1436 
1437  GNUNET_asprintf (&identity_cookie,
1438  "Identity=%s",
1439  handle->oidc->login_identity);
1440  GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1441  GNUNET_free (identity_cookie);
1442  // No login time for identity -> redirect to login
1443  if (GNUNET_YES ==
1445  {
1446  relog_time =
1448  current_time = GNUNET_TIME_absolute_get ();
1449  // 30 min after old login -> redirect to login
1450  if (current_time.abs_value_us <= relog_time->abs_value_us)
1451  {
1452  if (GNUNET_OK !=
1454  ->login_identity,
1455  &pubkey))
1456  {
1458  handle->edesc =
1459  GNUNET_strdup ("The cookie of a login identity is not valid");
1461  return;
1462  }
1463  // iterate over egos and compare their public key
1464  for (handle->ego_entry = ego_head; NULL != handle->ego_entry;
1465  handle->ego_entry = handle->ego_entry->next)
1466  {
1467  GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1468  if (0 == GNUNET_memcmp (&ego_pkey, &pubkey))
1469  {
1470  handle->priv_key =
1471  *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1472  handle->attr_idtoken_list =
1474  handle->attr_userinfo_list =
1476  handle->attr_it =
1478  &handle->priv_key,
1480  handle,
1482  handle,
1484  handle);
1485  return;
1486  }
1487  }
1489  return;
1490  }
1491  }
1492 }
1493 
1494 
1495 static void
1496 build_redirect (void *cls)
1497 {
1498  struct RequestHandle *handle = cls;
1499  struct MHD_Response *resp;
1500  char *redirect_uri;
1501 
1502  if (GNUNET_YES == handle->oidc->user_cancelled)
1503  {
1504  if ((NULL != handle->redirect_prefix) &&
1505  (NULL != handle->redirect_suffix) && (NULL != handle->tld))
1506  {
1507  GNUNET_asprintf (&redirect_uri,
1508  "%s.%s/%s?error=%s&error_description=%s&state=%s",
1509  handle->redirect_prefix,
1510  handle->tld,
1511  handle->redirect_suffix,
1512  "access_denied",
1513  "User denied access",
1514  handle->oidc->state);
1515  }
1516  else
1517  {
1518  GNUNET_asprintf (&redirect_uri,
1519  "%s?error=%s&error_description=%s&state=%s",
1520  handle->oidc->redirect_uri,
1521  "access_denied",
1522  "User denied access",
1523  handle->oidc->state);
1524  }
1525  resp = GNUNET_REST_create_response ("");
1526  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
1527  "Location",
1528  redirect_uri));
1529  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1531  GNUNET_free (redirect_uri);
1532  return;
1533  }
1535 }
1536 
1537 
1538 static void
1540  uint32_t rd_count,
1541  const struct GNUNET_GNSRECORD_Data *rd)
1542 {
1543  struct RequestHandle *handle = cls;
1544  char *tmp;
1545  char *tmp_key_str;
1546  char *pos;
1547  struct GNUNET_IDENTITY_PublicKey redirect_zone;
1548 
1549  handle->gns_op = NULL;
1550  if (0 == rd_count)
1551  {
1553  handle->edesc =
1554  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1556  return;
1557  }
1558  for (int i = 0; i < rd_count; i++)
1559  {
1560  if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type)
1561  continue;
1562  if (0 != strncmp (rd[i].data, handle->oidc->redirect_uri, rd[i].data_size))
1563  continue;
1564  tmp = GNUNET_strndup (rd[i].data, rd[i].data_size);
1565  if (NULL == strstr (tmp, handle->oidc->client_id))
1566  {
1568  "Redirect uri %s does not contain client_id %s\n",
1569  tmp,
1570  handle->oidc->client_id);
1571  }
1572  else
1573  {
1574  pos = strrchr (tmp, (unsigned char) '.');
1575  if (NULL == pos)
1576  {
1578  "Redirect uri %s contains client_id but is malformed\n",
1579  tmp);
1580  GNUNET_free (tmp);
1581  continue;
1582  }
1583  *pos = '\0';
1584  handle->redirect_prefix = GNUNET_strdup (tmp);
1585  tmp_key_str = pos + 1;
1586  pos = strchr (tmp_key_str, (unsigned char) '/');
1587  if (NULL == pos)
1588  {
1590  "Redirect uri %s contains client_id but is malformed\n",
1591  tmp);
1592  GNUNET_free (tmp);
1593  continue;
1594  }
1595  *pos = '\0';
1596  handle->redirect_suffix = GNUNET_strdup (pos + 1);
1597 
1598  GNUNET_STRINGS_string_to_data (tmp_key_str,
1599  strlen (tmp_key_str),
1600  &redirect_zone,
1601  sizeof(redirect_zone));
1602  }
1604  GNUNET_free (tmp);
1605  return;
1606  }
1608  handle->edesc =
1609  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1611 }
1612 
1613 
1617 static void
1618 client_redirect (void *cls)
1619 {
1620  struct RequestHandle *handle = cls;
1621 
1622  /* Lookup client redirect uri to verify request */
1623  handle->gns_op =
1626  &handle->oidc->client_pkey,
1630  handle);
1631 }
1632 
1633 
1634 static char *
1635 get_url_parameter_copy (const struct RequestHandle *handle, const char *key)
1636 {
1637  struct GNUNET_HashCode hc;
1638  char *value;
1639  char *res;
1640 
1641  GNUNET_CRYPTO_hash (key, strlen (key), &hc);
1643  ->url_param_map,
1644  &hc))
1645  return NULL;
1646  value =
1647  GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, &hc);
1648  if (NULL == value)
1649  return NULL;
1650  GNUNET_STRINGS_urldecode (value, strlen (value), &res);
1651  return res;
1652 }
1653 
1654 
1661 static void
1663 {
1664  struct RequestHandle *handle = cls;
1665  struct GNUNET_HashCode cache_key;
1666 
1667  char *expected_scope;
1668  char delimiter[] = " ";
1669  int number_of_ignored_parameter, iterator;
1670 
1671 
1672  // REQUIRED value: redirect_uri
1673  handle->oidc->redirect_uri =
1675  if (NULL == handle->oidc->redirect_uri)
1676  {
1678  handle->edesc = GNUNET_strdup ("missing parameter redirect_uri");
1680  return;
1681  }
1682 
1683  // REQUIRED value: response_type
1684  handle->oidc->response_type =
1686  if (NULL == handle->oidc->response_type)
1687  {
1689  handle->edesc = GNUNET_strdup ("missing parameter response_type");
1691  return;
1692  }
1693 
1694  // REQUIRED value: scope
1696  if (NULL == handle->oidc->scope)
1697  {
1699  handle->edesc = GNUNET_strdup ("missing parameter scope");
1701  return;
1702  }
1703 
1704  // OPTIONAL value: nonce
1706 
1707  // OPTIONAL value: claims
1709 
1710  // TODO check other values if needed
1711  number_of_ignored_parameter =
1712  sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1713  for (iterator = 0; iterator < number_of_ignored_parameter; iterator++)
1714  {
1717  &cache_key);
1718  if (GNUNET_YES ==
1720  ->url_param_map,
1721  &cache_key))
1722  {
1724  GNUNET_asprintf (&handle->edesc,
1725  "Server will not handle parameter: %s",
1728  return;
1729  }
1730  }
1731 
1732  // We only support authorization code flows.
1733  if (0 != strcmp (handle->oidc->response_type,
1735  {
1737  handle->edesc = GNUNET_strdup ("The authorization server does not support "
1738  "obtaining this authorization code.");
1740  return;
1741  }
1742 
1743  // Checks if scope contains 'openid'
1744  expected_scope = GNUNET_strdup (handle->oidc->scope);
1745  char *test;
1746  test = strtok (expected_scope, delimiter);
1747  while (NULL != test)
1748  {
1749  if (0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope))
1750  break;
1751  test = strtok (NULL, delimiter);
1752  }
1753  if (NULL == test)
1754  {
1756  handle->edesc =
1757  GNUNET_strdup ("The requested scope is invalid, unknown, or malformed.");
1759  GNUNET_free (expected_scope);
1760  return;
1761  }
1762 
1763  GNUNET_free (expected_scope);
1764  if ((NULL == handle->oidc->login_identity) &&
1765  (GNUNET_NO == handle->oidc->user_cancelled))
1767  else
1769 }
1770 
1771 
1775 static void
1776 tld_iter (void *cls, const char *section, const char *option, const char *value)
1777 {
1778  struct RequestHandle *handle = cls;
1780 
1781  if (GNUNET_OK !=
1783  {
1784  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping non key %s\n", value);
1785  return;
1786  }
1787  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1788  handle->tld = GNUNET_strdup (option + 1);
1789 }
1790 
1791 
1799 static void
1801  const char *url,
1802  void *cls)
1803 {
1804  struct RequestHandle *handle = cls;
1805  struct EgoEntry *tmp_ego;
1806  const struct GNUNET_IDENTITY_PrivateKey *priv_key;
1808 
1810 
1811  // RECOMMENDED value: state - REQUIRED for answers
1813 
1814  // REQUIRED value: client_id
1816  if (NULL == handle->oidc->client_id)
1817  {
1819  handle->edesc = GNUNET_strdup ("missing parameter client_id");
1820  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1822  return;
1823  }
1824 
1825  // OPTIONAL value: code_challenge
1826  handle->oidc->code_challenge = get_url_parameter_copy (handle,
1828  if (NULL == handle->oidc->code_challenge)
1829  {
1831  "OAuth authorization request does not contain PKCE parameters!\n");
1832  }
1833 
1834  if (GNUNET_OK !=
1836  &handle->oidc->client_pkey))
1837  {
1839  handle->edesc = GNUNET_strdup ("The client is not authorized to request an "
1840  "authorization code using this method.");
1841  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1843  return;
1844  }
1845 
1846  // If we know this identity, translated the corresponding TLD
1847  // TODO: We might want to have a reverse lookup functionality for TLDs?
1848  for (tmp_ego = ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
1849  {
1850  priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
1851  GNUNET_IDENTITY_key_get_public (priv_key, &pkey);
1852  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1853  {
1854  handle->tld = GNUNET_strdup (tmp_ego->identifier);
1855  handle->ego_entry = ego_tail;
1856  }
1857  }
1858  if (NULL == handle->tld)
1860  if (NULL == handle->tld)
1861  handle->tld = GNUNET_strdup (handle->oidc->client_id);
1863 }
1864 
1865 
1873 static void
1875  const char *url,
1876  void *cls)
1877 {
1878  struct MHD_Response *resp = GNUNET_REST_create_response ("");
1879  struct RequestHandle *handle = cls;
1880  struct GNUNET_HashCode cache_key;
1881  struct GNUNET_TIME_Absolute *current_time;
1882  struct GNUNET_TIME_Absolute *last_time;
1883  char *cookie;
1884  char *header_val;
1885  json_t *root;
1886  json_error_t error;
1887  json_t *identity;
1888  char term_data[handle->rest_handle->data_size + 1];
1889 
1890  term_data[handle->rest_handle->data_size] = '\0';
1891  GNUNET_memcpy (term_data,
1892  handle->rest_handle->data,
1893  handle->rest_handle->data_size);
1894  root = json_loads (term_data, JSON_DECODE_ANY, &error);
1895  identity = json_object_get (root, "identity");
1896  if (! json_is_string (identity))
1897  {
1899  "Error parsing json string from %s\n",
1900  term_data);
1901  handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1902  json_decref (root);
1904  return;
1905  }
1906  GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1907  GNUNET_asprintf (&header_val,
1908  "%s;Max-Age=%d",
1909  cookie,
1911  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
1912  "Set-Cookie", header_val));
1913  GNUNET_assert (MHD_NO !=
1914  MHD_add_response_header (resp,
1915  "Access-Control-Allow-Methods",
1916  "POST"));
1917  GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1918 
1919  if (0 != strcmp (json_string_value (identity), "Denied"))
1920  {
1921  current_time = GNUNET_new (struct GNUNET_TIME_Absolute);
1922  *current_time = GNUNET_TIME_relative_to_absolute (
1925  last_time =
1927  GNUNET_free (last_time);
1929  &cache_key,
1930  current_time,
1932  }
1933  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1934  GNUNET_free (cookie);
1935  GNUNET_free (header_val);
1936  json_decref (root);
1938 }
1939 
1940 
1941 static int
1943  char **client_id,
1944  char **client_secret)
1945 {
1946  struct GNUNET_HashCode cache_key;
1947  char *authorization;
1948  char *credentials;
1949  char *basic_authorization;
1950  char *client_id_tmp;
1951  char *pass;
1952 
1955  &cache_key);
1957  ->header_param_map,
1958  &cache_key))
1959  return GNUNET_SYSERR;
1960  authorization =
1961  GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
1962  &cache_key);
1963 
1964  // split header in "Basic" and [content]
1965  credentials = strtok (authorization, " ");
1966  if ((NULL == credentials) || (0 != strcmp ("Basic", credentials)))
1967  return GNUNET_SYSERR;
1968  credentials = strtok (NULL, " ");
1969  if (NULL == credentials)
1970  return GNUNET_SYSERR;
1971  GNUNET_STRINGS_base64_decode (credentials,
1972  strlen (credentials),
1973  (void **) &basic_authorization);
1974 
1975  if (NULL == basic_authorization)
1976  return GNUNET_SYSERR;
1977  client_id_tmp = strtok (basic_authorization, ":");
1978  if (NULL == client_id_tmp)
1979  {
1980  GNUNET_free (basic_authorization);
1981  return GNUNET_SYSERR;
1982  }
1983  pass = strtok (NULL, ":");
1984  if (NULL == pass)
1985  {
1986  GNUNET_free (basic_authorization);
1987  return GNUNET_SYSERR;
1988  }
1989  *client_id = strdup (client_id_tmp);
1990  *client_secret = strdup (pass);
1991  GNUNET_free (basic_authorization);
1992  return GNUNET_OK;
1993 }
1994 
1995 
1996 static int
1998  char **client_id,
1999  char **client_secret)
2000 {
2001  struct GNUNET_HashCode cache_key;
2002  char *client_id_tmp;
2003  char *pass;
2004 
2005  GNUNET_CRYPTO_hash ("client_id",
2006  strlen ("client_id"),
2007  &cache_key);
2009  ->url_param_map,
2010  &cache_key))
2011  return GNUNET_SYSERR;
2012  client_id_tmp = GNUNET_CONTAINER_multihashmap_get (
2013  handle->rest_handle->url_param_map,
2014  &cache_key);
2015  if (NULL == client_id_tmp)
2016  return GNUNET_SYSERR;
2017  *client_id = strdup (client_id_tmp);
2018  GNUNET_CRYPTO_hash ("client_secret",
2019  strlen ("client_secret"),
2020  &cache_key);
2022  ->url_param_map,
2023  &cache_key))
2024  {
2025  GNUNET_free (*client_id);
2026  *client_id = NULL;
2027  return GNUNET_SYSERR;
2028  }
2029  pass = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
2030  &cache_key);
2031  if (NULL == pass)
2032  {
2033  GNUNET_free (*client_id);
2034  *client_id = NULL;
2035  return GNUNET_SYSERR;
2036  }
2037  *client_secret = strdup (pass);
2038  return GNUNET_OK;
2039 }
2040 
2041 
2042 static int
2044  struct GNUNET_IDENTITY_PublicKey *cid)
2045 {
2046  char *expected_pass;
2047  char *received_cid;
2048  char *received_cpw;
2049  char *pkce_cv;
2050 
2052  &received_cid,
2053  &received_cpw))
2054  {
2056  "Received client credentials in HTTP AuthZ header\n");
2057  }
2059  &received_cid,
2060  &received_cpw))
2061  {
2063  "Received client credentials in POST body\n");
2064  }
2065  else
2066  {
2069  if (NULL == pkce_cv)
2070  {
2072  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2073  return GNUNET_SYSERR;
2074  }
2075  handle->public_client = GNUNET_YES;
2076  GNUNET_free (pkce_cv);
2078  GNUNET_STRINGS_string_to_data (received_cid,
2079  strlen (received_cid),
2080  cid,
2081  sizeof(struct GNUNET_IDENTITY_PublicKey));
2082  GNUNET_free (received_cid);
2083  return GNUNET_OK;
2084 
2085  }
2086 
2087  // check client password
2089  "reclaim-rest-plugin",
2090  "OIDC_CLIENT_HMAC_SECRET",
2091  &expected_pass))
2092  {
2093  if (0 != strcmp (expected_pass, received_cpw))
2094  {
2095  GNUNET_free (expected_pass);
2097  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2098  GNUNET_free (received_cpw);
2099  GNUNET_free (received_cid);
2100  return GNUNET_SYSERR;
2101  }
2102  GNUNET_free (expected_pass);
2103  }
2104  else
2105  {
2106  GNUNET_free (received_cpw);
2107  GNUNET_free (received_cid);
2109  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2110  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2111  return GNUNET_SYSERR;
2112  }
2113  // check client_id
2114  for (handle->ego_entry = ego_head; NULL != handle->ego_entry;
2115  handle->ego_entry = handle->ego_entry->next)
2116  {
2117  if (0 == strcmp (handle->ego_entry->keystring, received_cid))
2118  break;
2119  }
2120  if (NULL == handle->ego_entry)
2121  {
2122  GNUNET_free (received_cpw);
2123  GNUNET_free (received_cid);
2125  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2126  return GNUNET_SYSERR;
2127  }
2128  GNUNET_STRINGS_string_to_data (received_cid,
2129  strlen (received_cid),
2130  cid,
2131  sizeof(struct GNUNET_IDENTITY_PublicKey));
2132 
2133  GNUNET_free (received_cpw);
2134  GNUNET_free (received_cid);
2135  return GNUNET_OK;
2136 }
2137 
2138 
2139 const struct EgoEntry *
2141  struct GNUNET_IDENTITY_PublicKey *test_key)
2142 {
2143  struct EgoEntry *ego_entry;
2144  struct GNUNET_IDENTITY_PublicKey pub_key;
2145 
2146  for (ego_entry = ego_head; NULL != ego_entry;
2147  ego_entry = ego_entry->next)
2148  {
2149  GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
2150  if (0 == GNUNET_memcmp (&pub_key, test_key))
2151  return ego_entry;
2152  }
2153  return NULL;
2154 }
2155 
2156 
2164 static void
2166  const char *url,
2167  void *cls)
2168 {
2169  struct RequestHandle *handle = cls;
2170  const struct EgoEntry *ego_entry = NULL;
2171  struct GNUNET_TIME_Relative expiration_time;
2172  struct GNUNET_RECLAIM_AttributeList *cl = NULL;
2173  struct GNUNET_RECLAIM_PresentationList *pl = NULL;
2175  struct GNUNET_IDENTITY_PublicKey cid;
2176  struct GNUNET_HashCode cache_key;
2177  struct MHD_Response *resp = NULL;
2178  char *grant_type = NULL;
2179  char *code = NULL;
2180  char *json_response = NULL;
2181  char *id_token = NULL;
2182  char *access_token = NULL;
2183  char *jwa = NULL;
2184  char *jwt_secret = NULL;
2185  char *nonce = NULL;
2186  char *code_verifier = NULL;
2187  json_t *oidc_jwk = NULL;
2188  char *oidc_jwk_path = NULL;
2189  char *oidc_directory = NULL;
2190  char *tmp_at = NULL;
2191 
2192  /*
2193  * Check Authorization
2194  */
2195  if (GNUNET_SYSERR == check_authorization (handle, &cid))
2196  {
2198  "OIDC authorization for token endpoint failed\n");
2200  return;
2201  }
2202 
2203  /*
2204  * Check parameter
2205  */
2206 
2207  // TODO Do not allow multiple equal parameter names
2208  // REQUIRED grant_type
2210  strlen (OIDC_GRANT_TYPE_KEY),
2211  &cache_key);
2213  if (NULL == grant_type)
2214  {
2216  handle->edesc = GNUNET_strdup ("missing parameter grant_type");
2217  handle->response_code = MHD_HTTP_BAD_REQUEST;
2219  return;
2220  }
2221 
2222  // Check parameter grant_type == "authorization_code"
2223  if (0 != strcmp (OIDC_GRANT_TYPE_VALUE, grant_type))
2224  {
2226  handle->response_code = MHD_HTTP_BAD_REQUEST;
2227  GNUNET_free (grant_type);
2229  return;
2230  }
2231  GNUNET_free (grant_type);
2232  // REQUIRED code
2234  if (NULL == code)
2235  {
2237  handle->edesc = GNUNET_strdup ("missing parameter code");
2238  handle->response_code = MHD_HTTP_BAD_REQUEST;
2240  return;
2241  }
2242  ego_entry = find_ego (handle, &cid);
2243  if (NULL == ego_entry)
2244  {
2246  handle->edesc = GNUNET_strdup ("Unknown client");
2247  handle->response_code = MHD_HTTP_BAD_REQUEST;
2248  GNUNET_free (code);
2250  return;
2251  }
2252 
2253  // REQUIRED code verifier
2255  if (NULL == code_verifier)
2256  {
2258  "OAuth authorization request does not contain PKCE parameters!\n");
2259 
2260  }
2261 
2262  // decode code
2263  if (GNUNET_OK != OIDC_parse_authz_code (&cid, code, code_verifier, &ticket,
2264  &cl, &pl, &nonce,
2266  {
2268  handle->edesc = GNUNET_strdup ("invalid code");
2269  handle->response_code = MHD_HTTP_BAD_REQUEST;
2270  GNUNET_free (code);
2271  if (NULL != code_verifier)
2272  GNUNET_free (code_verifier);
2274  return;
2275  }
2276  if (NULL != code_verifier)
2277  GNUNET_free (code_verifier);
2278 
2279  // create jwt
2281  "reclaim-rest-plugin",
2282  "expiration_time",
2283  &expiration_time))
2284  {
2286  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2287  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2288  GNUNET_free (code);
2289  if (NULL != nonce)
2290  GNUNET_free (nonce);
2294  return;
2295  }
2296 
2297  // Check if HMAC or RSA should be used
2299  "reclaim-rest-plugin",
2300  "oidc_json_web_algorithm",
2301  &jwa))
2302  {
2304  "Could not read OIDC JSON Web Algorithm config attribute."
2305  "Defaulting to RS256.");
2306  jwa = JWT_ALG_VALUE_RSA;
2307  }
2308 
2309  if ( ! strcmp (jwa, JWT_ALG_VALUE_RSA))
2310  {
2311  // Replace for now
2312  oidc_jwk_path = get_oidc_jwk_path (cls);
2313  oidc_jwk = read_jwk_from_file (oidc_jwk_path);
2314 
2315  // Check if secret JWK exists
2316  if (! oidc_jwk)
2317  {
2318  // Generate and save a new key
2319  oidc_jwk = generate_jwk ();
2320  oidc_directory = get_oidc_dir_path (cls);
2321 
2322  // Create new oidc directory
2323  if (GNUNET_OK != GNUNET_DISK_directory_create (oidc_directory))
2324  {
2326  ("Failed to create directory `%s' for storing oidc data\n"),
2327  oidc_directory);
2328  }
2329  else
2330  {
2331  write_jwk_to_file (oidc_jwk_path, oidc_jwk);
2332  }
2333  }
2334 
2335  // Generate oidc token
2337  &ticket.identity,
2338  cl,
2339  pl,
2340  &expiration_time,
2341  (NULL != nonce) ? nonce : NULL,
2342  oidc_jwk);
2343  }
2344  else if ( ! strcmp (jwa, JWT_ALG_VALUE_HMAC))
2345  {
2346  // TODO OPTIONAL acr,amr,azp
2348  "reclaim-rest-plugin",
2349  "jwt_secret",
2350  &jwt_secret))
2351  {
2353  handle->edesc = GNUNET_strdup ("No signing secret configured!");
2354  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2355  GNUNET_free (code);
2358  if (NULL != nonce)
2359  GNUNET_free (nonce);
2361  return;
2362  }
2363 
2365  &ticket.identity,
2366  cl,
2367  pl,
2368  &expiration_time,
2369  (NULL != nonce) ? nonce : NULL,
2370  jwt_secret);
2371 
2372  GNUNET_free (jwt_secret);
2373  }
2374  else
2375  {
2376  // TODO: OPTION NOT FOUND ERROR
2377  }
2378 
2379  if (NULL != nonce)
2380  GNUNET_free (nonce);
2381  access_token = OIDC_access_token_new (&ticket);
2386  GNUNET_CRYPTO_hash (access_token,
2387  strlen (access_token),
2388  &cache_key);
2400  &cache_key);
2402  &cache_key,
2403  code,
2405  /* If there was a previous code in there, free the old value */
2406  if (NULL != tmp_at)
2407  {
2409  "OIDC access token already issued. Cleanup.\n");
2410  GNUNET_free (tmp_at);
2411  }
2412 
2413  OIDC_build_token_response (access_token,
2414  id_token,
2415  &expiration_time,
2416  &json_response);
2417 
2418  resp = GNUNET_REST_create_response (json_response);
2419  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
2420  "Cache-Control",
2421  "no-store"));
2422  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
2423  "Pragma", "no-cache"));
2424  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
2425  "Content-Type",
2426  "application/json"));
2427  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2430  GNUNET_free (access_token);
2431  GNUNET_free (json_response);
2432  GNUNET_free (id_token);
2434 }
2435 
2436 
2440 static void
2441 consume_ticket (void *cls,
2442  const struct GNUNET_IDENTITY_PublicKey *identity,
2443  const struct GNUNET_RECLAIM_Attribute *attr,
2444  const struct GNUNET_RECLAIM_Presentation *presentation)
2445 {
2446  struct RequestHandle *handle = cls;
2449  struct MHD_Response *resp;
2450  struct GNUNET_HashCode cache_key;
2451  char *result_str;
2452  char *cached_code;
2453 
2454  if (NULL != handle->consume_timeout_op)
2455  GNUNET_SCHEDULER_cancel (handle->consume_timeout_op);
2456  handle->consume_timeout_op = NULL;
2457  handle->idp_op = NULL;
2458 
2462  GNUNET_CRYPTO_hash (handle->access_token,
2463  strlen (handle->access_token),
2464  &cache_key);
2466  &cache_key);
2467  if (NULL != cached_code)
2468  {
2471  &cache_key,
2472  cached_code));
2473  GNUNET_free (cached_code);
2474  }
2475 
2476 
2477  if (NULL == identity)
2478  {
2479  result_str = OIDC_generate_userinfo (&handle->ticket.identity,
2480  handle->attr_userinfo_list,
2481  handle->presentations);
2482  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Userinfo: %s\n", result_str);
2483  resp = GNUNET_REST_create_response (result_str);
2484  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2485  GNUNET_free (result_str);
2487  return;
2488  }
2491  &attr->credential,
2492  attr->type,
2493  attr->data,
2494  attr->data_size);
2495  ale->attribute->id = attr->id;
2496  ale->attribute->flag = attr->flag;
2497  ale->attribute->credential = attr->credential;
2498  GNUNET_CONTAINER_DLL_insert (handle->attr_userinfo_list->list_head,
2499  handle->attr_userinfo_list->list_tail,
2500  ale);
2501  if (NULL == presentation)
2502  return;
2503  for (atle = handle->presentations->list_head;
2504  NULL != atle; atle = atle->next)
2505  {
2507  &atle->presentation->credential_id,
2508  &presentation->credential_id))
2509  continue;
2510  break;
2511  }
2512  if (NULL == atle)
2513  {
2516  atle->presentation = GNUNET_RECLAIM_presentation_new (presentation->type,
2517  presentation->data,
2518  presentation->
2519  data_size);
2520  atle->presentation->credential_id = presentation->credential_id;
2521  GNUNET_CONTAINER_DLL_insert (handle->presentations->list_head,
2522  handle->presentations->list_tail,
2523  atle);
2524  }
2525 }
2526 
2527 
2528 static void
2529 consume_fail (void *cls)
2530 {
2531  struct RequestHandle *handle = cls;
2532  struct GNUNET_HashCode cache_key;
2533  struct GNUNET_RECLAIM_AttributeList *cl = NULL;
2534  struct GNUNET_RECLAIM_PresentationList *pl = NULL;
2536  struct MHD_Response *resp;
2537  char *nonce;
2538  char *cached_code;
2539  char *result_str;
2540 
2541 
2542  handle->consume_timeout_op = NULL;
2543  if (NULL != handle->idp_op)
2544  GNUNET_RECLAIM_cancel (handle->idp_op);
2545  handle->idp_op = NULL;
2546 
2548  "Ticket consumptioned timed out. Using cache...\n");
2549  GNUNET_CRYPTO_hash (handle->access_token,
2550  strlen (handle->access_token),
2551  &cache_key);
2553  &cache_key);
2554  if (NULL == cached_code)
2555  {
2557  handle->edesc = GNUNET_strdup ("No Access Token in cache!");
2558  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2560  return;
2561  }
2567  &cache_key,
2568  cached_code));
2569 
2570  // decode code
2571  if (GNUNET_OK != OIDC_parse_authz_code (&handle->ticket.audience,
2572  cached_code, NULL, &ticket,
2573  &cl, &pl, &nonce,
2575  {
2577  handle->edesc = GNUNET_strdup ("invalid code");
2578  handle->response_code = MHD_HTTP_BAD_REQUEST;
2579  GNUNET_free (cached_code);
2580  if (NULL != nonce)
2581  GNUNET_free (nonce);
2583  return;
2584  }
2585 
2586  GNUNET_free (cached_code);
2587 
2588  result_str = OIDC_generate_userinfo (&handle->ticket.identity,
2589  cl,
2590  pl);
2591  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Userinfo: %s\n", result_str);
2592  resp = GNUNET_REST_create_response (result_str);
2593  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2594  GNUNET_free (result_str);
2595  GNUNET_free (nonce);
2599 }
2600 
2601 
2609 static void
2611  const char *url,
2612  void *cls)
2613 {
2614  // TODO expiration time
2615  struct RequestHandle *handle = cls;
2616  struct GNUNET_RECLAIM_Ticket *ticket;
2617  char delimiter[] = " ";
2618  struct GNUNET_HashCode cache_key;
2619  char *authorization;
2620  char *authorization_type;
2621  char *authorization_access_token;
2622  const struct EgoEntry *aud_ego;
2623  const struct GNUNET_IDENTITY_PrivateKey *privkey;
2624 
2625  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting userinfo\n");
2628  &cache_key);
2630  ->header_param_map,
2631  &cache_key))
2632  {
2634  handle->edesc = GNUNET_strdup ("No Access Token");
2635  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2637  return;
2638  }
2639  authorization =
2640  GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
2641  &cache_key);
2642 
2643  // split header in "Bearer" and access_token
2644  authorization = GNUNET_strdup (authorization);
2645  authorization_type = strtok (authorization, delimiter);
2646  if ((NULL == authorization_type) ||
2647  (0 != strcmp ("Bearer", authorization_type)))
2648  {
2650  handle->edesc = GNUNET_strdup ("No Access Token");
2651  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2653  GNUNET_free (authorization);
2654  return;
2655  }
2656  authorization_access_token = strtok (NULL, delimiter);
2657  if (NULL == authorization_access_token)
2658  {
2660  handle->edesc = GNUNET_strdup ("Access token missing");
2661  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2663  GNUNET_free (authorization);
2664  return;
2665  }
2666 
2667  if (GNUNET_OK != OIDC_access_token_parse (authorization_access_token,
2668  &ticket))
2669  {
2671  handle->edesc = GNUNET_strdup ("The access token is invalid");
2672  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2674  GNUNET_free (authorization);
2675  return;
2676 
2677  }
2678  GNUNET_assert (NULL != ticket);
2679  handle->ticket = *ticket;
2680  GNUNET_free (ticket);
2681  aud_ego = find_ego (handle, &handle->ticket.audience);
2682  if (NULL == aud_ego)
2683  {
2685  handle->edesc = GNUNET_strdup ("The access token expired");
2686  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2688  GNUNET_free (authorization);
2689  return;
2690  }
2691  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Consuming ticket\n");
2692  privkey = GNUNET_IDENTITY_ego_get_private_key (aud_ego->ego);
2693  handle->attr_userinfo_list =
2695  handle->presentations =
2697 
2698  /* If the consume takes too long, we use values from the cache */
2699  handle->access_token = GNUNET_strdup (authorization_access_token);
2700  handle->consume_timeout_op = GNUNET_SCHEDULER_add_delayed (consume_timeout,
2701  &consume_fail,
2702  handle);
2704  privkey,
2705  &handle->ticket,
2706  &consume_ticket,
2707  handle);
2708  GNUNET_free (authorization);
2709 }
2710 
2718 static void
2720  const char *url,
2721  void *cls)
2722 {
2723  char *oidc_directory;
2724  char *oidc_jwk_path;
2725  char *oidc_jwk_pub_str;
2726  json_t *oidc_jwk;
2727  struct MHD_Response *resp;
2728  struct RequestHandle *handle = cls;
2729 
2730  oidc_jwk_path = get_oidc_jwk_path (cls);
2731  oidc_jwk = read_jwk_from_file (oidc_jwk_path);
2732 
2733  // Check if secret JWK exists
2734  if (! oidc_jwk)
2735  {
2736  // Generate and save a new key
2737  oidc_jwk = generate_jwk ();
2738  oidc_directory = get_oidc_dir_path (cls);
2739 
2740  // Create new oidc directory
2741  if (GNUNET_OK != GNUNET_DISK_directory_create (oidc_directory))
2742  {
2744  ("Failed to create directory `%s' for storing oidc data\n"),
2745  oidc_directory);
2746  }
2747  else
2748  {
2749  write_jwk_to_file (oidc_jwk_path, oidc_jwk);
2750  }
2751  }
2752 
2753  // Convert secret JWK to public JWK
2754  jose_jwk_pub (NULL, oidc_jwk);
2755 
2756  // Encode JWK as string and return to API endpoint
2757  oidc_jwk_pub_str = json_dumps (oidc_jwk, JSON_INDENT (1));
2758  resp = GNUNET_REST_create_response (oidc_jwk_pub_str);
2759  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2760  json_decref (oidc_jwk);
2761  GNUNET_free (oidc_jwk_pub_str);
2762  GNUNET_free (oidc_jwk_pub_str);
2764 }
2765 
2798 static void
2799 list_ego (void *cls,
2800  struct GNUNET_IDENTITY_Ego *ego,
2801  void **ctx,
2802  const char *identifier)
2803 {
2804  struct EgoEntry *ego_entry;
2806 
2807  if (NULL == ego)
2808  {
2810  return;
2811  }
2812  if (ID_REST_STATE_INIT == state)
2813 
2814  {
2815  ego_entry = GNUNET_new (struct EgoEntry);
2818  ego_entry->ego = ego;
2819  ego_entry->identifier = GNUNET_strdup (identifier);
2821  ego_tail,
2822  ego_entry);
2823  return;
2824  }
2825  /* Ego renamed or added */
2826  if (identifier != NULL)
2827  {
2828  for (ego_entry = ego_head; NULL != ego_entry;
2829  ego_entry = ego_entry->next)
2830  {
2831  if (ego_entry->ego == ego)
2832  {
2833  /* Rename */
2834  GNUNET_free (ego_entry->identifier);
2835  ego_entry->identifier = GNUNET_strdup (identifier);
2836  break;
2837  }
2838  }
2839  if (NULL == ego_entry)
2840  {
2841  /* Add */
2842  ego_entry = GNUNET_new (struct EgoEntry);
2845  ego_entry->ego = ego;
2846  ego_entry->identifier = GNUNET_strdup (identifier);
2848  ego_tail,
2849  ego_entry);
2850  }
2851  }
2852  else
2853  {
2854  /* Delete */
2855  for (ego_entry = ego_head; NULL != ego_entry;
2856  ego_entry = ego_entry->next)
2857  {
2858  if (ego_entry->ego == ego)
2859  break;
2860  }
2861  if (NULL == ego_entry)
2862  return; /* Not found */
2863 
2865  ego_tail,
2866  ego_entry);
2867  GNUNET_free (ego_entry->identifier);
2868  GNUNET_free (ego_entry->keystring);
2869  GNUNET_free (ego_entry);
2870  return;
2871  }
2872 }
2873 
2874 
2875 static void
2877  const char *url,
2878  void *cls)
2879 {
2880  json_t *oidc_config;
2881  json_t *auth_methods;
2882  json_t *sig_algs;
2883  json_t *scopes;
2884  json_t *response_types;
2885  json_t *sub_types;
2886  json_t *claim_types;
2887  char *oidc_config_str;
2888  struct MHD_Response *resp;
2889  struct RequestHandle *handle = cls;
2890 
2891  oidc_config = json_object ();
2892  // FIXME get from config?
2893  json_object_set_new (oidc_config,
2894  "issuer", json_string ("http://localhost:7776"));
2895  json_object_set_new (oidc_config,
2896  "authorization_endpoint",
2897  json_string ("https://api.reclaim/openid/authorize"));
2898  json_object_set_new (oidc_config,
2899  "token_endpoint",
2900  json_string ("http://localhost:7776/openid/token"));
2901  auth_methods = json_array ();
2902  json_array_append_new (auth_methods,
2903  json_string ("client_secret_basic"));
2904  json_array_append_new (auth_methods,
2905  json_string ("client_secret_post"));
2906  json_object_set_new (oidc_config,
2907  "token_endpoint_auth_methods_supported",
2908  auth_methods);
2909  sig_algs = json_array ();
2910  json_array_append_new (sig_algs,
2911  json_string ("HS512"));
2912  json_array_append_new (sig_algs,
2913  json_string ("RS256"));
2914  json_object_set_new (oidc_config,
2915  "id_token_signing_alg_values_supported",
2916  sig_algs);
2917  json_object_set_new (oidc_config,
2918  "jwks_uri",
2919  json_string ("http://localhost:7776/jwks.json"));
2920  json_object_set_new (oidc_config,
2921  "userinfo_endpoint",
2922  json_string ("http://localhost:7776/openid/userinfo"));
2923  scopes = json_array ();
2924  json_array_append_new (scopes,
2925  json_string ("openid"));
2926  json_array_append_new (scopes,
2927  json_string ("profile"));
2928  json_array_append_new (scopes,
2929  json_string ("email"));
2930  json_array_append_new (scopes,
2931  json_string ("address"));
2932  json_array_append_new (scopes,
2933  json_string ("phone"));
2934  json_object_set_new (oidc_config,
2935  "scopes_supported",
2936  scopes);
2937  response_types = json_array ();
2938  json_array_append_new (response_types,
2939  json_string ("code"));
2940  json_object_set_new (oidc_config,
2941  "response_types_supported",
2942  response_types);
2943  sub_types = json_array ();
2944  json_array_append_new (sub_types,
2945  json_string ("public")); /* no pairwise support */
2946  json_object_set_new (oidc_config,
2947  "subject_types_supported",
2948  sub_types);
2949  claim_types = json_array ();
2950  json_array_append_new (claim_types,
2951  json_string ("normal"));
2952  json_array_append_new (claim_types,
2953  json_string ("aggregated"));
2954  json_object_set_new (oidc_config,
2955  "claim_types_supported",
2956  claim_types);
2957  json_object_set_new (oidc_config,
2958  "claims_parameter_supported",
2959  json_boolean (1));
2960  oidc_config_str = json_dumps (oidc_config, JSON_INDENT (1));
2961  resp = GNUNET_REST_create_response (oidc_config_str);
2962  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2963  json_decref (oidc_config);
2964  GNUNET_free (oidc_config_str);
2966 }
2967 
2968 
2976 static void
2978  const char *url,
2979  void *cls)
2980 {
2981  struct MHD_Response *resp;
2982  struct RequestHandle *handle = cls;
2983 
2984  // For now, independent of path return all options
2985  resp = GNUNET_REST_create_response (NULL);
2986  GNUNET_assert (MHD_NO !=
2987  MHD_add_response_header (resp,
2988  "Access-Control-Allow-Methods",
2989  allow_methods));
2990  GNUNET_assert (MHD_NO !=
2991  MHD_add_response_header (resp,
2992  "Access-Control-Allow-Origin",
2993  "*"));
2994  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2996  return;
2997 }
2998 
2999 
3000 static enum GNUNET_GenericReturnValue
3003  void *proc_cls)
3004 {
3005  struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
3007  static const struct GNUNET_REST_RequestHandler handlers[] =
3008  { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint },
3009  { MHD_HTTP_METHOD_POST,
3011  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont },
3012  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
3013  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
3014  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
3015  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_JWKS, &jwks_endpoint },
3016  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_OIDC_CONFIG,
3018  { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC_CONFIG,
3019  &oidc_config_cors },
3020  { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, &options_cont },
3022 
3023  handle->oidc = GNUNET_new (struct OIDC_Variables);
3024  if (NULL == OIDC_cookie_jar_map)
3026  GNUNET_NO);
3027  if (NULL == oidc_code_cache)
3029  GNUNET_NO);
3030 
3031  handle->response_code = 0;
3033  handle->proc_cls = proc_cls;
3034  handle->proc = proc;
3035  handle->rest_handle = rest_handle;
3036  handle->url = GNUNET_strdup (rest_handle->url);
3037  handle->timeout_task =
3040  requests_tail,
3041  handle);
3042  if (handle->url[strlen (handle->url) - 1] == '/')
3043  handle->url[strlen (handle->url) - 1] = '\0';
3044  if (GNUNET_NO ==
3045  GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
3046  return GNUNET_NO;
3047 
3048  return GNUNET_YES;
3049 }
3050 
3051 
3058 void *
3060 {
3061  static struct Plugin plugin;
3062  struct GNUNET_REST_Plugin *api;
3063 
3064  cfg = cls;
3065  if (NULL != plugin.cfg)
3066  return NULL; /* can only initialize once! */
3067  memset (&plugin, 0, sizeof(struct Plugin));
3068  plugin.cfg = cfg;
3069  api = GNUNET_new (struct GNUNET_REST_Plugin);
3070  api->cls = &plugin;
3077  "reclaim-rest-plugin",
3078  "OIDC_USERINFO_CONSUME_TIMEOUT",
3079  &consume_timeout))
3080  {
3082  }
3083 
3084 
3087  "%s, %s, %s, %s, %s",
3088  MHD_HTTP_METHOD_GET,
3089  MHD_HTTP_METHOD_POST,
3090  MHD_HTTP_METHOD_PUT,
3091  MHD_HTTP_METHOD_DELETE,
3092  MHD_HTTP_METHOD_OPTIONS);
3093 
3095  _ ("OpenID Connect REST API initialized\n"));
3096  return api;
3097 }
3098 
3099 
3100 static int
3101 cleanup_hashmap (void *cls, const struct GNUNET_HashCode *key, void *value)
3102 {
3103  GNUNET_free (value);
3104  return GNUNET_YES;
3105 }
3106 
3107 
3114 void *
3116 {
3117  struct GNUNET_REST_Plugin *api = cls;
3118  struct Plugin *plugin = api->cls;
3119  struct EgoEntry *ego_entry;
3120 
3121  plugin->cfg = NULL;
3122  while (NULL != requests_head)
3124  if (NULL != OIDC_cookie_jar_map)
3125  {
3127  &cleanup_hashmap,
3128  NULL);
3130  }
3131  if (NULL != oidc_code_cache)
3132  {
3134  &cleanup_hashmap,
3135  NULL);
3137  }
3138 
3140  if (NULL != gns_handle)
3142  if (NULL != identity_handle)
3144  if (NULL != idp)
3146  while (NULL != (ego_entry = ego_head))
3147  {
3149  ego_tail,
3150  ego_entry);
3151  GNUNET_free (ego_entry->identifier);
3152  GNUNET_free (ego_entry->keystring);
3153  GNUNET_free (ego_entry);
3154  }
3155  GNUNET_free (api);
3157  "OpenID Connect REST plugin is finished\n");
3158  return NULL;
3159 }
3160 
3161 
3162 /* end of plugin_rest_openid_connect.c */
#define GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT
Used reclaimID OIDC client redirect URIs.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static size_t data_size
Number of bytes in data.
Definition: gnunet-abd.c:187
static int res
static struct GNUNET_CADET_MessageHandler handlers[]
Handlers, for diverse services.
struct TestcasePlugin * plugin
The process handle to the testbed service.
struct GNUNET_HashCode key
The key used in the DHT.
static struct GNUNET_DNS_Handle * handle
Handle to transport service.
static char * filename
uint32_t data
The data value.
struct GNUNET_IDENTITY_PrivateKey pk
Private key from command line option, or NULL.
static char * pkey
Public key of the zone to look in, in ASCII.
static struct GNUNET_IDENTITY_PublicKey pubkey
Public key of the zone to look in.
static unsigned int rd_count
Number of records for currently parsed set.
static struct GNUNET_GNSRECORD_Data rd[50]
The record data under a single label.
static char * value
Value of the record to add/remove.
static struct GNUNET_IDENTITY_Handle * identity
Which namespace do we publish to? NULL if we do not publish to a namespace.
static char * attr_name
The attribute.
static struct GNUNET_RECLAIM_Ticket ticket
Ticket to consume.
static struct GNUNET_RECLAIM_Identifier credential
Credential ID.
static char buf[2048]
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
API to the GNS service.
API that can be used to manipulate GNS record data.
Identity service; implements identity management for GNUnet.
API that can be used to store naming information on a GNUnet node;.
Identity attribute definitions.
reclaim service; implements identity and personal data sharing for GNUnet
API for helper library to parse/create REST.
GNUnet service REST plugin header.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
enum GNUNET_GenericReturnValue 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.
enum GNUNET_GenericReturnValue 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.
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.
enum GNUNET_GenericReturnValue GNUNET_DISK_directory_create(const char *dir)
Implementation of "mkdir -p".
Definition: disk.c:495
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
struct GNUNET_GNS_LookupRequest * GNUNET_GNS_lookup(struct GNUNET_GNS_Handle *handle, const char *name, const struct GNUNET_IDENTITY_PublicKey *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:422
void GNUNET_GNS_disconnect(struct GNUNET_GNS_Handle *handle)
Shutdown connection with the GNS service.
Definition: gns_api.c:290
void * GNUNET_GNS_lookup_cancel(struct GNUNET_GNS_LookupRequest *lr)
Cancel pending lookup request.
Definition: gns_api.c:314
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
@ GNUNET_GNS_LO_DEFAULT
Defaults, look in cache, then in DHT.
#define GNUNET_GNS_EMPTY_LABEL_AT
String we use to indicate an empty label (top-level entry in the zone).
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:41
enum GNUNET_GenericReturnValue 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).
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_remove(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, const void *value)
Remove the given key-value pair from the map.
enum GNUNET_GenericReturnValue 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_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
int GNUNET_CONTAINER_multihashmap_iterate(struct GNUNET_CONTAINER_MultiHashMap *map, GNUNET_CONTAINER_MulitHashMapIteratorCallback it, void *it_cls)
Iterate over all entries in the map.
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
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.
static int iterator(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Iterator over hash map entries.
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE
If a value with the given key exists, replace it.
const struct GNUNET_IDENTITY_PrivateKey * GNUNET_IDENTITY_ego_get_private_key(const struct GNUNET_IDENTITY_Ego *ego)
Obtain the ECC key associated with a ego.
Definition: identity_api.c:560
enum GNUNET_GenericReturnValue GNUNET_IDENTITY_public_key_from_string(const char *str, struct GNUNET_IDENTITY_PublicKey *key)
Parses a (Base32) string representation of the public key.
enum GNUNET_GenericReturnValue GNUNET_IDENTITY_key_get_public(const struct GNUNET_IDENTITY_PrivateKey *privkey, struct GNUNET_IDENTITY_PublicKey *key)
Retrieves the public key representation of a private key.
Definition: identity_api.c:179
void GNUNET_IDENTITY_ego_get_public_key(struct GNUNET_IDENTITY_Ego *ego, struct GNUNET_IDENTITY_PublicKey *pk)
Get the identifier (public key) of an ego.
Definition: identity_api.c:573
char * GNUNET_IDENTITY_public_key_to_string(const struct GNUNET_IDENTITY_PublicKey *key)
Creates a (Base32) string representation of the public key.
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:531
void GNUNET_IDENTITY_disconnect(struct GNUNET_IDENTITY_Handle *h)
Disconnect from identity service.
Definition: identity_api.c:757
char * GNUNET_buffer_reap_str(struct GNUNET_Buffer *buf)
Clear the buffer and return the string it contained.
Definition: buffer.c:123
#define GNUNET_log(kind,...)
void GNUNET_buffer_write_fstr(struct GNUNET_Buffer *buf, const char *fmt,...) __attribute__((format(printf
Write a 0-terminated formatted string to a buffer, excluding the 0-terminator.
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
void GNUNET_buffer_write_str(struct GNUNET_Buffer *buf, const char *str)
Write a 0-terminated string to a buffer, excluding the 0-terminator.
Definition: buffer.c:103
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_RECLAIM_id_is_equal(a, b)
void GNUNET_RECLAIM_attribute_list_destroy(struct GNUNET_RECLAIM_AttributeList *attrs)
Destroy claim list.
struct GNUNET_RECLAIM_Credential * GNUNET_RECLAIM_credential_new(const char *name, uint32_t type, const void *data, size_t data_size)
Create a new credential.
void GNUNET_RECLAIM_credential_list_destroy(struct GNUNET_RECLAIM_CredentialList *credentials)
Destroy credential list.
void GNUNET_RECLAIM_presentation_list_destroy(struct GNUNET_RECLAIM_PresentationList *presentations)
Destroy presentations list.
struct GNUNET_RECLAIM_Attribute * GNUNET_RECLAIM_attribute_new(const char *attr_name, const struct GNUNET_RECLAIM_Identifier *credential, uint32_t type, const void *data, size_t data_size)
Create a new attribute claim.
struct GNUNET_RECLAIM_Presentation * GNUNET_RECLAIM_presentation_new(uint32_t type, const void *data, size_t data_size)
void GNUNET_RECLAIM_disconnect(struct GNUNET_RECLAIM_Handle *h)
Disconnect from identity provider service.
Definition: reclaim_api.c:1143
struct GNUNET_RECLAIM_AttributeIterator * GNUNET_RECLAIM_get_attributes_start(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *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:1332
void GNUNET_RECLAIM_cancel(struct GNUNET_RECLAIM_Operation *op)
Cancel an identity provider operation.
Definition: reclaim_api.c:1128
void GNUNET_RECLAIM_get_attributes_stop(struct GNUNET_RECLAIM_AttributeIterator *it)
Stops iteration and releases the handle for further calls.
Definition: reclaim_api.c:1391
void GNUNET_RECLAIM_get_credentials_next(struct GNUNET_RECLAIM_CredentialIterator *ait)
Calls the record processor specified in GNUNET_RECLAIM_get_credentials_start for the next record.
Definition: reclaim_api.c:1454
struct GNUNET_RECLAIM_CredentialIterator * GNUNET_RECLAIM_get_credentials_start(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *identity, GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls, GNUNET_RECLAIM_CredentialResult proc, void *proc_cls, GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls)
List all credentials for a local identity.
Definition: reclaim_api.c:1409
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:1377
struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_ticket_issue(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *iss, const struct GNUNET_IDENTITY_PublicKey *rp, const struct GNUNET_RECLAIM_AttributeList *attrs, GNUNET_RECLAIM_IssueTicketCallback cb, void *cb_cls)
Issues a ticket to a relying party.
Definition: reclaim_api.c:1489
struct GNUNET_RECLAIM_Handle * GNUNET_RECLAIM_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Connect to the re:claimID service.
Definition: reclaim_api.c:1111
void GNUNET_RECLAIM_get_credentials_stop(struct GNUNET_RECLAIM_CredentialIterator *ait)
Stops iteration and releases the handle for further calls.
Definition: reclaim_api.c:1469
struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_ticket_consume(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *identity, const struct GNUNET_RECLAIM_Ticket *ticket, GNUNET_RECLAIM_AttributeTicketResult cb, void *cb_cls)
Consumes an issued ticket.
Definition: reclaim_api.c:1549
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
struct MHD_Response * GNUNET_REST_create_response(const char *data)
Create REST MHD response.
Definition: rest.c:44
int GNUNET_REST_handle_request(struct GNUNET_REST_RequestHandle *conn, const struct GNUNET_REST_RequestHandler *handlers, struct GNUNET_REST_RequestHandlerError *err, void *cls)
Definition: rest.c:64
void(* GNUNET_REST_ResultProcessor)(void *cls, struct MHD_Response *resp, int status)
Iterator called on obtained result for a REST result.
#define GNUNET_REST_HANDLER_END
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1268
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:944
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:1241
size_t GNUNET_STRINGS_urldecode(const char *data, size_t len, char **out)
url/percent encode (RFC3986).
Definition: strings.c:1806
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:763
size_t GNUNET_STRINGS_urlencode(const char *data, size_t len, char **out)
url/percent encode (RFC3986).
Definition: strings.c:1850
enum GNUNET_GenericReturnValue 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:788
size_t GNUNET_STRINGS_base64_decode(const char *data, size_t len, void **output)
Decode from Base64.
Definition: strings.c:1695
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:111
struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_second_(void)
Return relative time of 1s.
Definition: time.c:169
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:316
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:484
@ MHD_HTTP_BAD_REQUEST
Bad Request [RFC7231, Section 6.5.1].
@ MHD_HTTP_UNAUTHORIZED
Unauthorized [RFC7235, Section 3.1].
@ MHD_HTTP_OK
OK [RFC7231, Section 6.3.1].
@ MHD_HTTP_INTERNAL_SERVER_ERROR
Internal Server Error [RFC7231, Section 6.6.1].
@ MHD_HTTP_FOUND
Found [RFC7231, Section 6.4.3].
char * OIDC_generate_id_token_hmac(const struct GNUNET_IDENTITY_PublicKey *aud_key, const struct GNUNET_IDENTITY_PublicKey *sub_key, const struct GNUNET_RECLAIM_AttributeList *attrs, const struct GNUNET_RECLAIM_PresentationList *presentations, const struct GNUNET_TIME_Relative *expiration_time, const char *nonce, const char *secret_key)
Create a JWT using HMAC (HS256) from attributes.
Definition: oidc_helper.c:489
char * OIDC_generate_userinfo(const struct GNUNET_IDENTITY_PublicKey *sub_key, const struct GNUNET_RECLAIM_AttributeList *attrs, const struct GNUNET_RECLAIM_PresentationList *presentations)
Generate userinfo JSON as string.
Definition: oidc_helper.c:346
char * OIDC_access_token_new(const struct GNUNET_RECLAIM_Ticket *ticket)
Generate a new access token.
Definition: oidc_helper.c:916
enum GNUNET_GenericReturnValue OIDC_check_scopes_for_claim_request(const char *scopes, const char *attr)
Checks if a claim is implicitly requested through standard scope(s) or explicitly through non-standar...
Definition: oidc_helper.c:958
char * OIDC_build_authz_code(const struct GNUNET_IDENTITY_PrivateKey *issuer, const struct GNUNET_RECLAIM_Ticket *ticket, const struct GNUNET_RECLAIM_AttributeList *attrs, const struct GNUNET_RECLAIM_PresentationList *presentations, const char *nonce_str, const char *code_challenge)
Builds an OIDC authorization code including a reclaim ticket and nonce.
Definition: oidc_helper.c:581
int OIDC_parse_authz_code(const struct GNUNET_IDENTITY_PublicKey *audience, const char *code, const char *code_verifier, struct GNUNET_RECLAIM_Ticket *ticket, struct GNUNET_RECLAIM_AttributeList **attrs, struct GNUNET_RECLAIM_PresentationList **presentations, char **nonce_str, enum OIDC_VerificationOptions opts)
Parse reclaim ticket and nonce from authorization code.
Definition: oidc_helper.c:767
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:888
int OIDC_access_token_parse(const char *token, struct GNUNET_RECLAIM_Ticket **ticket)
Parse an access token.
Definition: oidc_helper.c:931
char * OIDC_generate_id_token_rsa(const struct GNUNET_IDENTITY_PublicKey *aud_key, const struct GNUNET_IDENTITY_PublicKey *sub_key, const struct GNUNET_RECLAIM_AttributeList *attrs, const struct GNUNET_RECLAIM_PresentationList *presentations, const struct GNUNET_TIME_Relative *expiration_time, const char *nonce, const json_t *secret_rsa_key)
Create a JWT using RSA256 algorithm from attributes.
Definition: oidc_helper.c:427
helper library for OIDC related functions
#define JWT_ALG_VALUE_RSA
Definition: oidc_helper.h:35
@ OIDC_VERIFICATION_NO_CODE_VERIFIER
Do not check code verifier even if expected.
Definition: oidc_helper.h:49
@ OIDC_VERIFICATION_DEFAULT
Strict verification.
Definition: oidc_helper.h:44
#define JWT_ALG_VALUE_HMAC
Definition: oidc_helper.h:34
#define _(String)
GNU gettext support macro.
Definition: platform.h:177
static struct EgoEntry * ego_tail
Ego list.
#define OIDC_SCOPE_KEY
OIDC scope key.
static void consume_fail(void *cls)
json_t * read_jwk_from_file(const char *filename)
Read the the JSON Web Key in the given file and return it.
char * get_oidc_jwk_path(void *cls)
Return the path to the RSA JWK key file.
static int attr_in_userinfo_request(struct RequestHandle *handle, const char *attr_name)
#define OIDC_AUTHORIZATION_HEADER_KEY
OIDC cookie header information key.
#define GNUNET_REST_API_NS_OIDC_CONFIG
OIDC config.
static struct GNUNET_RECLAIM_Handle * idp
Identity Provider.
struct GNUNET_CONTAINER_MultiHashMap * oidc_code_cache
OIDC hashmap for cached access tokens and codes.
static void cookie_identity_interpretation(struct RequestHandle *handle)
Interprets cookie header and pass its identity keystring to handle.
json_t * generate_jwk()
Generate a new RSA JSON Web Key.
static struct GNUNET_GNS_Handle * gns_handle
GNS handle.
static int write_jwk_to_file(const char *filename, json_t *jwk)
Write the JWK to file.
#define OIDC_ERROR_KEY_INVALID_REQUEST
OIDC error key for invalid requests.
static int attr_in_claims_request(struct RequestHandle *handle, const char *attr_name, const char *claims_parameter)
static void oidc_attr_collect(void *cls, const struct GNUNET_IDENTITY_PublicKey *identity, const struct GNUNET_RECLAIM_Attribute *attr)
Collects all attributes for an ego if in scope parameter.
#define GNUNET_REST_API_NS_LOGIN
Login namespace.
#define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT
OIDC error key for unauthorized clients.
#define GNUNET_REST_API_NS_OIDC
REST root namespace.
static char * OIDC_ignored_parameter_array[]
OIDC ignored parameter array.
static void do_timeout(void *cls)
Task run on timeout, sends error message.
char * get_oidc_dir_path(void *cls)
Return the path to the oidc directory path.
static int parse_credentials_post_body(struct RequestHandle *handle, char **client_id, char **client_secret)
static void token_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Responds to token url-encoded POST request.
static void userinfo_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Responds to userinfo GET and url-encoded POST request.
static void jwks_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Responds to /jwks.json.
#define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE
OIDC error key for unsupported grants.
#define OIDC_ERROR_KEY_INVALID_TOKEN
OIDC error key for invalid tokens.
static struct GNUNET_TIME_Relative consume_timeout
Timeout for consume call on userinfo.
const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration handle.
#define OIDC_CLAIMS_KEY
OIDC claims key.
struct GNUNET_CONTAINER_MultiHashMap * OIDC_cookie_jar_map
OIDC hashmap that keeps track of issued cookies.
#define OIDC_ERROR_KEY_SERVER_ERROR
OIDC error key for generic server errors.
#define OIDC_COOKIE_EXPIRATION
OIDC cookie expiration (in seconds)
#define OIDC_ERROR_KEY_ACCESS_DENIED
OIDC error key for denied access.
const struct EgoEntry * find_ego(struct RequestHandle *handle, struct GNUNET_IDENTITY_PublicKey *test_key)
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.
#define OIDC_COOKIE_HEADER_KEY
OIDC cookie header key.
#define GNUNET_REST_API_JWKS
JSON Web Keys endpoint.
#define OIDC_JWK_RSA_FILENAME
OIDC key store file name.
#define ID_REST_STATE_INIT
State while collecting all egos.
#define OIDC_REDIRECT_URI_KEY
OIDC redirect_uri key.
static void do_redirect_error(void *cls)
Task run on error, sends error message and redirects.
static void code_redirect(void *cls)
Checks time and cookie and redirects accordingly.
static struct RequestHandle * requests_head
DLL.
static void options_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Respond to OPTIONS request.
#define OIDC_NONCE_KEY
OIDC nonce key.
#define OIDC_ERROR_KEY_INVALID_CLIENT
OIDC error key for invalid client.
void * libgnunet_plugin_rest_openid_connect_done(void *cls)
Exit point from the plugin.
static int parse_credentials_basic_auth(struct RequestHandle *handle, char **client_id, char **client_secret)
static void oidc_cred_collect(void *cls, const struct GNUNET_IDENTITY_PublicKey *identity, const struct GNUNET_RECLAIM_Credential *cred)
Collects all attributes for an ego if in scope parameter.
#define OIDC_GRANT_TYPE_KEY
OIDC grant_type key.
static int state
The processing state.
#define OIDC_ERROR_KEY_INVALID_COOKIE
OIDC error key for invalid cookies.
static struct EgoEntry * ego_head
Ego list.
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 oidc_cred_collect_finished_cb(void *cls)
#define OIDC_CODE_CHALLENGE_KEY
OIDC PKCE code challenge.
static char * allow_methods
HTTP methods allows for this plugin.
static void oidc_config_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
static void cleanup_handle(struct RequestHandle *handle)
Cleanup lookup handle.
#define OIDC_COOKIE_HEADER_ACCESS_DENIED
OIDC cookie header if user cancelled.
#define GNUNET_REST_API_NS_TOKEN
Token endpoint.
#define CONSUME_TIMEOUT
How long to wait for a consume in userinfo endpoint.
#define OIDC_EXPECTED_AUTHORIZATION_SCOPE
OIDC expected scope part while authorizing.
static void build_authz_response(void *cls)
Iteration over all results finished, build final response.
static void do_userinfo_error(void *cls)
Task run on error in userinfo endpoint, sends error header.
static void oidc_ticket_issue_cb(void *cls, const struct GNUNET_RECLAIM_Ticket *ticket, const struct GNUNET_RECLAIM_PresentationList *presentation)
Issues ticket and redirects to relying party with the authorization code as parameter.
#define OIDC_RESPONSE_TYPE_KEY
OIDC response_type key.
static struct RequestHandle * requests_tail
DLL.
#define OIDC_COOKIE_HEADER_INFORMATION_KEY
OIDC cookie header information key.
static char * get_url_parameter_copy(const struct RequestHandle *handle, const char *key)
#define OIDC_STATE_KEY
OIDC state key.
static struct GNUNET_IDENTITY_Handle * identity_handle
Handle to Identity service.
static void tld_iter(void *cls, const char *section, const char *option, const char *value)
Iterate over tlds in config.
void * libgnunet_plugin_rest_openid_connect_init(void *cls)
Entry point for the plugin.
#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE
OIDC expected response_type while authorizing.
static int check_authorization(struct RequestHandle *handle, struct GNUNET_IDENTITY_PublicKey *cid)
#define GNUNET_REST_API_NS_USERINFO
UserInfo endpoint.
static struct GNUNET_RECLAIM_AttributeList * attribute_list_merge(struct GNUNET_RECLAIM_AttributeList *list_a, struct GNUNET_RECLAIM_AttributeList *list_b)
#define GNUNET_REST_API_NS_AUTHORIZE
Authorize endpoint.
static void oidc_config_cors(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Respond to OPTIONS request.
#define OIDC_CODE_KEY
OIDC code key.
#define OIDC_CODE_VERIFIER_KEY
OIDC PKCE code verifier.
static void authorize_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Responds to authorization GET and url-encoded POST request.
#define OIDC_CLIENT_ID_KEY
OIDC client_id key.
#define OIDC_GRANT_TYPE_VALUE
OIDC grant_type key.
json_t * oidc_jwk
The RSA key used by the oidc enpoint.
#define ID_REST_STATE_POST_INIT
Done collecting egos.
static int cleanup_hashmap(void *cls, const struct GNUNET_HashCode *key, void *value)
static void lookup_redirect_uri_result(void *cls, uint32_t rd_count, const struct GNUNET_GNSRECORD_Data *rd)
static enum GNUNET_GenericReturnValue rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
static void build_redirect(void *cls)
static void oidc_attr_collect_finished_cb(void *cls)
#define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE
OIDC error key for unsupported response types.
static void consume_ticket(void *cls, const struct GNUNET_IDENTITY_PublicKey *identity, const struct GNUNET_RECLAIM_Attribute *attr, const struct GNUNET_RECLAIM_Presentation *presentation)
Collects claims and stores them in handle.
#define OIDC_ERROR_KEY_INVALID_SCOPE
OIDC error key for invalid scopes.
static void do_error(void *cls)
Task run on error, sends error message.
static void oidc_iteration_error(void *cls)
Does internal server error when iteration failed.
static void client_redirect(void *cls)
Initiate redirect back to client.
static void login_redirect(void *cls)
Redirects to login page stored in configuration file.
static int attr_in_idtoken_request(struct RequestHandle *handle, const char *attr_name)
The ego list.
char * identifier
Ego Identifier.
struct EgoEntry * prev
DLL.
char * keystring
Public key string.
struct EgoEntry * next
DLL.
struct GNUNET_IDENTITY_Ego * ego
The Ego.
void * cls
Closure for all of the callbacks.
Dynamically growing buffer.
Internal representation of the hash map.
size_t data_size
Number of bytes in data.
Connection to the GNS service.
Definition: gns_api.h:36
Handle to a lookup request.
Definition: gns_api.c:49
A 512-bit hashcode.
Handle for an ego.
Definition: identity.h:37
Handle for the service.
Definition: identity_api.c:97
Handle for an operation with the identity service.
Definition: identity_api.c:41
A private key for an identity as per LSD0001.
An identity key as per LSD0001.
Handle for a attribute iterator operation.
Definition: reclaim_api.c:182
struct GNUNET_RECLAIM_Attribute * attribute
The attribute claim.
struct GNUNET_RECLAIM_AttributeListEntry * next
DLL.
A list of GNUNET_RECLAIM_Attribute structures.
struct GNUNET_RECLAIM_AttributeListEntry * list_tail
List tail.
struct GNUNET_RECLAIM_AttributeListEntry * list_head
List head.
const char * name
The name of the attribute.
struct GNUNET_RECLAIM_Identifier credential
Referenced ID of credential (may be GNUNET_RECLAIM_ID_ZERO if self-creded)
struct GNUNET_RECLAIM_Identifier id
ID.
uint32_t type
Type of Claim.
const void * data
Binary value stored as attribute value.
size_t data_size
Number of bytes in data.
Handle for a credential iterator operation.
Definition: reclaim_api.c:249
struct GNUNET_RECLAIM_CredentialListEntry * next
DLL.
struct GNUNET_RECLAIM_Credential * credential
The credential.
A list of GNUNET_RECLAIM_Credential structures.
uint32_t type
Type/Format of Claim.
const char * name
The name of the credential.
const void * data
Binary value stored as credential value.
size_t data_size
Number of bytes in data.
struct GNUNET_RECLAIM_Identifier id
ID.
Handle to the service.
Definition: reclaim_api.c:317
Handle for an operation with the service.
Definition: reclaim_api.c:41
struct GNUNET_RECLAIM_Presentation * presentation
The credential.
struct GNUNET_RECLAIM_PresentationListEntry * next
DLL.
A list of GNUNET_RECLAIM_Presentation structures.
A credential presentation.
const void * data
Binary value stored as presentation value.
uint32_t type
Type/Format of Claim.
struct GNUNET_RECLAIM_Identifier credential_id
The credential id of which this is a presentation.
Handle for a ticket iterator operation.
Definition: reclaim_api.c:119
The authorization ticket.
struct GNUNET_IDENTITY_PublicKey audience
The ticket audience (= relying party)
struct GNUNET_IDENTITY_PublicKey identity
The ticket issuer (= the user)
struct returned by the initialization function of the plugin
char * name
Plugin name.
void * cls
The closure of the plugin.
enum GNUNET_GenericReturnValue(* process_request)(struct GNUNET_REST_RequestHandle *handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function to process a REST call.
const char * url
The url as string.
void(* proc)(struct GNUNET_REST_RequestHandle *handle, const char *url, void *cls)
Namespace to handle.
Entry in list of pending tasks.
Definition: scheduler.c:136
Time for absolute times used by GNUnet, in microseconds.
uint64_t abs_value_us
The actual value.
Time for relative time used by GNUnet, in microseconds.
OIDC needed variables.
char * login_identity
The identity chosen by the user to login.
char * client_id
The OIDC client id of the RP.
char * response_type
The OIDC response type.
int user_cancelled
User cancelled authorization/login.
struct GNUNET_IDENTITY_PublicKey client_pkey
The RP client public key.
char * redirect_uri
The OIDC redirect uri.
char * claims
The OIDC claims.
char * code_challenge
The PKCE code_challenge.
char * scope
The list of oidc scopes.
char * code_verifier
The PKCE code_verifier.
char * nonce
The OIDC nonce.
char * state
The OIDC state.
Handle for a plugin.
Definition: block.c:38
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:47
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
The request handle.
struct GNUNET_RECLAIM_TicketIterator * ticket_it
Ticket iterator.
struct GNUNET_RECLAIM_Ticket ticket
A ticket.
char * emsg
Error response message.
struct GNUNET_IDENTITY_Operation * op
IDENTITY Operation.
struct RequestHandle * prev
DLL.
struct GNUNET_RECLAIM_PresentationList * presentations
Presentations.
struct GNUNET_RECLAIM_Operation * idp_op
Idp Operation.
struct GNUNET_RECLAIM_AttributeList * attr_idtoken_list
Attribute claim list for id_token.
int response_code
Response code.
struct EgoEntry * ego_entry
IDENTITY Operation.
struct GNUNET_SCHEDULER_Task * timeout_task
ID of a task associated with the resolution process.
void * proc_cls
The closure of the result processor.
char * access_token
The passed access token.
char * redirect_prefix
The redirect prefix.
struct GNUNET_RECLAIM_AttributeIterator * attr_it
Attribute iterator.
GNUNET_REST_ResultProcessor proc
The plugin result processor.
char * redirect_suffix
The redirect suffix.
struct RequestHandle * next
DLL.
struct GNUNET_IDENTITY_PrivateKey priv_key
Pointer to ego private key.
struct GNUNET_RECLAIM_CredentialIterator * cred_it
Credential iterator.
struct GNUNET_REST_RequestHandle * rest_handle
Rest connection.
char * url
The url.
int public_client
Public client.
char * tld
The tld for redirect.
struct OIDC_Variables * oidc
OIDC variables.
struct GNUNET_RECLAIM_AttributeList * attr_userinfo_list
Attribute claim list for userinfo.
struct GNUNET_GNS_LookupRequest * gns_op
GNS lookup op.
struct GNUNET_RECLAIM_CredentialList * credentials
Credentials.
struct GNUNET_SCHEDULER_Task * consume_timeout_op
Timeout task for consume.
struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
char * edesc
Error response description.