GNUnet  0.17.6
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_buffer_lib.h"
34 #include "gnunet_strings_lib.h"
35 #include "gnunet_gns_service.h"
36 #include "gnunet_gnsrecord_lib.h"
39 #include "gnunet_reclaim_lib.h"
40 #include "gnunet_reclaim_service.h"
41 #include "gnunet_rest_lib.h"
42 #include "gnunet_rest_plugin.h"
43 #include "gnunet_signatures.h"
44 #include "microhttpd.h"
45 #include "oidc_helper.h"
46 
50 #define GNUNET_REST_API_NS_OIDC "/openid"
51 
55 #define GNUNET_REST_API_NS_OIDC_CONFIG "/.well-known/openid-configuration"
56 
60 #define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize"
61 
65 #define GNUNET_REST_API_NS_TOKEN "/openid/token"
66 
70 #define GNUNET_REST_API_JWKS "/jwks.json"
71 
75 #define GNUNET_REST_API_NS_USERINFO "/openid/userinfo"
76 
80 #define GNUNET_REST_API_NS_LOGIN "/openid/login"
81 
85 #define ID_REST_STATE_INIT 0
86 
90 #define ID_REST_STATE_POST_INIT 1
91 
95 #define OIDC_GRANT_TYPE_KEY "grant_type"
96 
100 #define OIDC_GRANT_TYPE_VALUE "authorization_code"
101 
105 #define OIDC_CODE_KEY "code"
106 
110 #define OIDC_RESPONSE_TYPE_KEY "response_type"
111 
115 #define OIDC_CLIENT_ID_KEY "client_id"
116 
120 #define OIDC_SCOPE_KEY "scope"
121 
125 #define OIDC_REDIRECT_URI_KEY "redirect_uri"
126 
130 #define OIDC_STATE_KEY "state"
131 
135 #define OIDC_NONCE_KEY "nonce"
136 
140 #define OIDC_CLAIMS_KEY "claims"
141 
145 #define OIDC_CODE_CHALLENGE_KEY "code_challenge"
146 
150 #define OIDC_CODE_VERIFIER_KEY "code_verifier"
151 
155 #define OIDC_COOKIE_EXPIRATION 3
156 
160 #define OIDC_COOKIE_HEADER_KEY "cookie"
161 
165 #define OIDC_AUTHORIZATION_HEADER_KEY "authorization"
166 
170 #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
171 
175 #define OIDC_COOKIE_HEADER_ACCESS_DENIED "Identity=Denied"
176 
180 #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
181 
185 #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
186 
190 #define OIDC_ERROR_KEY_INVALID_CLIENT "invalid_client"
191 
195 #define OIDC_ERROR_KEY_INVALID_SCOPE "invalid_scope"
196 
200 #define OIDC_ERROR_KEY_INVALID_REQUEST "invalid_request"
201 
205 #define OIDC_ERROR_KEY_INVALID_TOKEN "invalid_token"
206 
210 #define OIDC_ERROR_KEY_INVALID_COOKIE "invalid_cookie"
211 
215 #define OIDC_ERROR_KEY_SERVER_ERROR "server_error"
216 
220 #define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE "unsupported_grant_type"
221 
225 #define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE "unsupported_response_type"
226 
230 #define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT "unauthorized_client"
231 
235 #define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied"
236 
240 #define OIDC_JWK_RSA_FILENAME "jwk_rsa.json"
241 
245 #define CONSUME_TIMEOUT GNUNET_TIME_relative_multiply ( \
246  GNUNET_TIME_UNIT_SECONDS,2)
247 
251 static char *OIDC_ignored_parameter_array[] = { "display",
252  "prompt",
253  "ui_locales",
254  "response_mode",
255  "id_token_hint",
256  "login_hint",
257  "acr_values" };
258 
263 
268 
273 
277 static char *allow_methods;
278 
282 static struct EgoEntry *ego_head;
283 
287 static struct EgoEntry *ego_tail;
288 
292 static int state;
293 
298 
303 
307 static struct GNUNET_RECLAIM_Handle *idp;
308 
313 
317 struct Plugin
318 {
320 };
321 
325 json_t *oidc_jwk;
326 
331 {
336 
340  char *client_id;
341 
346 
350  char *scope;
351 
355  char *state;
356 
360  char *nonce;
361 
365  char *claims;
366 
371 
376 
381 
386 
391 
392 };
393 
397 struct EgoEntry
398 {
402  struct EgoEntry *next;
403 
407  struct EgoEntry *prev;
408 
412  char *identifier;
413 
417  char *keystring;
418 
422  struct GNUNET_IDENTITY_Ego *ego;
423 };
424 
425 
426 struct RequestHandle
427 {
431  struct RequestHandle *next;
432 
436  struct RequestHandle *prev;
437 
442 
447 
452 
457 
462 
467 
472 
477 
482 
487 
488 
493 
498 
503 
508 
509 
514 
519 
524 
529 
534 
538  void *proc_cls;
539 
543  char *url;
544 
549 
553  char *tld;
554 
559 
564 
568  char *emsg;
569 
573  char *edesc;
574 
578  int response_code;
579 
584 };
585 
590 
595 
596 
601 static void
603 {
604 
605  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
606  if (NULL != handle->timeout_task)
607  GNUNET_SCHEDULER_cancel (handle->timeout_task);
608  if (NULL != handle->attr_it)
610  if (NULL != handle->cred_it)
612  if (NULL != handle->ticket_it)
614  if (NULL != handle->idp_op)
615  GNUNET_RECLAIM_cancel (handle->idp_op);
616  if (NULL != handle->consume_timeout_op)
617  GNUNET_SCHEDULER_cancel (handle->consume_timeout_op);
618  GNUNET_free (handle->url);
619  GNUNET_free (handle->tld);
620  GNUNET_free (handle->redirect_prefix);
621  GNUNET_free (handle->redirect_suffix);
622  GNUNET_free (handle->emsg);
623  GNUNET_free (handle->edesc);
624  if (NULL != handle->gns_op)
626  if (NULL != handle->oidc)
627  {
628  GNUNET_free (handle->oidc->client_id);
629  GNUNET_free (handle->oidc->login_identity);
630  GNUNET_free (handle->oidc->nonce);
631  GNUNET_free (handle->oidc->redirect_uri);
632  GNUNET_free (handle->oidc->response_type);
633  GNUNET_free (handle->oidc->scope);
634  GNUNET_free (handle->oidc->state);
635  if (NULL != handle->oidc->claims)
636  GNUNET_free (handle->oidc->claims);
637  if (NULL != handle->oidc->code_challenge)
638  GNUNET_free (handle->oidc->code_challenge);
639  GNUNET_free (handle->oidc);
640  }
641  if (NULL!=handle->attr_idtoken_list)
642  GNUNET_RECLAIM_attribute_list_destroy (handle->attr_idtoken_list);
643  if (NULL!=handle->attr_userinfo_list)
644  GNUNET_RECLAIM_attribute_list_destroy (handle->attr_userinfo_list);
645  if (NULL!=handle->credentials)
647  if (NULL!=handle->presentations)
651  handle);
652  if (NULL != handle->access_token)
653  GNUNET_free (handle->access_token);
655 }
656 
657 
663 static void
664 do_error (void *cls)
665 {
666  struct RequestHandle *handle = cls;
667  struct MHD_Response *resp;
668  char *json_error;
669 
670  GNUNET_asprintf (&json_error,
671  "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
672  handle->emsg,
673  (NULL != handle->edesc) ? handle->edesc : "",
674  (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
675  (NULL != handle->oidc->state) ? handle->oidc->state : "",
676  (NULL != handle->oidc->state) ? "\"" : "");
677  if (0 == handle->response_code)
678  handle->response_code = MHD_HTTP_BAD_REQUEST;
679  resp = GNUNET_REST_create_response (json_error);
680  if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
681  GNUNET_assert (MHD_NO !=
682  MHD_add_response_header (resp,
683  MHD_HTTP_HEADER_WWW_AUTHENTICATE,
684  "Basic"));
685  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
686  MHD_HTTP_HEADER_CONTENT_TYPE,
687  "application/json"));
688  handle->proc (handle->proc_cls, resp, handle->response_code);
690  GNUNET_free (json_error);
691 }
692 
693 
700 static void
701 do_userinfo_error (void *cls)
702 {
703  struct RequestHandle *handle = cls;
704  struct MHD_Response *resp;
705  char *error;
706 
708  "Error: %s\n", handle->edesc);
709  GNUNET_asprintf (&error,
710  "error=\"%s\", error_description=\"%s\"",
711  handle->emsg,
712  (NULL != handle->edesc) ? handle->edesc : "");
713  resp = GNUNET_REST_create_response ("");
714  GNUNET_assert (MHD_NO !=
715  MHD_add_response_header (resp,
716  MHD_HTTP_HEADER_WWW_AUTHENTICATE,
717  "Bearer"));
718  handle->proc (handle->proc_cls, resp, handle->response_code);
720  GNUNET_free (error);
721 }
722 
723 
729 static void
730 do_redirect_error (void *cls)
731 {
732  struct RequestHandle *handle = cls;
733  struct MHD_Response *resp;
734  char *redirect;
735 
736  GNUNET_asprintf (&redirect,
737  "%s?error=%s&error_description=%s%s%s",
738  handle->oidc->redirect_uri,
739  handle->emsg,
740  handle->edesc,
741  (NULL != handle->oidc->state) ? "&state=" : "",
742  (NULL != handle->oidc->state) ? handle->oidc->state : "");
743  resp = GNUNET_REST_create_response ("");
744  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
745  "Location", redirect));
746  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
748  GNUNET_free (redirect);
749 }
750 
751 
757 static void
758 do_timeout (void *cls)
759 {
760  struct RequestHandle *handle = cls;
761 
762  handle->timeout_task = NULL;
763  do_error (handle);
764 }
765 
766 
774 static void
776  const char *url,
777  void *cls)
778 {
779  struct MHD_Response *resp;
780  struct RequestHandle *handle = cls;
781 
782  // For now, independent of path return all options
783  resp = GNUNET_REST_create_response (NULL);
784  MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
785  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
787  return;
788 }
789 
790 
794 static void
796 {
797  struct GNUNET_HashCode cache_key;
798  char *cookies;
799  struct GNUNET_TIME_Absolute current_time, *relog_time;
800  char delimiter[] = "; ";
801  char *tmp_cookies;
802  char *token;
803  char *value;
804 
805  // gets identity of login try with cookie
807  strlen (OIDC_COOKIE_HEADER_KEY),
808  &cache_key);
810  ->header_param_map,
811  &cache_key))
812  {
813  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cookie found\n");
814  return;
815  }
816  // splits cookies and find 'Identity' cookie
817  tmp_cookies =
818  GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
819  &cache_key);
820  cookies = GNUNET_strdup (tmp_cookies);
821  token = strtok (cookies, delimiter);
822  handle->oidc->user_cancelled = GNUNET_NO;
823  handle->oidc->login_identity = NULL;
824  if (NULL == token)
825  {
827  "Unable to parse cookie: %s\n",
828  cookies);
829  GNUNET_free (cookies);
830  return;
831  }
832 
833  while (NULL != token)
834  {
835  if (0 == strcmp (token, OIDC_COOKIE_HEADER_ACCESS_DENIED))
836  {
837  handle->oidc->user_cancelled = GNUNET_YES;
838  GNUNET_free (cookies);
839  return;
840  }
841  if (NULL != strstr (token, OIDC_COOKIE_HEADER_INFORMATION_KEY))
842  break;
843  token = strtok (NULL, delimiter);
844  }
845  if (NULL == token)
846  {
848  "No cookie value to process: %s\n",
849  cookies);
850  GNUNET_free (cookies);
851  return;
852  }
853  GNUNET_CRYPTO_hash (token, strlen (token), &cache_key);
854  if (GNUNET_NO ==
856  {
857  GNUNET_log (
859  "Found cookie `%s', but no corresponding expiration entry present...\n",
860  token);
861  GNUNET_free (cookies);
862  return;
863  }
864  relog_time =
866  current_time = GNUNET_TIME_absolute_get ();
867  // 30 min after old login -> redirect to login
868  if (current_time.abs_value_us > relog_time->abs_value_us)
869  {
871  "Found cookie `%s', but it is expired.\n",
872  token);
873  GNUNET_free (cookies);
874  return;
875  }
876  value = strtok (token, OIDC_COOKIE_HEADER_INFORMATION_KEY);
877  GNUNET_assert (NULL != value);
878  handle->oidc->login_identity = GNUNET_strdup (value);
879  GNUNET_free (cookies);
880 }
881 
882 
891 json_t *
893 {
894  json_t *jwk;
895  json_error_t error;
896 
897  jwk = json_load_file (filename, JSON_DECODE_ANY, &error);
898 
899  if (! jwk)
900  {
902  ("Could not read OIDC RSA key from config file; %s\n"),
903  error.text);
904  }
905 
906  return jwk;
907 }
908 
916 static int
918  json_t *jwk)
919 {
920  if (json_dump_file (jwk, filename, JSON_INDENT (2)))
921  {
923  ("Could not write OIDC RSA key to file %s\n"),
924  filename);
926  }
927  else
928  return GNUNET_OK;
929 }
930 
936 json_t *
938 {
939  json_t *jwk;
940  jwk = json_pack ("{s:s,s:i}", "kty", "RSA", "bits", 2048);
941  jose_jwk_gen (NULL, jwk);
942  json_incref (jwk);
943  return jwk;
944 }
945 
951 char *
952 get_oidc_dir_path (void *cls)
953 {
954  char *oidc_directory;
955  struct RequestHandle *handle = cls;
956 
957  // Read OIDC directory from config
959  "reclaim-rest-plugin",
960  "oidc_dir",
961  &oidc_directory))
962  {
963  // Could not read Config file
965  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
966  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
968  return NULL;
969  }
970 
971  return oidc_directory;
972 }
973 
979 char *
980 get_oidc_jwk_path (void *cls)
981 {
982  char *oidc_directory;
983  char *oidc_jwk_path;
984 
985  oidc_directory = get_oidc_dir_path (cls);
986 
987  // Create path to file
988  GNUNET_asprintf (&oidc_jwk_path, "%s/%s", oidc_directory,
990 
991  return oidc_jwk_path;
992 }
993 
994 
998 static void
999 login_redirect (void *cls)
1000 {
1001  char *login_base_url;
1002  char *new_redirect;
1003  char *tmp;
1004  struct MHD_Response *resp;
1005  struct GNUNET_Buffer buf = { 0 };
1006  struct RequestHandle *handle = cls;
1007 
1009  "reclaim-rest-plugin",
1010  "address",
1011  &login_base_url))
1012  {
1013  GNUNET_buffer_write_str (&buf, login_base_url);
1015  "?%s=%s",
1017  handle->oidc->response_type);
1019  "&%s=%s",
1021  handle->oidc->client_id);
1022  GNUNET_STRINGS_urlencode (handle->oidc->redirect_uri,
1023  strlen (handle->oidc->redirect_uri),
1024  &tmp);
1026  "&%s=%s",
1028  tmp);
1029  GNUNET_free (tmp);
1030  GNUNET_STRINGS_urlencode (handle->oidc->scope,
1031  strlen (handle->oidc->scope),
1032  &tmp);
1034  "&%s=%s",
1036  tmp);
1037  GNUNET_free (tmp);
1038  if (NULL != handle->oidc->state)
1039  {
1040  GNUNET_STRINGS_urlencode (handle->oidc->state,
1041  strlen (handle->oidc->state),
1042  &tmp);
1044  "&%s=%s",
1046  handle->oidc->state);
1047  GNUNET_free (tmp);
1048  }
1049  if (NULL != handle->oidc->code_challenge)
1050  {
1052  "&%s=%s",
1054  handle->oidc->code_challenge);
1055  }
1056  if (NULL != handle->oidc->nonce)
1057  {
1059  "&%s=%s",
1061  handle->oidc->nonce);
1062  }
1063  if (NULL != handle->oidc->claims)
1064  {
1065  GNUNET_STRINGS_urlencode (handle->oidc->claims,
1066  strlen (handle->oidc->claims),
1067  &tmp);
1069  "&%s=%s",
1071  tmp);
1072  GNUNET_free (tmp);
1073  }
1074  new_redirect = GNUNET_buffer_reap_str (&buf);
1075  resp = GNUNET_REST_create_response ("");
1076  MHD_add_response_header (resp, "Location", new_redirect);
1077  GNUNET_free (login_base_url);
1078  }
1079  else
1080  {
1082  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1083  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1085  return;
1086  }
1087  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1088  GNUNET_free (new_redirect);
1090 }
1091 
1092 
1096 static void
1098 {
1099  struct RequestHandle *handle = cls;
1100 
1102  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1104 }
1105 
1106 
1111 static void
1113  const struct GNUNET_RECLAIM_Ticket *ticket,
1114  const struct
1115  GNUNET_RECLAIM_PresentationList *presentation)
1116 {
1117  struct RequestHandle *handle = cls;
1118  struct MHD_Response *resp;
1119  char *ticket_str;
1120  char *redirect_uri;
1121  char *code_string;
1122 
1123  handle->idp_op = NULL;
1124  if (NULL == ticket)
1125  {
1127  handle->edesc = GNUNET_strdup ("Server cannot generate ticket.");
1129  return;
1130  }
1131  handle->ticket = *ticket;
1132  ticket_str =
1134  sizeof(struct GNUNET_RECLAIM_Ticket));
1135  code_string = OIDC_build_authz_code (&handle->priv_key,
1136  &handle->ticket,
1137  handle->attr_idtoken_list,
1138  presentation,
1139  handle->oidc->nonce,
1140  handle->oidc->code_challenge);
1141  if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
1142  (NULL != handle->tld))
1143  {
1144  GNUNET_asprintf (&redirect_uri,
1145  "%s.%s/%s%s%s=%s&state=%s",
1146  handle->redirect_prefix,
1147  handle->tld,
1148  handle->redirect_suffix,
1149  (NULL == strchr (handle->redirect_suffix, '?') ? "?" :
1150  "&"),
1151  handle->oidc->response_type,
1152  code_string,
1153  handle->oidc->state);
1154  }
1155  else
1156  {
1157  GNUNET_asprintf (&redirect_uri,
1158  "%s%s%s=%s&state=%s",
1159  handle->oidc->redirect_uri,
1160  (NULL == strchr (handle->oidc->redirect_uri, '?') ? "?" :
1161  "&"),
1162  handle->oidc->response_type,
1163  code_string,
1164  handle->oidc->state);
1165  }
1166  resp = GNUNET_REST_create_response ("");
1167  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
1168  "Location", redirect_uri));
1169  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1171  GNUNET_free (redirect_uri);
1172  GNUNET_free (ticket_str);
1173  GNUNET_free (code_string);
1174 }
1175 
1176 
1177 static struct GNUNET_RECLAIM_AttributeList*
1179  struct GNUNET_RECLAIM_AttributeList *list_b)
1180 {
1181  struct GNUNET_RECLAIM_AttributeList *merged_list;
1182  struct GNUNET_RECLAIM_AttributeListEntry *le_a;
1183  struct GNUNET_RECLAIM_AttributeListEntry *le_b;
1184  struct GNUNET_RECLAIM_AttributeListEntry *le_m;
1185 
1186  merged_list = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
1187  for (le_a = list_a->list_head; NULL != le_a; le_a = le_a->next)
1188  {
1191  &le_a->attribute->
1192  credential,
1193  le_a->attribute->type,
1194  le_a->attribute->data,
1195  le_a->attribute->data_size);
1196  le_m->attribute->id = le_a->attribute->id;
1197  le_m->attribute->flag = le_a->attribute->flag;
1198  le_m->attribute->credential = le_a->attribute->credential;
1199  GNUNET_CONTAINER_DLL_insert (merged_list->list_head,
1200  merged_list->list_tail,
1201  le_m);
1202  }
1203  le_m = NULL;
1204  for (le_b = list_b->list_head; NULL != le_b; le_b = le_b->next)
1205  {
1206  for (le_m = merged_list->list_head; NULL != le_m; le_m = le_m->next)
1207  {
1209  &le_b->attribute->id))
1210  break;
1211  }
1212  if (NULL != le_m)
1213  continue;
1216  &le_b->attribute->
1217  credential,
1218  le_b->attribute->type,
1219  le_b->attribute->data,
1220  le_b->attribute->data_size);
1221  le_m->attribute->id = le_b->attribute->id;
1222  le_m->attribute->flag = le_b->attribute->flag;
1223  le_m->attribute->credential = le_b->attribute->credential;
1224  GNUNET_CONTAINER_DLL_insert (merged_list->list_head,
1225  merged_list->list_tail,
1226  le_m);
1227  }
1228  return merged_list;
1229 }
1230 
1231 
1232 static void
1234 {
1235  struct RequestHandle *handle = cls;
1236  struct GNUNET_RECLAIM_AttributeList *merged_list;
1237  struct GNUNET_RECLAIM_AttributeListEntry *le_m;
1238 
1239  handle->cred_it = NULL;
1240  merged_list = attribute_list_merge (handle->attr_idtoken_list,
1241  handle->attr_userinfo_list);
1242  for (le_m = merged_list->list_head; NULL != le_m; le_m = le_m->next)
1244  "List Attribute in ticket to issue: %s\n",
1245  le_m->attribute->name);
1247  &handle->priv_key,
1248  &handle->oidc->client_pkey,
1249  merged_list,
1251  handle);
1253 }
1254 
1255 
1259 static void
1261  const struct GNUNET_IDENTITY_PublicKey *identity,
1262  const struct GNUNET_RECLAIM_Credential *cred)
1263 {
1264  struct RequestHandle *handle = cls;
1267 
1268  for (ale = handle->credentials->list_head; NULL != ale; ale = ale->next)
1269  {
1271  &cred->id))
1272  continue;
1275  return;
1276  }
1277 
1278  for (le = handle->attr_idtoken_list->list_head; NULL != le; le = le->next)
1279  {
1281  &cred->id))
1282  continue;
1286  cred->type,
1287  cred->data,
1288  cred->data_size);
1289  GNUNET_CONTAINER_DLL_insert (handle->credentials->list_head,
1290  handle->credentials->list_tail,
1291  ale);
1292  }
1294 }
1295 
1296 
1297 static void
1299 {
1300  struct RequestHandle *handle = cls;
1301 
1302  handle->attr_it = NULL;
1303  handle->ticket_it = NULL;
1304  if (NULL == handle->attr_idtoken_list->list_head)
1305  {
1307  handle->edesc = GNUNET_strdup ("The requested scope is not available.");
1309  return;
1310  }
1311  handle->credentials = GNUNET_new (struct GNUNET_RECLAIM_CredentialList);
1312  handle->cred_it =
1314  &handle->priv_key,
1316  handle,
1318  handle,
1320  handle);
1321 
1322 }
1323 
1324 
1325 static int
1327  const char *attr_name,
1328  const char *claims_parameter)
1329 {
1330  int ret = GNUNET_NO;
1331  json_t *root;
1332  json_error_t error;
1333  json_t *claims_j;
1334  const char *key;
1335  json_t *value;
1336 
1339  attr_name))
1340  return GNUNET_YES;
1341 
1343  if (NULL != handle->oidc->claims)
1344  {
1345  root = json_loads (handle->oidc->claims, JSON_DECODE_ANY, &error);
1346  claims_j = json_object_get (root, claims_parameter);
1347  /* obj is a JSON object */
1348  if (NULL != claims_j)
1349  {
1350  json_object_foreach (claims_j, key, value) {
1351  if (0 != strcmp (attr_name, key))
1352  continue;
1353  ret = GNUNET_YES;
1354  break;
1355  }
1356  }
1357  json_decref (root);
1358  }
1359  return ret;
1360 }
1361 
1362 
1363 static int
1365  const char *attr_name)
1366 {
1367  return attr_in_claims_request (handle, attr_name, "id_token");
1368 }
1369 
1370 
1371 static int
1373  const char *attr_name)
1374 {
1375  return attr_in_claims_request (handle, attr_name, "userinfo");
1376 }
1377 
1378 
1382 static void
1384  const struct GNUNET_IDENTITY_PublicKey *identity,
1385  const struct GNUNET_RECLAIM_Attribute *attr)
1386 {
1387  struct RequestHandle *handle = cls;
1390  {
1393  &attr->credential,
1394  attr->type,
1395  attr->data,
1396  attr->data_size);
1397  le->attribute->id = attr->id;
1398  le->attribute->flag = attr->flag;
1399  le->attribute->credential = attr->credential;
1400  GNUNET_CONTAINER_DLL_insert (handle->attr_idtoken_list->list_head,
1401  handle->attr_idtoken_list->list_tail,
1402  le);
1403  }
1405  {
1408  &attr->credential,
1409  attr->type,
1410  attr->data,
1411  attr->data_size);
1412  le->attribute->id = attr->id;
1413  le->attribute->flag = attr->flag;
1414  le->attribute->credential = attr->credential;
1415  GNUNET_CONTAINER_DLL_insert (handle->attr_userinfo_list->list_head,
1416  handle->attr_userinfo_list->list_tail,
1417  le);
1418  }
1419 
1421 }
1422 
1423 
1427 static void
1428 code_redirect (void *cls)
1429 {
1430  struct RequestHandle *handle = cls;
1431  struct GNUNET_TIME_Absolute current_time;
1432  struct GNUNET_TIME_Absolute *relog_time;
1434  struct GNUNET_IDENTITY_PublicKey ego_pkey;
1435  struct GNUNET_HashCode cache_key;
1436  char *identity_cookie;
1437 
1438  GNUNET_asprintf (&identity_cookie,
1439  "Identity=%s",
1440  handle->oidc->login_identity);
1441  GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1442  GNUNET_free (identity_cookie);
1443  // No login time for identity -> redirect to login
1444  if (GNUNET_YES ==
1446  {
1447  relog_time =
1449  current_time = GNUNET_TIME_absolute_get ();
1450  // 30 min after old login -> redirect to login
1451  if (current_time.abs_value_us <= relog_time->abs_value_us)
1452  {
1453  if (GNUNET_OK !=
1455  ->login_identity,
1456  &pubkey))
1457  {
1459  handle->edesc =
1460  GNUNET_strdup ("The cookie of a login identity is not valid");
1462  return;
1463  }
1464  // iterate over egos and compare their public key
1465  for (handle->ego_entry = ego_head; NULL != handle->ego_entry;
1466  handle->ego_entry = handle->ego_entry->next)
1467  {
1468  GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1469  if (0 == GNUNET_memcmp (&ego_pkey, &pubkey))
1470  {
1471  handle->priv_key =
1472  *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1473  handle->attr_idtoken_list =
1475  handle->attr_userinfo_list =
1477  handle->attr_it =
1479  &handle->priv_key,
1481  handle,
1483  handle,
1485  handle);
1486  return;
1487  }
1488  }
1490  return;
1491  }
1492  }
1493 }
1494 
1495 
1496 static void
1497 build_redirect (void *cls)
1498 {
1499  struct RequestHandle *handle = cls;
1500  struct MHD_Response *resp;
1501  char *redirect_uri;
1502 
1503  if (GNUNET_YES == handle->oidc->user_cancelled)
1504  {
1505  if ((NULL != handle->redirect_prefix) &&
1506  (NULL != handle->redirect_suffix) && (NULL != handle->tld))
1507  {
1508  GNUNET_asprintf (&redirect_uri,
1509  "%s.%s/%s?error=%s&error_description=%s&state=%s",
1510  handle->redirect_prefix,
1511  handle->tld,
1512  handle->redirect_suffix,
1513  "access_denied",
1514  "User denied access",
1515  handle->oidc->state);
1516  }
1517  else
1518  {
1519  GNUNET_asprintf (&redirect_uri,
1520  "%s?error=%s&error_description=%s&state=%s",
1521  handle->oidc->redirect_uri,
1522  "access_denied",
1523  "User denied access",
1524  handle->oidc->state);
1525  }
1526  resp = GNUNET_REST_create_response ("");
1527  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
1528  "Location",
1529  redirect_uri));
1530  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1532  GNUNET_free (redirect_uri);
1533  return;
1534  }
1536 }
1537 
1538 
1539 static void
1541  uint32_t rd_count,
1542  const struct GNUNET_GNSRECORD_Data *rd)
1543 {
1544  struct RequestHandle *handle = cls;
1545  char *tmp;
1546  char *tmp_key_str;
1547  char *pos;
1548  struct GNUNET_IDENTITY_PublicKey redirect_zone;
1549 
1550  handle->gns_op = NULL;
1551  if (0 == rd_count)
1552  {
1554  handle->edesc =
1555  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1557  return;
1558  }
1559  for (int i = 0; i < rd_count; i++)
1560  {
1561  if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type)
1562  continue;
1563  if (0 != strncmp (rd[i].data, handle->oidc->redirect_uri, rd[i].data_size))
1564  continue;
1565  tmp = GNUNET_strndup (rd[i].data, rd[i].data_size);
1566  if (NULL == strstr (tmp, handle->oidc->client_id))
1567  {
1569  "Redirect uri %s does not contain client_id %s\n",
1570  tmp,
1571  handle->oidc->client_id);
1572  }
1573  else
1574  {
1575  pos = strrchr (tmp, (unsigned char) '.');
1576  if (NULL == pos)
1577  {
1579  "Redirect uri %s contains client_id but is malformed\n",
1580  tmp);
1581  GNUNET_free (tmp);
1582  continue;
1583  }
1584  *pos = '\0';
1585  handle->redirect_prefix = GNUNET_strdup (tmp);
1586  tmp_key_str = pos + 1;
1587  pos = strchr (tmp_key_str, (unsigned char) '/');
1588  if (NULL == pos)
1589  {
1591  "Redirect uri %s contains client_id but is malformed\n",
1592  tmp);
1593  GNUNET_free (tmp);
1594  continue;
1595  }
1596  *pos = '\0';
1597  handle->redirect_suffix = GNUNET_strdup (pos + 1);
1598 
1599  GNUNET_STRINGS_string_to_data (tmp_key_str,
1600  strlen (tmp_key_str),
1601  &redirect_zone,
1602  sizeof(redirect_zone));
1603  }
1605  GNUNET_free (tmp);
1606  return;
1607  }
1609  handle->edesc =
1610  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1612 }
1613 
1614 
1618 static void
1619 client_redirect (void *cls)
1620 {
1621  struct RequestHandle *handle = cls;
1622 
1623  /* Lookup client redirect uri to verify request */
1624  handle->gns_op =
1627  &handle->oidc->client_pkey,
1631  handle);
1632 }
1633 
1634 
1635 static char *
1636 get_url_parameter_copy (const struct RequestHandle *handle, const char *key)
1637 {
1638  struct GNUNET_HashCode hc;
1639  char *value;
1640  char *res;
1641 
1642  GNUNET_CRYPTO_hash (key, strlen (key), &hc);
1644  ->url_param_map,
1645  &hc))
1646  return NULL;
1647  value =
1648  GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, &hc);
1649  if (NULL == value)
1650  return NULL;
1651  GNUNET_STRINGS_urldecode (value, strlen (value), &res);
1652  return res;
1653 }
1654 
1655 
1662 static void
1664 {
1665  struct RequestHandle *handle = cls;
1666  struct GNUNET_HashCode cache_key;
1667 
1668  char *expected_scope;
1669  char delimiter[] = " ";
1670  int number_of_ignored_parameter, iterator;
1671 
1672 
1673  // REQUIRED value: redirect_uri
1674  handle->oidc->redirect_uri =
1676  if (NULL == handle->oidc->redirect_uri)
1677  {
1679  handle->edesc = GNUNET_strdup ("missing parameter redirect_uri");
1681  return;
1682  }
1683 
1684  // REQUIRED value: response_type
1685  handle->oidc->response_type =
1687  if (NULL == handle->oidc->response_type)
1688  {
1690  handle->edesc = GNUNET_strdup ("missing parameter response_type");
1692  return;
1693  }
1694 
1695  // REQUIRED value: scope
1697  if (NULL == handle->oidc->scope)
1698  {
1700  handle->edesc = GNUNET_strdup ("missing parameter scope");
1702  return;
1703  }
1704 
1705  // OPTIONAL value: nonce
1707 
1708  // OPTIONAL value: claims
1710 
1711  // TODO check other values if needed
1712  number_of_ignored_parameter =
1713  sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1714  for (iterator = 0; iterator < number_of_ignored_parameter; iterator++)
1715  {
1718  &cache_key);
1719  if (GNUNET_YES ==
1721  ->url_param_map,
1722  &cache_key))
1723  {
1725  GNUNET_asprintf (&handle->edesc,
1726  "Server will not handle parameter: %s",
1729  return;
1730  }
1731  }
1732 
1733  // We only support authorization code flows.
1734  if (0 != strcmp (handle->oidc->response_type,
1736  {
1738  handle->edesc = GNUNET_strdup ("The authorization server does not support "
1739  "obtaining this authorization code.");
1741  return;
1742  }
1743 
1744  // Checks if scope contains 'openid'
1745  expected_scope = GNUNET_strdup (handle->oidc->scope);
1746  char *test;
1747  test = strtok (expected_scope, delimiter);
1748  while (NULL != test)
1749  {
1750  if (0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope))
1751  break;
1752  test = strtok (NULL, delimiter);
1753  }
1754  if (NULL == test)
1755  {
1757  handle->edesc =
1758  GNUNET_strdup ("The requested scope is invalid, unknown, or malformed.");
1760  GNUNET_free (expected_scope);
1761  return;
1762  }
1763 
1764  GNUNET_free (expected_scope);
1765  if ((NULL == handle->oidc->login_identity) &&
1766  (GNUNET_NO == handle->oidc->user_cancelled))
1768  else
1770 }
1771 
1772 
1776 static void
1777 tld_iter (void *cls, const char *section, const char *option, const char *value)
1778 {
1779  struct RequestHandle *handle = cls;
1781 
1782  if (GNUNET_OK !=
1784  {
1785  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping non key %s\n", value);
1786  return;
1787  }
1788  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1789  handle->tld = GNUNET_strdup (option + 1);
1790 }
1791 
1792 
1800 static void
1802  const char *url,
1803  void *cls)
1804 {
1805  struct RequestHandle *handle = cls;
1806  struct EgoEntry *tmp_ego;
1807  const struct GNUNET_IDENTITY_PrivateKey *priv_key;
1809 
1811 
1812  // RECOMMENDED value: state - REQUIRED for answers
1814 
1815  // REQUIRED value: client_id
1817  if (NULL == handle->oidc->client_id)
1818  {
1820  handle->edesc = GNUNET_strdup ("missing parameter client_id");
1821  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1823  return;
1824  }
1825 
1826  // OPTIONAL value: code_challenge
1827  handle->oidc->code_challenge = get_url_parameter_copy (handle,
1829  if (NULL == handle->oidc->code_challenge)
1830  {
1832  "OAuth authorization request does not contain PKCE parameters!\n");
1833  }
1834 
1835  if (GNUNET_OK !=
1837  &handle->oidc->client_pkey))
1838  {
1840  handle->edesc = GNUNET_strdup ("The client is not authorized to request an "
1841  "authorization code using this method.");
1842  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1844  return;
1845  }
1846 
1847  // If we know this identity, translated the corresponding TLD
1848  // TODO: We might want to have a reverse lookup functionality for TLDs?
1849  for (tmp_ego = ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
1850  {
1851  priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
1852  GNUNET_IDENTITY_key_get_public (priv_key, &pkey);
1853  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1854  {
1855  handle->tld = GNUNET_strdup (tmp_ego->identifier);
1856  handle->ego_entry = ego_tail;
1857  }
1858  }
1859  if (NULL == handle->tld)
1861  if (NULL == handle->tld)
1862  handle->tld = GNUNET_strdup (handle->oidc->client_id);
1864 }
1865 
1866 
1874 static void
1876  const char *url,
1877  void *cls)
1878 {
1879  struct MHD_Response *resp = GNUNET_REST_create_response ("");
1880  struct RequestHandle *handle = cls;
1881  struct GNUNET_HashCode cache_key;
1882  struct GNUNET_TIME_Absolute *current_time;
1883  struct GNUNET_TIME_Absolute *last_time;
1884  char *cookie;
1885  char *header_val;
1886  json_t *root;
1887  json_error_t error;
1888  json_t *identity;
1889  char term_data[handle->rest_handle->data_size + 1];
1890 
1891  term_data[handle->rest_handle->data_size] = '\0';
1892  GNUNET_memcpy (term_data,
1893  handle->rest_handle->data,
1894  handle->rest_handle->data_size);
1895  root = json_loads (term_data, JSON_DECODE_ANY, &error);
1896  identity = json_object_get (root, "identity");
1897  if (! json_is_string (identity))
1898  {
1900  "Error parsing json string from %s\n",
1901  term_data);
1902  handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1903  json_decref (root);
1905  return;
1906  }
1907  GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1908  GNUNET_asprintf (&header_val,
1909  "%s;Max-Age=%d",
1910  cookie,
1912  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
1913  "Set-Cookie", header_val));
1914  GNUNET_assert (MHD_NO !=
1915  MHD_add_response_header (resp,
1916  "Access-Control-Allow-Methods",
1917  "POST"));
1918  GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1919 
1920  if (0 != strcmp (json_string_value (identity), "Denied"))
1921  {
1922  current_time = GNUNET_new (struct GNUNET_TIME_Absolute);
1923  *current_time = GNUNET_TIME_relative_to_absolute (
1926  last_time =
1928  GNUNET_free (last_time);
1930  &cache_key,
1931  current_time,
1933  }
1934  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1935  GNUNET_free (cookie);
1936  GNUNET_free (header_val);
1937  json_decref (root);
1939 }
1940 
1941 
1942 static int
1944  char **client_id,
1945  char **client_secret)
1946 {
1947  struct GNUNET_HashCode cache_key;
1948  char *authorization;
1949  char *credentials;
1950  char *basic_authorization;
1951  char *client_id_tmp;
1952  char *pass;
1953 
1956  &cache_key);
1958  ->header_param_map,
1959  &cache_key))
1960  return GNUNET_SYSERR;
1961  authorization =
1962  GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
1963  &cache_key);
1964 
1965  // split header in "Basic" and [content]
1966  credentials = strtok (authorization, " ");
1967  if ((NULL == credentials) || (0 != strcmp ("Basic", credentials)))
1968  return GNUNET_SYSERR;
1969  credentials = strtok (NULL, " ");
1970  if (NULL == credentials)
1971  return GNUNET_SYSERR;
1972  GNUNET_STRINGS_base64_decode (credentials,
1973  strlen (credentials),
1974  (void **) &basic_authorization);
1975 
1976  if (NULL == basic_authorization)
1977  return GNUNET_SYSERR;
1978  client_id_tmp = strtok (basic_authorization, ":");
1979  if (NULL == client_id_tmp)
1980  {
1981  GNUNET_free (basic_authorization);
1982  return GNUNET_SYSERR;
1983  }
1984  pass = strtok (NULL, ":");
1985  if (NULL == pass)
1986  {
1987  GNUNET_free (basic_authorization);
1988  return GNUNET_SYSERR;
1989  }
1990  *client_id = strdup (client_id_tmp);
1991  *client_secret = strdup (pass);
1992  GNUNET_free (basic_authorization);
1993  return GNUNET_OK;
1994 }
1995 
1996 
1997 static int
1999  char **client_id,
2000  char **client_secret)
2001 {
2002  struct GNUNET_HashCode cache_key;
2003  char *client_id_tmp;
2004  char *pass;
2005 
2006  GNUNET_CRYPTO_hash ("client_id",
2007  strlen ("client_id"),
2008  &cache_key);
2010  ->url_param_map,
2011  &cache_key))
2012  return GNUNET_SYSERR;
2013  client_id_tmp = GNUNET_CONTAINER_multihashmap_get (
2014  handle->rest_handle->url_param_map,
2015  &cache_key);
2016  if (NULL == client_id_tmp)
2017  return GNUNET_SYSERR;
2018  *client_id = strdup (client_id_tmp);
2019  GNUNET_CRYPTO_hash ("client_secret",
2020  strlen ("client_secret"),
2021  &cache_key);
2023  ->url_param_map,
2024  &cache_key))
2025  {
2026  GNUNET_free (*client_id);
2027  *client_id = NULL;
2028  return GNUNET_SYSERR;
2029  }
2030  pass = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
2031  &cache_key);
2032  if (NULL == pass)
2033  {
2034  GNUNET_free (*client_id);
2035  *client_id = NULL;
2036  return GNUNET_SYSERR;
2037  }
2038  *client_secret = strdup (pass);
2039  return GNUNET_OK;
2040 }
2041 
2042 
2043 static int
2045  struct GNUNET_IDENTITY_PublicKey *cid)
2046 {
2047  char *expected_pass;
2048  char *received_cid;
2049  char *received_cpw;
2050  char *pkce_cv;
2051 
2053  &received_cid,
2054  &received_cpw))
2055  {
2057  "Received client credentials in HTTP AuthZ header\n");
2058  }
2060  &received_cid,
2061  &received_cpw))
2062  {
2064  "Received client credentials in POST body\n");
2065  }
2066  else
2067  {
2070  if (NULL == pkce_cv)
2071  {
2073  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2074  return GNUNET_SYSERR;
2075  }
2076  handle->public_client = GNUNET_YES;
2077  GNUNET_free (pkce_cv);
2079  GNUNET_STRINGS_string_to_data (received_cid,
2080  strlen (received_cid),
2081  cid,
2082  sizeof(struct GNUNET_IDENTITY_PublicKey));
2083  GNUNET_free (received_cid);
2084  return GNUNET_OK;
2085 
2086  }
2087 
2088  // check client password
2090  "reclaim-rest-plugin",
2091  "OIDC_CLIENT_HMAC_SECRET",
2092  &expected_pass))
2093  {
2094  if (0 != strcmp (expected_pass, received_cpw))
2095  {
2096  GNUNET_free (expected_pass);
2098  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2099  GNUNET_free (received_cpw);
2100  GNUNET_free (received_cid);
2101  return GNUNET_SYSERR;
2102  }
2103  GNUNET_free (expected_pass);
2104  }
2105  else
2106  {
2107  GNUNET_free (received_cpw);
2108  GNUNET_free (received_cid);
2110  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2111  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2112  return GNUNET_SYSERR;
2113  }
2114  // check client_id
2115  for (handle->ego_entry = ego_head; NULL != handle->ego_entry;
2116  handle->ego_entry = handle->ego_entry->next)
2117  {
2118  if (0 == strcmp (handle->ego_entry->keystring, received_cid))
2119  break;
2120  }
2121  if (NULL == handle->ego_entry)
2122  {
2123  GNUNET_free (received_cpw);
2124  GNUNET_free (received_cid);
2126  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2127  return GNUNET_SYSERR;
2128  }
2129  GNUNET_STRINGS_string_to_data (received_cid,
2130  strlen (received_cid),
2131  cid,
2132  sizeof(struct GNUNET_IDENTITY_PublicKey));
2133 
2134  GNUNET_free (received_cpw);
2135  GNUNET_free (received_cid);
2136  return GNUNET_OK;
2137 }
2138 
2139 
2140 const struct EgoEntry *
2142  struct GNUNET_IDENTITY_PublicKey *test_key)
2143 {
2144  struct EgoEntry *ego_entry;
2145  struct GNUNET_IDENTITY_PublicKey pub_key;
2146 
2147  for (ego_entry = ego_head; NULL != ego_entry;
2148  ego_entry = ego_entry->next)
2149  {
2150  GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
2151  if (0 == GNUNET_memcmp (&pub_key, test_key))
2152  return ego_entry;
2153  }
2154  return NULL;
2155 }
2156 
2157 
2165 static void
2167  const char *url,
2168  void *cls)
2169 {
2170  struct RequestHandle *handle = cls;
2171  const struct EgoEntry *ego_entry = NULL;
2172  struct GNUNET_TIME_Relative expiration_time;
2173  struct GNUNET_RECLAIM_AttributeList *cl = NULL;
2174  struct GNUNET_RECLAIM_PresentationList *pl = NULL;
2176  struct GNUNET_IDENTITY_PublicKey cid;
2177  struct GNUNET_HashCode cache_key;
2178  struct MHD_Response *resp = NULL;
2179  char *grant_type = NULL;
2180  char *code = NULL;
2181  char *json_response = NULL;
2182  char *id_token = NULL;
2183  char *access_token = NULL;
2184  char *jwa = NULL;
2185  char *jwt_secret = NULL;
2186  char *nonce = NULL;
2187  char *code_verifier = NULL;
2188  json_t *oidc_jwk = NULL;
2189  char *oidc_jwk_path = NULL;
2190  char *oidc_directory = NULL;
2191  char *tmp_at = NULL;
2192 
2193  /*
2194  * Check Authorization
2195  */
2196  if (GNUNET_SYSERR == check_authorization (handle, &cid))
2197  {
2199  "OIDC authorization for token endpoint failed\n");
2201  return;
2202  }
2203 
2204  /*
2205  * Check parameter
2206  */
2207 
2208  // TODO Do not allow multiple equal parameter names
2209  // REQUIRED grant_type
2211  strlen (OIDC_GRANT_TYPE_KEY),
2212  &cache_key);
2214  if (NULL == grant_type)
2215  {
2217  handle->edesc = GNUNET_strdup ("missing parameter grant_type");
2218  handle->response_code = MHD_HTTP_BAD_REQUEST;
2220  return;
2221  }
2222 
2223  // Check parameter grant_type == "authorization_code"
2224  if (0 != strcmp (OIDC_GRANT_TYPE_VALUE, grant_type))
2225  {
2227  handle->response_code = MHD_HTTP_BAD_REQUEST;
2228  GNUNET_free (grant_type);
2230  return;
2231  }
2232  GNUNET_free (grant_type);
2233  // REQUIRED code
2235  if (NULL == code)
2236  {
2238  handle->edesc = GNUNET_strdup ("missing parameter code");
2239  handle->response_code = MHD_HTTP_BAD_REQUEST;
2241  return;
2242  }
2243  ego_entry = find_ego (handle, &cid);
2244  if (NULL == ego_entry)
2245  {
2247  handle->edesc = GNUNET_strdup ("Unknown client");
2248  handle->response_code = MHD_HTTP_BAD_REQUEST;
2249  GNUNET_free (code);
2251  return;
2252  }
2253 
2254  // REQUIRED code verifier
2256  if (NULL == code_verifier)
2257  {
2259  "OAuth authorization request does not contain PKCE parameters!\n");
2260 
2261  }
2262 
2263  // decode code
2264  if (GNUNET_OK != OIDC_parse_authz_code (&cid, code, code_verifier, &ticket,
2265  &cl, &pl, &nonce,
2267  {
2269  handle->edesc = GNUNET_strdup ("invalid code");
2270  handle->response_code = MHD_HTTP_BAD_REQUEST;
2271  GNUNET_free (code);
2272  if (NULL != code_verifier)
2273  GNUNET_free (code_verifier);
2275  return;
2276  }
2277  if (NULL != code_verifier)
2278  GNUNET_free (code_verifier);
2279 
2280  // create jwt
2282  "reclaim-rest-plugin",
2283  "expiration_time",
2284  &expiration_time))
2285  {
2287  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2288  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2289  GNUNET_free (code);
2290  if (NULL != nonce)
2291  GNUNET_free (nonce);
2295  return;
2296  }
2297 
2298  // Check if HMAC or RSA should be used
2300  "reclaim-rest-plugin",
2301  "oidc_json_web_algorithm",
2302  &jwa))
2303  {
2305  "Could not read OIDC JSON Web Algorithm config attribute."
2306  "Defaulting to RS256.");
2307  jwa = JWT_ALG_VALUE_RSA;
2308  }
2309 
2310  if ( ! strcmp (jwa, JWT_ALG_VALUE_RSA))
2311  {
2312  // Replace for now
2313  oidc_jwk_path = get_oidc_jwk_path (cls);
2314  oidc_jwk = read_jwk_from_file (oidc_jwk_path);
2315 
2316  // Check if secret JWK exists
2317  if (! oidc_jwk)
2318  {
2319  // Generate and save a new key
2320  oidc_jwk = generate_jwk ();
2321  oidc_directory = get_oidc_dir_path (cls);
2322 
2323  // Create new oidc directory
2324  if (GNUNET_OK != GNUNET_DISK_directory_create (oidc_directory))
2325  {
2327  ("Failed to create directory `%s' for storing oidc data\n"),
2328  oidc_directory);
2329  }
2330  else
2331  {
2332  write_jwk_to_file (oidc_jwk_path, oidc_jwk);
2333  }
2334  }
2335 
2336  // Generate oidc token
2338  &ticket.identity,
2339  cl,
2340  pl,
2341  &expiration_time,
2342  (NULL != nonce) ? nonce : NULL,
2343  oidc_jwk);
2344  }
2345  else if ( ! strcmp (jwa, JWT_ALG_VALUE_HMAC))
2346  {
2347  // TODO OPTIONAL acr,amr,azp
2349  "reclaim-rest-plugin",
2350  "jwt_secret",
2351  &jwt_secret))
2352  {
2354  handle->edesc = GNUNET_strdup ("No signing secret configured!");
2355  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2356  GNUNET_free (code);
2359  if (NULL != nonce)
2360  GNUNET_free (nonce);
2362  return;
2363  }
2364 
2366  &ticket.identity,
2367  cl,
2368  pl,
2369  &expiration_time,
2370  (NULL != nonce) ? nonce : NULL,
2371  jwt_secret);
2372 
2373  GNUNET_free (jwt_secret);
2374  }
2375  else
2376  {
2377  // TODO: OPTION NOT FOUND ERROR
2378  }
2379 
2380  if (NULL != nonce)
2381  GNUNET_free (nonce);
2382  access_token = OIDC_access_token_new (&ticket);
2387  GNUNET_CRYPTO_hash (access_token,
2388  strlen (access_token),
2389  &cache_key);
2401  &cache_key);
2403  &cache_key,
2404  code,
2406  /* If there was a previous code in there, free the old value */
2407  if (NULL != tmp_at)
2408  {
2410  "OIDC access token already issued. Cleanup.\n");
2411  GNUNET_free (tmp_at);
2412  }
2413 
2414  OIDC_build_token_response (access_token,
2415  id_token,
2416  &expiration_time,
2417  &json_response);
2418 
2419  resp = GNUNET_REST_create_response (json_response);
2420  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
2421  "Cache-Control",
2422  "no-store"));
2423  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
2424  "Pragma", "no-cache"));
2425  GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
2426  "Content-Type",
2427  "application/json"));
2428  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2431  GNUNET_free (access_token);
2432  GNUNET_free (json_response);
2433  GNUNET_free (id_token);
2435 }
2436 
2437 
2441 static void
2442 consume_ticket (void *cls,
2443  const struct GNUNET_IDENTITY_PublicKey *identity,
2444  const struct GNUNET_RECLAIM_Attribute *attr,
2445  const struct GNUNET_RECLAIM_Presentation *presentation)
2446 {
2447  struct RequestHandle *handle = cls;
2450  struct MHD_Response *resp;
2451  struct GNUNET_HashCode cache_key;
2452  char *result_str;
2453  char *cached_code;
2454 
2455  if (NULL != handle->consume_timeout_op)
2456  GNUNET_SCHEDULER_cancel (handle->consume_timeout_op);
2457  handle->consume_timeout_op = NULL;
2458  handle->idp_op = NULL;
2459 
2463  GNUNET_CRYPTO_hash (handle->access_token,
2464  strlen (handle->access_token),
2465  &cache_key);
2467  &cache_key);
2468  if (NULL != cached_code)
2469  {
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  }
2566  &cache_key,
2567  cached_code);
2568 
2569  // decode code
2570  if (GNUNET_OK != OIDC_parse_authz_code (&handle->ticket.audience,
2571  cached_code, NULL, &ticket,
2572  &cl, &pl, &nonce,
2574  {
2576  handle->edesc = GNUNET_strdup ("invalid code");
2577  handle->response_code = MHD_HTTP_BAD_REQUEST;
2578  GNUNET_free (cached_code);
2579  if (NULL != nonce)
2580  GNUNET_free (nonce);
2582  return;
2583  }
2584 
2585  GNUNET_free (cached_code);
2586 
2587  result_str = OIDC_generate_userinfo (&handle->ticket.identity,
2588  cl,
2589  pl);
2590  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Userinfo: %s\n", result_str);
2591  resp = GNUNET_REST_create_response (result_str);
2592  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2593  GNUNET_free (result_str);
2594  GNUNET_free (nonce);
2598 }
2599 
2600 
2608 static void
2610  const char *url,
2611  void *cls)
2612 {
2613  // TODO expiration time
2614  struct RequestHandle *handle = cls;
2615  struct GNUNET_RECLAIM_Ticket *ticket;
2616  char delimiter[] = " ";
2617  struct GNUNET_HashCode cache_key;
2618  char *authorization;
2619  char *authorization_type;
2620  char *authorization_access_token;
2621  const struct EgoEntry *aud_ego;
2622  const struct GNUNET_IDENTITY_PrivateKey *privkey;
2623 
2624  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting userinfo\n");
2627  &cache_key);
2629  ->header_param_map,
2630  &cache_key))
2631  {
2633  handle->edesc = GNUNET_strdup ("No Access Token");
2634  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2636  return;
2637  }
2638  authorization =
2639  GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
2640  &cache_key);
2641 
2642  // split header in "Bearer" and access_token
2643  authorization = GNUNET_strdup (authorization);
2644  authorization_type = strtok (authorization, delimiter);
2645  if ((NULL == authorization_type) ||
2646  (0 != strcmp ("Bearer", authorization_type)))
2647  {
2649  handle->edesc = GNUNET_strdup ("No Access Token");
2650  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2652  GNUNET_free (authorization);
2653  return;
2654  }
2655  authorization_access_token = strtok (NULL, delimiter);
2656  if (NULL == authorization_access_token)
2657  {
2659  handle->edesc = GNUNET_strdup ("Access token missing");
2660  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2662  GNUNET_free (authorization);
2663  return;
2664  }
2665 
2666  if (GNUNET_OK != OIDC_access_token_parse (authorization_access_token,
2667  &ticket))
2668  {
2670  handle->edesc = GNUNET_strdup ("The access token is invalid");
2671  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2673  GNUNET_free (authorization);
2674  return;
2675 
2676  }
2677  GNUNET_assert (NULL != ticket);
2678  handle->ticket = *ticket;
2679  GNUNET_free (ticket);
2680  aud_ego = find_ego (handle, &handle->ticket.audience);
2681  if (NULL == aud_ego)
2682  {
2684  handle->edesc = GNUNET_strdup ("The access token expired");
2685  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2687  GNUNET_free (authorization);
2688  return;
2689  }
2690  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Consuming ticket\n");
2691  privkey = GNUNET_IDENTITY_ego_get_private_key (aud_ego->ego);
2692  handle->attr_userinfo_list =
2694  handle->presentations =
2696 
2697  /* If the consume takes too long, we use values from the cache */
2698  handle->access_token = GNUNET_strdup (authorization_access_token);
2699  handle->consume_timeout_op = GNUNET_SCHEDULER_add_delayed (consume_timeout,
2700  &consume_fail,
2701  handle);
2703  privkey,
2704  &handle->ticket,
2705  &consume_ticket,
2706  handle);
2707  GNUNET_free (authorization);
2708 }
2709 
2717 static void
2719  const char *url,
2720  void *cls)
2721 {
2722  char *oidc_directory;
2723  char *oidc_jwk_path;
2724  char *oidc_jwk_pub_str;
2725  json_t *oidc_jwk;
2726  struct MHD_Response *resp;
2727  struct RequestHandle *handle = cls;
2728 
2729  oidc_jwk_path = get_oidc_jwk_path (cls);
2730  oidc_jwk = read_jwk_from_file (oidc_jwk_path);
2731 
2732  // Check if secret JWK exists
2733  if (! oidc_jwk)
2734  {
2735  // Generate and save a new key
2736  oidc_jwk = generate_jwk ();
2737  oidc_directory = get_oidc_dir_path (cls);
2738 
2739  // Create new oidc directory
2740  if (GNUNET_OK != GNUNET_DISK_directory_create (oidc_directory))
2741  {
2743  ("Failed to create directory `%s' for storing oidc data\n"),
2744  oidc_directory);
2745  }
2746  else
2747  {
2748  write_jwk_to_file (oidc_jwk_path, oidc_jwk);
2749  }
2750  }
2751 
2752  // Convert secret JWK to public JWK
2753  jose_jwk_pub (NULL, oidc_jwk);
2754 
2755  // Encode JWK as string and return to API endpoint
2756  oidc_jwk_pub_str = json_dumps (oidc_jwk, JSON_INDENT (1));
2757  resp = GNUNET_REST_create_response (oidc_jwk_pub_str);
2758  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2759  json_decref (oidc_jwk);
2760  GNUNET_free (oidc_jwk_pub_str);
2761  GNUNET_free (oidc_jwk_pub_str);
2763 }
2764 
2797 static void
2798 list_ego (void *cls,
2799  struct GNUNET_IDENTITY_Ego *ego,
2800  void **ctx,
2801  const char *identifier)
2802 {
2803  struct EgoEntry *ego_entry;
2805 
2806  if (NULL == ego)
2807  {
2809  return;
2810  }
2811  if (ID_REST_STATE_INIT == state)
2812 
2813  {
2814  ego_entry = GNUNET_new (struct EgoEntry);
2817  ego_entry->ego = ego;
2818  ego_entry->identifier = GNUNET_strdup (identifier);
2820  ego_tail,
2821  ego_entry);
2822  return;
2823  }
2824  /* Ego renamed or added */
2825  if (identifier != NULL)
2826  {
2827  for (ego_entry = ego_head; NULL != ego_entry;
2828  ego_entry = ego_entry->next)
2829  {
2830  if (ego_entry->ego == ego)
2831  {
2832  /* Rename */
2833  GNUNET_free (ego_entry->identifier);
2834  ego_entry->identifier = GNUNET_strdup (identifier);
2835  break;
2836  }
2837  }
2838  if (NULL == ego_entry)
2839  {
2840  /* Add */
2841  ego_entry = GNUNET_new (struct EgoEntry);
2844  ego_entry->ego = ego;
2845  ego_entry->identifier = GNUNET_strdup (identifier);
2847  ego_tail,
2848  ego_entry);
2849  }
2850  }
2851  else
2852  {
2853  /* Delete */
2854  for (ego_entry = ego_head; NULL != ego_entry;
2855  ego_entry = ego_entry->next)
2856  {
2857  if (ego_entry->ego == ego)
2858  break;
2859  }
2860  if (NULL == ego_entry)
2861  return; /* Not found */
2862 
2864  ego_tail,
2865  ego_entry);
2866  GNUNET_free (ego_entry->identifier);
2867  GNUNET_free (ego_entry->keystring);
2868  GNUNET_free (ego_entry);
2869  return;
2870  }
2871 }
2872 
2873 
2874 static void
2876  const char *url,
2877  void *cls)
2878 {
2879  json_t *oidc_config;
2880  json_t *auth_methods;
2881  json_t *sig_algs;
2882  json_t *scopes;
2883  json_t *response_types;
2884  json_t *sub_types;
2885  json_t *claim_types;
2886  char *oidc_config_str;
2887  struct MHD_Response *resp;
2888  struct RequestHandle *handle = cls;
2889 
2890  oidc_config = json_object ();
2891  // FIXME get from config?
2892  json_object_set_new (oidc_config,
2893  "issuer", json_string ("http://localhost:7776"));
2894  json_object_set_new (oidc_config,
2895  "authorization_endpoint",
2896  json_string ("https://api.reclaim/openid/authorize"));
2897  json_object_set_new (oidc_config,
2898  "token_endpoint",
2899  json_string ("http://localhost:7776/openid/token"));
2900  auth_methods = json_array ();
2901  json_array_append_new (auth_methods,
2902  json_string ("client_secret_basic"));
2903  json_array_append_new (auth_methods,
2904  json_string ("client_secret_post"));
2905  json_object_set_new (oidc_config,
2906  "token_endpoint_auth_methods_supported",
2907  auth_methods);
2908  sig_algs = json_array ();
2909  json_array_append_new (sig_algs,
2910  json_string ("HS512"));
2911  json_array_append_new (sig_algs,
2912  json_string ("RS256"));
2913  json_object_set_new (oidc_config,
2914  "id_token_signing_alg_values_supported",
2915  sig_algs);
2916  json_object_set_new (oidc_config,
2917  "jwks_uri",
2918  json_string ("http://localhost:7776/jwks.json"));
2919  json_object_set_new (oidc_config,
2920  "userinfo_endpoint",
2921  json_string ("http://localhost:7776/openid/userinfo"));
2922  scopes = json_array ();
2923  json_array_append_new (scopes,
2924  json_string ("openid"));
2925  json_array_append_new (scopes,
2926  json_string ("profile"));
2927  json_array_append_new (scopes,
2928  json_string ("email"));
2929  json_array_append_new (scopes,
2930  json_string ("address"));
2931  json_array_append_new (scopes,
2932  json_string ("phone"));
2933  json_object_set_new (oidc_config,
2934  "scopes_supported",
2935  scopes);
2936  response_types = json_array ();
2937  json_array_append_new (response_types,
2938  json_string ("code"));
2939  json_object_set_new (oidc_config,
2940  "response_types_supported",
2941  response_types);
2942  sub_types = json_array ();
2943  json_array_append_new (sub_types,
2944  json_string ("public")); /* no pairwise support */
2945  json_object_set_new (oidc_config,
2946  "subject_types_supported",
2947  sub_types);
2948  claim_types = json_array ();
2949  json_array_append_new (claim_types,
2950  json_string ("normal"));
2951  json_array_append_new (claim_types,
2952  json_string ("aggregated"));
2953  json_object_set_new (oidc_config,
2954  "claim_types_supported",
2955  claim_types);
2956  json_object_set_new (oidc_config,
2957  "claims_parameter_supported",
2958  json_boolean (1));
2959  oidc_config_str = json_dumps (oidc_config, JSON_INDENT (1));
2960  resp = GNUNET_REST_create_response (oidc_config_str);
2961  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2962  json_decref (oidc_config);
2963  GNUNET_free (oidc_config_str);
2965 }
2966 
2967 
2975 static void
2977  const char *url,
2978  void *cls)
2979 {
2980  struct MHD_Response *resp;
2981  struct RequestHandle *handle = cls;
2982 
2983  // For now, independent of path return all options
2984  resp = GNUNET_REST_create_response (NULL);
2985  GNUNET_assert (MHD_NO !=
2986  MHD_add_response_header (resp,
2987  "Access-Control-Allow-Methods",
2988  allow_methods));
2989  GNUNET_assert (MHD_NO !=
2990  MHD_add_response_header (resp,
2991  "Access-Control-Allow-Origin",
2992  "*"));
2993  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2995  return;
2996 }
2997 
2998 
2999 static enum GNUNET_GenericReturnValue
3002  void *proc_cls)
3003 {
3004  struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
3006  static const struct GNUNET_REST_RequestHandler handlers[] =
3007  { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint },
3008  { MHD_HTTP_METHOD_POST,
3010  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont },
3011  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
3012  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
3013  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
3014  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_JWKS, &jwks_endpoint },
3015  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_OIDC_CONFIG,
3017  { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC_CONFIG,
3018  &oidc_config_cors },
3019  { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, &options_cont },
3021 
3022  handle->oidc = GNUNET_new (struct OIDC_Variables);
3023  if (NULL == OIDC_cookie_jar_map)
3025  GNUNET_NO);
3026  if (NULL == oidc_code_cache)
3028  GNUNET_NO);
3029 
3030  handle->response_code = 0;
3032  handle->proc_cls = proc_cls;
3033  handle->proc = proc;
3034  handle->rest_handle = rest_handle;
3035  handle->url = GNUNET_strdup (rest_handle->url);
3036  handle->timeout_task =
3039  requests_tail,
3040  handle);
3041  if (handle->url[strlen (handle->url) - 1] == '/')
3042  handle->url[strlen (handle->url) - 1] = '\0';
3043  if (GNUNET_NO ==
3044  GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
3045  return GNUNET_NO;
3046 
3047  return GNUNET_YES;
3048 }
3049 
3050 
3057 void *
3059 {
3060  static struct Plugin plugin;
3061  struct GNUNET_REST_Plugin *api;
3062 
3063  cfg = cls;
3064  if (NULL != plugin.cfg)
3065  return NULL; /* can only initialize once! */
3066  memset (&plugin, 0, sizeof(struct Plugin));
3067  plugin.cfg = cfg;
3068  api = GNUNET_new (struct GNUNET_REST_Plugin);
3069  api->cls = &plugin;
3076  "reclaim-rest-plugin",
3077  "OIDC_USERINFO_CONSUME_TIMEOUT",
3078  &consume_timeout))
3079  {
3081  }
3082 
3083 
3086  "%s, %s, %s, %s, %s",
3087  MHD_HTTP_METHOD_GET,
3088  MHD_HTTP_METHOD_POST,
3089  MHD_HTTP_METHOD_PUT,
3090  MHD_HTTP_METHOD_DELETE,
3091  MHD_HTTP_METHOD_OPTIONS);
3092 
3094  _ ("OpenID Connect REST API initialized\n"));
3095  return api;
3096 }
3097 
3098 
3099 static int
3100 cleanup_hashmap (void *cls, const struct GNUNET_HashCode *key, void *value)
3101 {
3102  GNUNET_free (value);
3103  return GNUNET_YES;
3104 }
3105 
3106 
3113 void *
3115 {
3116  struct GNUNET_REST_Plugin *api = cls;
3117  struct Plugin *plugin = api->cls;
3118  struct EgoEntry *ego_entry;
3119 
3120  plugin->cfg = NULL;
3121  while (NULL != requests_head)
3123  if (NULL != OIDC_cookie_jar_map)
3124  {
3126  &cleanup_hashmap,
3127  NULL);
3129  }
3130  if (NULL != oidc_code_cache)
3131  {
3133  &cleanup_hashmap,
3134  NULL);
3136  }
3137 
3139  if (NULL != gns_handle)
3141  if (NULL != identity_handle)
3143  if (NULL != idp)
3145  while (NULL != (ego_entry = ego_head))
3146  {
3148  ego_tail,
3149  ego_entry);
3150  GNUNET_free (ego_entry->identifier);
3151  GNUNET_free (ego_entry->keystring);
3152  GNUNET_free (ego_entry);
3153  }
3154  GNUNET_free (api);
3156  "OpenID Connect REST plugin is finished\n");
3157  return NULL;
3158 }
3159 
3160 
3161 /* 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 Plugin * 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 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.
Strings and string handling functions.
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:496
#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:412
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:639
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:175
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:652
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:610
void GNUNET_IDENTITY_disconnect(struct GNUNET_IDENTITY_Handle *h)
Disconnect from identity service.
Definition: identity_api.c:921
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.
Definition: gnunet_common.h:96
@ GNUNET_OK
Definition: gnunet_common.h:99
@ GNUNET_YES
@ GNUNET_NO
Definition: gnunet_common.h:98
@ GNUNET_SYSERR
Definition: gnunet_common.h:97
#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 claim 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:1103
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:1330
void GNUNET_RECLAIM_cancel(struct GNUNET_RECLAIM_Operation *op)
Cancel an identity provider operation.
Definition: reclaim_api.c:1088
void GNUNET_RECLAIM_get_attributes_stop(struct GNUNET_RECLAIM_AttributeIterator *it)
Stops iteration and releases the handle for further calls.
Definition: reclaim_api.c:1397
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:1486
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:1439
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:1376
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:1541
struct GNUNET_RECLAIM_Handle * GNUNET_RECLAIM_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Connect to the re:claimID service.
Definition: reclaim_api.c:1063
void GNUNET_RECLAIM_get_credentials_stop(struct GNUNET_RECLAIM_CredentialIterator *ait)
Stops iteration and releases the handle for further calls.
Definition: reclaim_api.c:1508
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:1589
void GNUNET_RECLAIM_ticket_iteration_stop(struct GNUNET_RECLAIM_TicketIterator *it)
Stops iteration and releases the handle for further calls.
Definition: reclaim_api.c:1699
struct MHD_Response * GNUNET_REST_create_response(const char *data)
Create REST MHD response.
Definition: rest.c:57
int GNUNET_REST_handle_request(struct GNUNET_REST_RequestHandle *conn, const struct GNUNET_REST_RequestHandler *handlers, struct GNUNET_REST_RequestHandlerError *err, void *cls)
Definition: rest.c:77
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:1281
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:957
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:1254
size_t GNUNET_STRINGS_urldecode(const char *data, size_t len, char **out)
url/percent encode (RFC3986).
Definition: strings.c:1807
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:764
size_t GNUNET_STRINGS_urlencode(const char *data, size_t len, char **out)
url/percent encode (RFC3986).
Definition: strings.c:1851
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:789
size_t GNUNET_STRINGS_base64_decode(const char *data, size_t len, void **output)
Decode from Base64.
Definition: strings.c:1696
#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:110
struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_second_(void)
Return relative time of 1s.
Definition: time.c:168
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:315
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:483
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:501
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:930
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:972
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:595
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:781
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:902
int OIDC_access_token_parse(const char *token, struct GNUNET_RECLAIM_Ticket **ticket)
Parse an access token.
Definition: oidc_helper.c:945
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:439
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:96
Handle for an operation with the identity service.
Definition: identity_api.c:40
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:183
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:250
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:318
Handle for an operation with the service.
Definition: reclaim_api.c:42
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:120
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:135
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.