GNUnet  0.11.x
plugin_rest_openid_connect.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2012-2018 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
27 #include "platform.h"
28 #include <inttypes.h>
29 #include <jansson.h>
30 
31 #include "gnunet_gns_service.h"
32 #include "gnunet_gnsrecord_lib.h"
35 #include "gnunet_reclaim_lib.h"
36 #include "gnunet_reclaim_service.h"
37 #include "gnunet_rest_lib.h"
38 #include "gnunet_rest_plugin.h"
39 #include "gnunet_signatures.h"
40 #include "microhttpd.h"
41 #include "oidc_helper.h"
45 #define GNUNET_REST_API_NS_OIDC "/openid"
46 
50 #define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize"
51 
55 #define GNUNET_REST_API_NS_TOKEN "/openid/token"
56 
60 #define GNUNET_REST_API_NS_USERINFO "/openid/userinfo"
61 
65 #define GNUNET_REST_API_NS_LOGIN "/openid/login"
66 
70 #define ID_REST_STATE_INIT 0
71 
75 #define ID_REST_STATE_POST_INIT 1
76 
80 #define OIDC_GRANT_TYPE_KEY "grant_type"
81 
85 #define OIDC_GRANT_TYPE_VALUE "authorization_code"
86 
90 #define OIDC_CODE_KEY "code"
91 
95 #define OIDC_RESPONSE_TYPE_KEY "response_type"
96 
100 #define OIDC_CLIENT_ID_KEY "client_id"
101 
105 #define OIDC_SCOPE_KEY "scope"
106 
110 #define OIDC_REDIRECT_URI_KEY "redirect_uri"
111 
115 #define OIDC_STATE_KEY "state"
116 
120 #define OIDC_NONCE_KEY "nonce"
121 
125 #define OIDC_CLAIMS_KEY "claims"
126 
130 #define OIDC_CODE_CHALLENGE_KEY "code_challenge"
131 
135 #define OIDC_CODE_VERIFIER_KEY "code_verifier"
136 
140 #define OIDC_COOKIE_EXPIRATION 3
141 
145 #define OIDC_COOKIE_HEADER_KEY "cookie"
146 
150 #define OIDC_AUTHORIZATION_HEADER_KEY "authorization"
151 
155 #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
156 
160 #define OIDC_COOKIE_HEADER_ACCESS_DENIED "Identity=Denied"
161 
165 #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
166 
170 #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
171 
175 #define OIDC_ERROR_KEY_INVALID_CLIENT "invalid_client"
176 
180 #define OIDC_ERROR_KEY_INVALID_SCOPE "invalid_scope"
181 
185 #define OIDC_ERROR_KEY_INVALID_REQUEST "invalid_request"
186 
190 #define OIDC_ERROR_KEY_INVALID_TOKEN "invalid_token"
191 
195 #define OIDC_ERROR_KEY_INVALID_COOKIE "invalid_cookie"
196 
200 #define OIDC_ERROR_KEY_SERVER_ERROR "server_error"
201 
205 #define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE "unsupported_grant_type"
206 
210 #define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE "unsupported_response_type"
211 
215 #define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT "unauthorized_client"
216 
220 #define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied"
221 
222 
226 static char *OIDC_ignored_parameter_array[] = { "display",
227  "prompt",
228  "ui_locales",
229  "response_mode",
230  "id_token_hint",
231  "login_hint",
232  "acr_values" };
233 
238 
244 
249 
253 static char *allow_methods;
254 
258 struct Plugin
259 {
260  const struct GNUNET_CONFIGURATION_Handle *cfg;
261 };
262 
267 {
271  struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
272 
276  char *client_id;
277 
282 
286  char *scope;
287 
291  char *state;
292 
296  char *nonce;
297 
301  char *claims;
302 
307 
312 
317 
322 
327 
331  json_t *response;
332 };
333 
337 struct EgoEntry
338 {
342  struct EgoEntry *next;
343 
347  struct EgoEntry *prev;
348 
352  char *identifier;
353 
357  char *keystring;
358 
362  struct GNUNET_IDENTITY_Ego *ego;
363 };
364 
365 
366 struct RequestHandle
367 {
371  struct EgoEntry *ego_head;
372 
376  struct EgoEntry *ego_tail;
377 
381  struct EgoEntry *ego_entry;
382 
387 
392 
396  int state;
397 
402 
406  struct GNUNET_REST_RequestHandle *rest_handle;
407 
412 
417 
422 
427 
432 
437 
438 
443 
448 
453 
458 
463 
464 
469 
474 
479 
484 
489 
493  void *proc_cls;
494 
498  char *url;
499 
503  char *tld;
504 
509 
514 
518  char *emsg;
519 
523  char *edesc;
524 
528  int response_code;
529 };
530 
535 static void
537 {
538  struct EgoEntry *ego_entry;
539  struct EgoEntry *ego_tmp;
540 
541  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
542  if (NULL != handle->timeout_task)
544  if (NULL != handle->identity_handle)
546  if (NULL != handle->attr_it)
548  if (NULL != handle->attest_it)
550  if (NULL != handle->ticket_it)
552  if (NULL != handle->idp)
553  GNUNET_RECLAIM_disconnect (handle->idp);
554  GNUNET_free_non_null (handle->url);
555  GNUNET_free_non_null (handle->tld);
558  GNUNET_free_non_null (handle->emsg);
559  GNUNET_free_non_null (handle->edesc);
560  if (NULL != handle->gns_op)
562  if (NULL != handle->gns_handle)
564 
565  if (NULL != handle->namestore_handle)
567  if (NULL != handle->oidc)
568  {
571  GNUNET_free_non_null (handle->oidc->nonce);
574  GNUNET_free_non_null (handle->oidc->scope);
575  GNUNET_free_non_null (handle->oidc->state);
576  json_decref (handle->oidc->response);
577  GNUNET_free (handle->oidc);
578  }
581 
582  for (ego_entry = handle->ego_head; NULL != ego_entry;)
583  {
584  ego_tmp = ego_entry;
585  ego_entry = ego_entry->next;
586  GNUNET_free (ego_tmp->identifier);
587  GNUNET_free (ego_tmp->keystring);
588  GNUNET_free (ego_tmp);
589  }
590  GNUNET_free (handle);
591 }
592 
593 
594 static void
596 {
597  cleanup_handle (cls);
598 }
599 
600 
606 static void
607 do_error (void *cls)
608 {
609  struct RequestHandle *handle = cls;
610  struct MHD_Response *resp;
611  char *json_error;
612 
613  GNUNET_asprintf (&json_error,
614  "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
615  handle->emsg,
616  (NULL != handle->edesc) ? handle->edesc : "",
617  (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
618  (NULL != handle->oidc->state) ? handle->oidc->state : "",
619  (NULL != handle->oidc->state) ? "\"" : "");
620  if (0 == handle->response_code)
621  handle->response_code = MHD_HTTP_BAD_REQUEST;
622  resp = GNUNET_REST_create_response (json_error);
623  if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
624  MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Basic");
625  MHD_add_response_header (resp,
626  MHD_HTTP_HEADER_CONTENT_TYPE,
627  "application/json");
628  handle->proc (handle->proc_cls, resp, handle->response_code);
630  GNUNET_free (json_error);
631 }
632 
633 
640 static void
641 do_userinfo_error (void *cls)
642 {
643  struct RequestHandle *handle = cls;
644  struct MHD_Response *resp;
645  char *error;
646 
647  GNUNET_asprintf (&error,
648  "error=\"%s\", error_description=\"%s\"",
649  handle->emsg,
650  (NULL != handle->edesc) ? handle->edesc : "");
651  resp = GNUNET_REST_create_response ("");
652  MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Bearer");
653  handle->proc (handle->proc_cls, resp, handle->response_code);
655  GNUNET_free (error);
656 }
657 
658 
664 static void
665 do_redirect_error (void *cls)
666 {
667  struct RequestHandle *handle = cls;
668  struct MHD_Response *resp;
669  char *redirect;
670 
671  GNUNET_asprintf (&redirect,
672  "%s?error=%s&error_description=%s%s%s",
673  handle->oidc->redirect_uri,
674  handle->emsg,
675  handle->edesc,
676  (NULL != handle->oidc->state) ? "&state=" : "",
677  (NULL != handle->oidc->state) ? handle->oidc->state : "");
678  resp = GNUNET_REST_create_response ("");
679  MHD_add_response_header (resp, "Location", redirect);
680  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
682  GNUNET_free (redirect);
683 }
684 
685 
691 static void
692 do_timeout (void *cls)
693 {
694  struct RequestHandle *handle = cls;
695 
696  handle->timeout_task = NULL;
697  do_error (handle);
698 }
699 
700 
706 static void
708 {
709  char *result_str;
710  struct RequestHandle *handle = cls;
711  struct MHD_Response *resp;
712 
713  result_str = json_dumps (handle->oidc->response, 0);
714  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"ID-Token: %s\n",result_str);
715  resp = GNUNET_REST_create_response (result_str);
716  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
717  GNUNET_free (result_str);
718  cleanup_handle (handle);
719 }
720 
721 
729 static void
731  const char *url,
732  void *cls)
733 {
734  struct MHD_Response *resp;
735  struct RequestHandle *handle = cls;
736 
737  // For now, independent of path return all options
738  resp = GNUNET_REST_create_response (NULL);
739  MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
740  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
741  cleanup_handle (handle);
742  return;
743 }
744 
745 
749 static void
751 {
752  struct GNUNET_HashCode cache_key;
753  char *cookies;
754  struct GNUNET_TIME_Absolute current_time, *relog_time;
755  char delimiter[] = "; ";
756  char *tmp_cookies;
757  char *token;
758  char *value;
759 
760  // gets identity of login try with cookie
762  strlen (OIDC_COOKIE_HEADER_KEY),
763  &cache_key);
766  &cache_key))
767  {
768  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cookie found\n");
769  return;
770  }
771  // splits cookies and find 'Identity' cookie
772  tmp_cookies =
774  &cache_key);
775  cookies = GNUNET_strdup (tmp_cookies);
776  token = strtok (cookies, delimiter);
777  handle->oidc->user_cancelled = GNUNET_NO;
778  handle->oidc->login_identity = NULL;
779  if (NULL == token)
780  {
782  "Unable to parse cookie: %s\n",
783  cookies);
784  GNUNET_free (cookies);
785  return;
786  }
787 
788  while (NULL != token)
789  {
790  if (0 == strcmp (token, OIDC_COOKIE_HEADER_ACCESS_DENIED))
791  {
792  handle->oidc->user_cancelled = GNUNET_YES;
793  GNUNET_free (cookies);
794  return;
795  }
796  if (NULL != strstr (token, OIDC_COOKIE_HEADER_INFORMATION_KEY))
797  break;
798  token = strtok (NULL, delimiter);
799  }
800  if (NULL == token)
801  {
803  "No cookie value to process: %s\n",
804  cookies);
805  GNUNET_free (cookies);
806  return;
807  }
808  GNUNET_CRYPTO_hash (token, strlen (token), &cache_key);
809  if (GNUNET_NO ==
810  GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
811  {
812  GNUNET_log (
814  "Found cookie `%s', but no corresponding expiration entry present...\n",
815  token);
816  GNUNET_free (cookies);
817  return;
818  }
819  relog_time =
820  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
821  current_time = GNUNET_TIME_absolute_get ();
822  // 30 min after old login -> redirect to login
823  if (current_time.abs_value_us > relog_time->abs_value_us)
824  {
826  "Found cookie `%s', but it is expired.\n",
827  token);
828  GNUNET_free (cookies);
829  return;
830  }
831  value = strtok (token, OIDC_COOKIE_HEADER_INFORMATION_KEY);
832  GNUNET_assert (NULL != value);
833  handle->oidc->login_identity = GNUNET_strdup (value);
834  GNUNET_free (cookies);
835 }
836 
837 
841 static void
842 login_redirect (void *cls)
843 {
844  char *login_base_url;
845  char *new_redirect;
846  struct MHD_Response *resp;
847  struct RequestHandle *handle = cls;
848 
850  "reclaim-rest-plugin",
851  "address",
852  &login_base_url))
853  {
854  GNUNET_asprintf (&new_redirect,
855  "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
856  login_base_url,
858  handle->oidc->response_type,
860  handle->oidc->client_id,
862  handle->oidc->redirect_uri,
864  handle->oidc->scope,
866  (NULL != handle->oidc->state) ? handle->oidc->state : "",
868  (NULL != handle->oidc->code_challenge) ?
869  handle->oidc->code_challenge : "",
871  (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "",
873  (NULL != handle->oidc->claims) ? handle->oidc->claims :
874  "");
875  resp = GNUNET_REST_create_response ("");
876  MHD_add_response_header (resp, "Location", new_redirect);
877  GNUNET_free (login_base_url);
878  }
879  else
880  {
882  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
883  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
885  return;
886  }
887  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
888  GNUNET_free (new_redirect);
890 }
891 
892 
896 static void
898 {
899  struct RequestHandle *handle = cls;
900 
902  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
904 }
905 
906 
911 static void
913 {
914  struct RequestHandle *handle = cls;
915  struct MHD_Response *resp;
916  char *ticket_str;
917  char *redirect_uri;
918  char *code_string;
919 
920  handle->idp_op = NULL;
921  if (NULL == ticket)
922  {
924  handle->edesc = GNUNET_strdup ("Server cannot generate ticket.");
926  return;
927  }
928  handle->ticket = *ticket;
929  ticket_str =
931  sizeof(struct GNUNET_RECLAIM_Ticket));
932  // TODO change if more attributes are needed (see max_age)
933  code_string = OIDC_build_authz_code (&handle->priv_key,
934  &handle->ticket,
935  handle->attr_list,
936  handle->attests_list,
937  handle->oidc->nonce,
938  handle->oidc->code_challenge);
939  if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
940  (NULL != handle->tld))
941  {
942  GNUNET_asprintf (&redirect_uri,
943  "%s.%s/%s?%s=%s&state=%s",
944  handle->redirect_prefix,
945  handle->tld,
946  handle->redirect_suffix,
947  handle->oidc->response_type,
948  code_string,
949  handle->oidc->state);
950  }
951  else
952  {
953  GNUNET_asprintf (&redirect_uri,
954  "%s?%s=%s&state=%s",
955  handle->oidc->redirect_uri,
956  handle->oidc->response_type,
957  code_string,
958  handle->oidc->state);
959  }
960  resp = GNUNET_REST_create_response ("");
961  MHD_add_response_header (resp, "Location", redirect_uri);
962  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
964  GNUNET_free (redirect_uri);
965  GNUNET_free (ticket_str);
966  GNUNET_free (code_string);
967 }
968 
969 
970 static void
972 {
973  struct RequestHandle *handle = cls;
974 
975  handle->attest_it = NULL;
976  handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp,
977  &handle->priv_key,
978  &handle->oidc->client_pkey,
979  handle->attr_list,
981  handle);
982 }
983 
984 
988 static void
991  const struct GNUNET_RECLAIM_Attestation *attest)
992 {
993  struct RequestHandle *handle = cls;
995 
996  for (le = handle->attr_list->list_head; NULL != le; le = le->next)
997  {
999  &attest->id))
1000  {
1004  attest->type,
1005  attest->data,
1006  attest->data_size);
1008  handle->attests_list->list_tail,
1009  ale);
1010  }
1011  }
1013 }
1014 
1015 
1016 static void
1018 {
1019  struct RequestHandle *handle = cls;
1020 
1021  handle->attr_it = NULL;
1022  handle->ticket_it = NULL;
1023  if (NULL == handle->attr_list->list_head)
1024  {
1026  handle->edesc = GNUNET_strdup ("The requested scope is not available.");
1028  return;
1029  }
1031  handle->attest_it =
1033  &handle->priv_key,
1035  handle,
1037  handle,
1039  handle);
1040 
1041  handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp,
1042  &handle->priv_key,
1043  &handle->oidc->client_pkey,
1044  handle->attr_list,
1046  handle);
1047 }
1048 
1049 
1053 static void
1055  const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1056  const struct GNUNET_RECLAIM_Attribute *attr)
1057 {
1058  struct RequestHandle *handle = cls;
1060  char *scope_variables;
1061  char *scope_variable;
1062  char delimiter[] = " ";
1063 
1064  scope_variables = GNUNET_strdup (handle->oidc->scope);
1065  scope_variable = strtok (scope_variables, delimiter);
1066  while (NULL != scope_variable)
1067  {
1068  if (0 == strcmp (attr->name, scope_variable))
1069  break;
1070  scope_variable = strtok (NULL, delimiter);
1071  }
1072  if (NULL == scope_variable)
1073  {
1075  GNUNET_free (scope_variables);
1076  // We can ignore this
1077  return;
1078  }
1079  GNUNET_free (scope_variables);
1082  &attr->attestation,
1083  attr->type,
1084  attr->data,
1085  attr->data_size);
1086  le->attribute->id = attr->id;
1087  le->attribute->flag = attr->flag;
1088  le->attribute->attestation = attr->attestation;
1090  handle->attr_list->list_tail,
1091  le);
1093 }
1094 
1095 
1099 static void
1100 code_redirect (void *cls)
1101 {
1102  struct RequestHandle *handle = cls;
1103  struct GNUNET_TIME_Absolute current_time;
1104  struct GNUNET_TIME_Absolute *relog_time;
1105  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
1106  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pkey;
1107  struct GNUNET_HashCode cache_key;
1108  char *identity_cookie;
1109 
1110  GNUNET_asprintf (&identity_cookie,
1111  "Identity=%s",
1112  handle->oidc->login_identity);
1113  GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1114  GNUNET_free (identity_cookie);
1115  // No login time for identity -> redirect to login
1116  if (GNUNET_YES ==
1117  GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
1118  {
1119  relog_time =
1120  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
1121  current_time = GNUNET_TIME_absolute_get ();
1122  // 30 min after old login -> redirect to login
1123  if (current_time.abs_value_us <= relog_time->abs_value_us)
1124  {
1125  if (GNUNET_OK !=
1127  ->login_identity,
1128  strlen (
1129  handle->oidc
1130  ->login_identity),
1131  &pubkey))
1132  {
1134  handle->edesc =
1135  GNUNET_strdup ("The cookie of a login identity is not valid");
1137  return;
1138  }
1139  // iterate over egos and compare their public key
1140  for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
1141  handle->ego_entry = handle->ego_entry->next)
1142  {
1143  GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1144  if (0 == GNUNET_memcmp (&ego_pkey, &pubkey))
1145  {
1146  handle->priv_key =
1148  handle->idp = GNUNET_RECLAIM_connect (cfg);
1149  handle->attr_list =
1151  handle->attr_it =
1153  &handle->priv_key,
1155  handle,
1157  handle,
1159  handle);
1160  return;
1161  }
1162  }
1164  return;
1165  }
1166  }
1167 }
1168 
1169 
1170 static void
1171 build_redirect (void *cls)
1172 {
1173  struct RequestHandle *handle = cls;
1174  struct MHD_Response *resp;
1175  char *redirect_uri;
1176 
1177  if (GNUNET_YES == handle->oidc->user_cancelled)
1178  {
1179  if ((NULL != handle->redirect_prefix) &&
1180  (NULL != handle->redirect_suffix) && (NULL != handle->tld))
1181  {
1182  GNUNET_asprintf (&redirect_uri,
1183  "%s.%s/%s?error=%s&error_description=%s&state=%s",
1184  handle->redirect_prefix,
1185  handle->tld,
1186  handle->redirect_suffix,
1187  "access_denied",
1188  "User denied access",
1189  handle->oidc->state);
1190  }
1191  else
1192  {
1193  GNUNET_asprintf (&redirect_uri,
1194  "%s?error=%s&error_description=%s&state=%s",
1195  handle->oidc->redirect_uri,
1196  "access_denied",
1197  "User denied access",
1198  handle->oidc->state);
1199  }
1200  resp = GNUNET_REST_create_response ("");
1201  MHD_add_response_header (resp, "Location", redirect_uri);
1202  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1204  GNUNET_free (redirect_uri);
1205  return;
1206  }
1208 }
1209 
1210 
1211 static void
1213  uint32_t rd_count,
1214  const struct GNUNET_GNSRECORD_Data *rd)
1215 {
1216  struct RequestHandle *handle = cls;
1217  char *tmp;
1218  char *tmp_key_str;
1219  char *pos;
1220  struct GNUNET_CRYPTO_EcdsaPublicKey redirect_zone;
1221 
1222  handle->gns_op = NULL;
1223  if (0 == rd_count)
1224  {
1226  handle->edesc =
1227  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1229  return;
1230  }
1231  for (int i = 0; i < rd_count; i++)
1232  {
1233  if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type)
1234  continue;
1235  if (0 != strncmp (rd[i].data, handle->oidc->redirect_uri, rd[i].data_size))
1236  continue;
1237  tmp = GNUNET_strndup (rd[i].data, rd[i].data_size);
1238  if (NULL == strstr (tmp, handle->oidc->client_id))
1239  {
1241  "Redirect uri %s does not contain client_id %s\n",
1242  tmp,
1243  handle->oidc->client_id);
1244  }
1245  else
1246  {
1247  pos = strrchr (tmp, (unsigned char) '.');
1248  if (NULL == pos)
1249  {
1251  "Redirect uri %s contains client_id but is malformed\n",
1252  tmp);
1253  GNUNET_free (tmp);
1254  continue;
1255  }
1256  *pos = '\0';
1257  handle->redirect_prefix = GNUNET_strdup (tmp);
1258  tmp_key_str = pos + 1;
1259  pos = strchr (tmp_key_str, (unsigned char) '/');
1260  if (NULL == pos)
1261  {
1263  "Redirect uri %s contains client_id but is malformed\n",
1264  tmp);
1265  GNUNET_free (tmp);
1266  continue;
1267  }
1268  *pos = '\0';
1269  handle->redirect_suffix = GNUNET_strdup (pos + 1);
1270 
1271  GNUNET_STRINGS_string_to_data (tmp_key_str,
1272  strlen (tmp_key_str),
1273  &redirect_zone,
1274  sizeof(redirect_zone));
1275  }
1277  GNUNET_free (tmp);
1278  return;
1279  }
1281  handle->edesc =
1282  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1284 }
1285 
1286 
1290 static void
1291 client_redirect (void *cls)
1292 {
1293  struct RequestHandle *handle = cls;
1294 
1295  /* Lookup client redirect uri to verify request */
1296  handle->gns_op =
1297  GNUNET_GNS_lookup (handle->gns_handle,
1299  &handle->oidc->client_pkey,
1303  handle);
1304 }
1305 
1306 
1307 static char *
1308 get_url_parameter_copy (const struct RequestHandle *handle, const char *key)
1309 {
1310  struct GNUNET_HashCode hc;
1311  char *value;
1312 
1313  GNUNET_CRYPTO_hash (key, strlen (key), &hc);
1315  ->url_param_map,
1316  &hc))
1317  return NULL;
1318  value =
1320  if (NULL == value)
1321  return NULL;
1322  return GNUNET_strdup (value);
1323 }
1324 
1325 
1332 static void
1334 {
1335  struct RequestHandle *handle = cls;
1336  struct GNUNET_HashCode cache_key;
1337 
1338  char *expected_scope;
1339  char delimiter[] = " ";
1340  int number_of_ignored_parameter, iterator;
1341 
1342 
1343  // REQUIRED value: redirect_uri
1344  handle->oidc->redirect_uri =
1346  if (NULL == handle->oidc->redirect_uri)
1347  {
1349  handle->edesc = GNUNET_strdup ("missing parameter redirect_uri");
1351  return;
1352  }
1353 
1354  // REQUIRED value: response_type
1355  handle->oidc->response_type =
1357  if (NULL == handle->oidc->response_type)
1358  {
1360  handle->edesc = GNUNET_strdup ("missing parameter response_type");
1362  return;
1363  }
1364 
1365  // REQUIRED value: scope
1366  handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
1367  if (NULL == handle->oidc->scope)
1368  {
1370  handle->edesc = GNUNET_strdup ("missing parameter scope");
1372  return;
1373  }
1374 
1375  // OPTIONAL value: nonce
1376  handle->oidc->nonce = get_url_parameter_copy (handle, OIDC_NONCE_KEY);
1377 
1378  // OPTIONAL value: claims
1379  handle->oidc->claims = get_url_parameter_copy (handle, OIDC_CLAIMS_KEY);
1380 
1381  // TODO check other values if needed
1382  number_of_ignored_parameter =
1383  sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1384  for (iterator = 0; iterator < number_of_ignored_parameter; iterator++)
1385  {
1387  strlen (OIDC_ignored_parameter_array[iterator]),
1388  &cache_key);
1389  if (GNUNET_YES ==
1391  ->url_param_map,
1392  &cache_key))
1393  {
1395  GNUNET_asprintf (&handle->edesc,
1396  "Server will not handle parameter: %s",
1397  OIDC_ignored_parameter_array[iterator]);
1399  return;
1400  }
1401  }
1402 
1403  // We only support authorization code flows.
1404  if (0 != strcmp (handle->oidc->response_type,
1406  {
1408  handle->edesc = GNUNET_strdup ("The authorization server does not support "
1409  "obtaining this authorization code.");
1411  return;
1412  }
1413 
1414  // Checks if scope contains 'openid'
1415  expected_scope = GNUNET_strdup (handle->oidc->scope);
1416  char *test;
1417  test = strtok (expected_scope, delimiter);
1418  while (NULL != test)
1419  {
1420  if (0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope))
1421  break;
1422  test = strtok (NULL, delimiter);
1423  }
1424  if (NULL == test)
1425  {
1427  handle->edesc =
1428  GNUNET_strdup ("The requested scope is invalid, unknown, or malformed.");
1430  GNUNET_free (expected_scope);
1431  return;
1432  }
1433 
1434  GNUNET_free (expected_scope);
1435  if ((NULL == handle->oidc->login_identity) &&
1436  (GNUNET_NO == handle->oidc->user_cancelled))
1438  else
1440 }
1441 
1442 
1446 static void
1447 tld_iter (void *cls, const char *section, const char *option, const char *value)
1448 {
1449  struct RequestHandle *handle = cls;
1450  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1451 
1452  if (GNUNET_OK !=
1453  GNUNET_CRYPTO_ecdsa_public_key_from_string (value, strlen (value), &pkey))
1454  {
1455  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping non key %s\n", value);
1456  return;
1457  }
1458  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1459  handle->tld = GNUNET_strdup (option + 1);
1460 }
1461 
1462 
1470 static void
1472  const char *url,
1473  void *cls)
1474 {
1475  struct RequestHandle *handle = cls;
1476  struct EgoEntry *tmp_ego;
1477  const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1478  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1479 
1481 
1482  // RECOMMENDED value: state - REQUIRED for answers
1483  handle->oidc->state = get_url_parameter_copy (handle, OIDC_STATE_KEY);
1484 
1485  // REQUIRED value: client_id
1487  if (NULL == handle->oidc->client_id)
1488  {
1490  handle->edesc = GNUNET_strdup ("missing parameter client_id");
1491  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1493  return;
1494  }
1495 
1496  // OPTIONAL value: code_challenge
1497  handle->oidc->code_challenge = get_url_parameter_copy (handle,
1499  if (NULL == handle->oidc->code_challenge)
1500  {
1502  "OAuth authorization request does not contain PKCE parameters!\n");
1503  }
1504 
1505  if (GNUNET_OK !=
1507  strlen (
1508  handle->oidc->client_id),
1509  &handle->oidc->client_pkey))
1510  {
1512  handle->edesc = GNUNET_strdup ("The client is not authorized to request an "
1513  "authorization code using this method.");
1514  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1516  return;
1517  }
1518 
1519  // If we know this identity, translated the corresponding TLD
1520  // TODO: We might want to have a reverse lookup functionality for TLDs?
1521  for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
1522  {
1523  priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
1524  GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, &pkey);
1525  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1526  {
1527  handle->tld = GNUNET_strdup (tmp_ego->identifier);
1528  handle->ego_entry = handle->ego_tail;
1529  }
1530  }
1531  handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
1533  handle->oidc->scope));
1534  if (NULL == handle->tld)
1536  if (NULL == handle->tld)
1537  handle->tld = GNUNET_strdup (handle->oidc->client_id);
1539 }
1540 
1541 
1549 static void
1551  const char *url,
1552  void *cls)
1553 {
1554  struct MHD_Response *resp = GNUNET_REST_create_response ("");
1555  struct RequestHandle *handle = cls;
1556  struct GNUNET_HashCode cache_key;
1557  struct GNUNET_TIME_Absolute *current_time;
1558  struct GNUNET_TIME_Absolute *last_time;
1559  char *cookie;
1560  char *header_val;
1561  json_t *root;
1562  json_error_t error;
1563  json_t *identity;
1564  char term_data[handle->rest_handle->data_size + 1];
1565 
1566  term_data[handle->rest_handle->data_size] = '\0';
1567  GNUNET_memcpy (term_data,
1568  handle->rest_handle->data,
1569  handle->rest_handle->data_size);
1570  root = json_loads (term_data, JSON_DECODE_ANY, &error);
1571  identity = json_object_get (root, "identity");
1572  if (! json_is_string (identity))
1573  {
1575  "Error parsing json string from %s\n",
1576  term_data);
1577  handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1578  json_decref (root);
1580  return;
1581  }
1582  GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1583  GNUNET_asprintf (&header_val,
1584  "%s;Max-Age=%d",
1585  cookie,
1587  MHD_add_response_header (resp, "Set-Cookie", header_val);
1588  MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST");
1589  GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1590 
1591  if (0 != strcmp (json_string_value (identity), "Denied"))
1592  {
1593  current_time = GNUNET_new (struct GNUNET_TIME_Absolute);
1594  *current_time = GNUNET_TIME_relative_to_absolute (
1597  last_time =
1598  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
1599  GNUNET_free_non_null (last_time);
1600  GNUNET_CONTAINER_multihashmap_put (OIDC_cookie_jar_map,
1601  &cache_key,
1602  current_time,
1604  }
1605  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1606  GNUNET_free (cookie);
1607  GNUNET_free (header_val);
1608  json_decref (root);
1610 }
1611 
1612 
1613 static int
1615  struct GNUNET_CRYPTO_EcdsaPublicKey *cid)
1616 {
1617  struct GNUNET_HashCode cache_key;
1618  char *authorization;
1619  char *credentials;
1620  char *basic_authorization;
1621  char *client_id;
1622  char *pass;
1623  char *expected_pass;
1624 
1627  &cache_key);
1629  ->header_param_map,
1630  &cache_key))
1631  {
1633  handle->edesc = GNUNET_strdup ("missing authorization");
1634  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1635  return GNUNET_SYSERR;
1636  }
1637  authorization =
1639  &cache_key);
1640 
1641  // split header in "Basic" and [content]
1642  credentials = strtok (authorization, " ");
1643  if ((NULL == credentials) || (0 != strcmp ("Basic", credentials)))
1644  {
1646  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1647  return GNUNET_SYSERR;
1648  }
1649  credentials = strtok (NULL, " ");
1650  if (NULL == credentials)
1651  {
1653  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1654  return GNUNET_SYSERR;
1655  }
1656  GNUNET_STRINGS_base64_decode (credentials,
1657  strlen (credentials),
1658  (void **) &basic_authorization);
1659 
1660  if (NULL == basic_authorization)
1661  {
1663  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1664  return GNUNET_SYSERR;
1665  }
1666  client_id = strtok (basic_authorization, ":");
1667  if (NULL == client_id)
1668  {
1669  GNUNET_free_non_null (basic_authorization);
1671  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1672  return GNUNET_SYSERR;
1673  }
1674  pass = strtok (NULL, ":");
1675  if (NULL == pass)
1676  {
1677  GNUNET_free_non_null (basic_authorization);
1679  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1680  return GNUNET_SYSERR;
1681  }
1682 
1683  // check client password
1685  "reclaim-rest-plugin",
1686  "OIDC_CLIENT_SECRET",
1687  &expected_pass))
1688  {
1689  if (0 != strcmp (expected_pass, pass))
1690  {
1691  GNUNET_free_non_null (basic_authorization);
1692  GNUNET_free (expected_pass);
1694  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1695  return GNUNET_SYSERR;
1696  }
1697  GNUNET_free (expected_pass);
1698  }
1699  else
1700  {
1701  GNUNET_free_non_null (basic_authorization);
1703  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1704  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1705  return GNUNET_SYSERR;
1706  }
1707 
1708  // check client_id
1709  for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
1710  handle->ego_entry = handle->ego_entry->next)
1711  {
1712  if (0 == strcmp (handle->ego_entry->keystring, client_id))
1713  break;
1714  }
1715  if (NULL == handle->ego_entry)
1716  {
1717  GNUNET_free_non_null (basic_authorization);
1719  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1720  return GNUNET_SYSERR;
1721  }
1722  GNUNET_STRINGS_string_to_data (client_id,
1723  strlen (client_id),
1724  cid,
1725  sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
1726 
1727  GNUNET_free (basic_authorization);
1728  return GNUNET_OK;
1729 }
1730 
1731 
1732 const struct EgoEntry *
1734  struct GNUNET_CRYPTO_EcdsaPublicKey *test_key)
1735 {
1736  struct EgoEntry *ego_entry;
1737  struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1738 
1739  for (ego_entry = handle->ego_head; NULL != ego_entry;
1740  ego_entry = ego_entry->next)
1741  {
1742  GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
1743  if (0 == GNUNET_memcmp (&pub_key, test_key))
1744  return ego_entry;
1745  }
1746  return NULL;
1747 }
1748 
1749 
1750 static void
1752  const char *access_token,
1753  const struct GNUNET_RECLAIM_Ticket *ticket)
1754 {
1755  struct GNUNET_HashCode hc;
1756  struct GNUNET_RECLAIM_Ticket *ticketbuf;
1757 
1758  GNUNET_CRYPTO_hash (access_token, strlen (access_token), &hc);
1759  ticketbuf = GNUNET_new (struct GNUNET_RECLAIM_Ticket);
1760  *ticketbuf = *ticket;
1763  OIDC_access_token_map,
1764  &hc,
1765  ticketbuf,
1767 }
1768 
1769 
1777 static void
1779  const char *url,
1780  void *cls)
1781 {
1782  struct RequestHandle *handle = cls;
1783  const struct EgoEntry *ego_entry;
1784  struct GNUNET_TIME_Relative expiration_time;
1785  struct GNUNET_RECLAIM_AttributeList *cl;
1786  struct GNUNET_RECLAIM_AttestationList *al;
1787  struct GNUNET_RECLAIM_Ticket ticket;
1788  struct GNUNET_CRYPTO_EcdsaPublicKey cid;
1789  const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
1790  struct GNUNET_HashCode cache_key;
1791  struct MHD_Response *resp;
1792  char *grant_type;
1793  char *code;
1794  char *json_response;
1795  char *id_token;
1796  char *access_token;
1797  char *jwt_secret;
1798  char *nonce;
1799  char *code_verifier;
1800 
1801  /*
1802  * Check Authorization
1803  */
1804  if (GNUNET_SYSERR == check_authorization (handle, &cid))
1805  {
1807  "OIDC authorization for token endpoint failed\n");
1809  return;
1810  }
1811 
1812  /*
1813  * Check parameter
1814  */
1815 
1816  // TODO Do not allow multiple equal parameter names
1817  // REQUIRED grant_type
1819  strlen (OIDC_GRANT_TYPE_KEY),
1820  &cache_key);
1821  grant_type = get_url_parameter_copy (handle, OIDC_GRANT_TYPE_KEY);
1822  if (NULL == grant_type)
1823  {
1825  handle->edesc = GNUNET_strdup ("missing parameter grant_type");
1826  handle->response_code = MHD_HTTP_BAD_REQUEST;
1828  return;
1829  }
1830 
1831  // Check parameter grant_type == "authorization_code"
1832  if (0 != strcmp (OIDC_GRANT_TYPE_VALUE, grant_type))
1833  {
1835  handle->response_code = MHD_HTTP_BAD_REQUEST;
1836  GNUNET_free (grant_type);
1838  return;
1839  }
1840  GNUNET_free (grant_type);
1841  // REQUIRED code
1842  code = get_url_parameter_copy (handle, OIDC_CODE_KEY);
1843  if (NULL == code)
1844  {
1846  handle->edesc = GNUNET_strdup ("missing parameter code");
1847  handle->response_code = MHD_HTTP_BAD_REQUEST;
1849  return;
1850  }
1851  ego_entry = find_ego (handle, &cid);
1852  if (NULL == ego_entry)
1853  {
1855  handle->edesc = GNUNET_strdup ("Unknown client");
1856  handle->response_code = MHD_HTTP_BAD_REQUEST;
1857  GNUNET_free (code);
1859  return;
1860  }
1861  privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1862 
1863  // REQUIRED code verifier
1864  code_verifier = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY);
1865  if (NULL == code_verifier)
1866  {
1868  "OAuth authorization request does not contain PKCE parameters!\n");
1869 
1870  }
1871 
1872  // decode code
1873  if (GNUNET_OK != OIDC_parse_authz_code (privkey, code, code_verifier, &ticket,
1874  &cl, &al, &nonce))
1875  {
1877  handle->edesc = GNUNET_strdup ("invalid code");
1878  handle->response_code = MHD_HTTP_BAD_REQUEST;
1879  GNUNET_free (code);
1881  return;
1882  }
1883  GNUNET_free (code);
1884 
1885  // create jwt
1887  "reclaim-rest-plugin",
1888  "expiration_time",
1889  &expiration_time))
1890  {
1892  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1893  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1895  return;
1896  }
1897 
1898 
1899  // TODO OPTIONAL acr,amr,azp
1901  "reclaim-rest-plugin",
1902  "jwt_secret",
1903  &jwt_secret))
1904  {
1906  handle->edesc = GNUNET_strdup ("No signing secret configured!");
1907  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1909  return;
1910  }
1911  id_token = OIDC_id_token_new (&ticket.audience,
1912  &ticket.identity,
1913  cl,
1914  al,
1915  &expiration_time,
1916  (NULL != nonce) ? nonce : NULL,
1917  jwt_secret);
1918  access_token = OIDC_access_token_new ();
1919  OIDC_build_token_response (access_token,
1920  id_token,
1921  &expiration_time,
1922  &json_response);
1923 
1924  persist_access_token (handle, access_token, &ticket);
1925  resp = GNUNET_REST_create_response (json_response);
1926  MHD_add_response_header (resp, "Cache-Control", "no-store");
1927  MHD_add_response_header (resp, "Pragma", "no-cache");
1928  MHD_add_response_header (resp, "Content-Type", "application/json");
1929  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1932  GNUNET_free (access_token);
1933  GNUNET_free (json_response);
1934  GNUNET_free (id_token);
1936 }
1937 
1938 
1942 static void
1943 consume_ticket (void *cls,
1944  const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1945  const struct GNUNET_RECLAIM_Attribute *attr,
1946  const struct GNUNET_RECLAIM_Attestation *attest)
1947 {
1948  struct RequestHandle *handle = cls;
1949  if (NULL == identity)
1950  {
1952  return;
1953  }
1955  {
1956  char *tmp_value;
1957  json_t *value;
1959  attr->data,
1960  attr->data_size);
1961  value = json_string (tmp_value);
1962  json_object_set_new (handle->oidc->response, attr->name, value);
1963  GNUNET_free (tmp_value);
1964  return;
1965  }
1966  json_t *claim_sources;
1967  json_t *claim_sources_jwt;
1968  json_t *claim_names;
1969  char *attest_val_str;
1970  claim_sources = json_object_get (handle->oidc->response,"_claim_sources");
1971  claim_names = json_object_get (handle->oidc->response,"_claim_names");
1972  attest_val_str =
1974  attest->data,
1975  attest->data_size);
1976  if ((NULL == claim_sources) && (NULL == claim_names) )
1977  {
1978  claim_sources = json_object ();
1979  claim_names = json_object ();
1980  }
1981  char *source_name;
1982  int i = 0;
1983  GNUNET_asprintf (&source_name, "src%d", i);
1984  while (NULL != (claim_sources_jwt = json_object_get (claim_sources,
1985  source_name)))
1986  {
1987  if (0 == strcmp (json_string_value (json_object_get (claim_sources_jwt,
1988  "JWT")),
1989  attest_val_str))
1990  {
1991  // Adapt only the claim names
1992  json_object_set_new (claim_names, attr->data,
1993  json_string (source_name));
1994  json_object_set (handle->oidc->response,
1995  "_claim_names", claim_names);
1996  break;
1997  }
1998  i++;
1999  GNUNET_free (source_name);
2000  GNUNET_asprintf (&source_name, "src%d", i);
2001  }
2002 
2003  // Create new one
2004  if (NULL == claim_sources_jwt)
2005  {
2006  claim_sources_jwt = json_object ();
2007  // Set the JWT for names
2008  json_object_set_new (claim_names, attr->data,
2009  json_string (source_name));
2010  // Set the JWT for the inner source
2011  json_object_set_new (claim_sources_jwt, "JWT",
2012  json_string (attest_val_str));
2013  // Set the JWT for the source
2014  json_object_set_new (claim_sources, source_name, claim_sources_jwt);
2015  // Set as claims
2016  json_object_set (handle->oidc->response, "_claim_names", claim_names);
2017  json_object_set (handle->oidc->response, "_claim_sources",claim_sources);
2018  }
2019 
2020  json_decref (claim_sources);
2021  json_decref (claim_names);
2022  json_decref (claim_sources_jwt);
2023  GNUNET_free (attest_val_str);
2024 }
2025 
2026 
2034 static void
2036  const char *url,
2037  void *cls)
2038 {
2039  // TODO expiration time
2040  struct RequestHandle *handle = cls;
2041  char delimiter[] = " ";
2042  struct GNUNET_HashCode cache_key;
2043  char *authorization;
2044  char *authorization_type;
2045  char *authorization_access_token;
2046  struct GNUNET_RECLAIM_Ticket *ticket;
2047  const struct EgoEntry *ego_entry;
2048  const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
2049 
2052  &cache_key);
2054  ->header_param_map,
2055  &cache_key))
2056  {
2058  handle->edesc = GNUNET_strdup ("No Access Token");
2059  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2061  return;
2062  }
2063  authorization =
2065  &cache_key);
2066 
2067  // split header in "Bearer" and access_token
2068  authorization = GNUNET_strdup (authorization);
2069  authorization_type = strtok (authorization, delimiter);
2070  if ((NULL == authorization_type) ||
2071  (0 != strcmp ("Bearer", authorization_type)))
2072  {
2074  handle->edesc = GNUNET_strdup ("No Access Token");
2075  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2077  GNUNET_free (authorization);
2078  return;
2079  }
2080  authorization_access_token = strtok (NULL, delimiter);
2081  if (NULL == authorization_access_token)
2082  {
2084  handle->edesc = GNUNET_strdup ("Access token missing");
2085  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2087  GNUNET_free (authorization);
2088  return;
2089  }
2090 
2091  GNUNET_CRYPTO_hash (authorization_access_token,
2092  strlen (authorization_access_token),
2093  &cache_key);
2094  if (GNUNET_NO ==
2095  GNUNET_CONTAINER_multihashmap_contains (OIDC_access_token_map,
2096  &cache_key))
2097  {
2099  handle->edesc = GNUNET_strdup ("The access token expired");
2100  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2102  GNUNET_free (authorization);
2103  return;
2104  }
2105  ticket =
2106  GNUNET_CONTAINER_multihashmap_get (OIDC_access_token_map, &cache_key);
2107  GNUNET_assert (NULL != ticket);
2108  ego_entry = find_ego (handle, &ticket->audience);
2109  if (NULL == ego_entry)
2110  {
2112  handle->edesc = GNUNET_strdup ("The access token expired");
2113  handle->response_code = MHD_HTTP_UNAUTHORIZED;
2115  GNUNET_free (authorization);
2116  return;
2117  }
2118 
2119  handle->idp = GNUNET_RECLAIM_connect (cfg);
2120  handle->oidc->response = json_object ();
2121  json_object_set_new (handle->oidc->response,
2122  "sub",
2123  json_string (ego_entry->keystring));
2124  privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
2125  handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
2126  privkey,
2127  ticket,
2129  handle);
2130  GNUNET_free (authorization);
2131 }
2132 
2133 
2139 static void
2141 {
2143  static const struct GNUNET_REST_RequestHandler handlers[] =
2144  { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint },
2145  { MHD_HTTP_METHOD_POST,
2147  &authorize_endpoint }, // url-encoded
2148  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont },
2149  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
2150  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2151  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2152  { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, &options_cont },
2154 
2155  if (GNUNET_NO ==
2156  GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
2157  {
2158  handle->response_code = err.error_code;
2160  }
2161 }
2162 
2163 
2197 static void
2198 list_ego (void *cls,
2199  struct GNUNET_IDENTITY_Ego *ego,
2200  void **ctx,
2201  const char *identifier)
2202 {
2203  struct RequestHandle *handle = cls;
2204  struct EgoEntry *ego_entry;
2205  struct GNUNET_CRYPTO_EcdsaPublicKey pk;
2206 
2207  if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
2208  {
2209  handle->state = ID_REST_STATE_POST_INIT;
2210  init_cont (handle);
2211  return;
2212  }
2213  GNUNET_assert (NULL != ego);
2214  if (ID_REST_STATE_INIT == handle->state)
2215 
2216  {
2217  ego_entry = GNUNET_new (struct EgoEntry);
2220  ego_entry->ego = ego;
2221  ego_entry->identifier = GNUNET_strdup (identifier);
2223  handle->ego_tail,
2224  ego_entry);
2225  return;
2226  }
2227  /* Ego renamed or added */
2228  if (identifier != NULL)
2229  {
2230  for (ego_entry = handle->ego_head; NULL != ego_entry;
2231  ego_entry = ego_entry->next)
2232  {
2233  if (ego_entry->ego == ego)
2234  {
2235  /* Rename */
2236  GNUNET_free (ego_entry->identifier);
2237  ego_entry->identifier = GNUNET_strdup (identifier);
2238  break;
2239  }
2240  }
2241  if (NULL == ego_entry)
2242  {
2243  /* Add */
2244  ego_entry = GNUNET_new (struct EgoEntry);
2247  ego_entry->ego = ego;
2248  ego_entry->identifier = GNUNET_strdup (identifier);
2250  handle->ego_tail,
2251  ego_entry);
2252  }
2253  }
2254  else
2255  {
2256  /* Delete */
2257  for (ego_entry = handle->ego_head; NULL != ego_entry;
2258  ego_entry = ego_entry->next)
2259  {
2260  if (ego_entry->ego == ego)
2261  break;
2262  }
2263  if (NULL != ego_entry)
2265  handle->ego_tail,
2266  ego_entry);
2267  }
2268 }
2269 
2270 
2271 static void
2274  void *proc_cls)
2275 {
2276  struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
2277 
2278  handle->oidc = GNUNET_new (struct OIDC_Variables);
2279  if (NULL == OIDC_cookie_jar_map)
2280  OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2281  if (NULL == OIDC_access_token_map)
2282  OIDC_access_token_map =
2284  handle->response_code = 0;
2286  handle->proc_cls = proc_cls;
2287  handle->proc = proc;
2288  handle->state = ID_REST_STATE_INIT;
2289  handle->rest_handle = rest_handle;
2290 
2291  handle->url = GNUNET_strdup (rest_handle->url);
2292  if (handle->url[strlen (handle->url) - 1] == '/')
2293  handle->url[strlen (handle->url) - 1] = '\0';
2294  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
2295  handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
2296  handle->gns_handle = GNUNET_GNS_connect (cfg);
2298  handle->timeout_task =
2299  GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
2300  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
2301 }
2302 
2303 
2310 void *
2312 {
2313  static struct Plugin plugin;
2314  struct GNUNET_REST_Plugin *api;
2315 
2316  cfg = cls;
2317  if (NULL != plugin.cfg)
2318  return NULL; /* can only initialize once! */
2319  memset (&plugin, 0, sizeof(struct Plugin));
2320  plugin.cfg = cfg;
2321  api = GNUNET_new (struct GNUNET_REST_Plugin);
2322  api->cls = &plugin;
2326  "%s, %s, %s, %s, %s",
2327  MHD_HTTP_METHOD_GET,
2328  MHD_HTTP_METHOD_POST,
2329  MHD_HTTP_METHOD_PUT,
2330  MHD_HTTP_METHOD_DELETE,
2331  MHD_HTTP_METHOD_OPTIONS);
2332 
2334  _ ("OpenID Connect REST API initialized\n"));
2335  return api;
2336 }
2337 
2338 
2345 void *
2347 {
2348  struct GNUNET_REST_Plugin *api = cls;
2349  struct Plugin *plugin = api->cls;
2350 
2351  plugin->cfg = NULL;
2352 
2353  struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2354  void *value = NULL;
2355  hashmap_it =
2356  GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_cookie_jar_map);
2357  while (GNUNET_YES ==
2358  GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2359  GNUNET_free_non_null (value);
2361  GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map);
2362 
2363  hashmap_it =
2364  GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_access_token_map);
2365  while (GNUNET_YES ==
2366  GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2367  GNUNET_free_non_null (value);
2368  GNUNET_CONTAINER_multihashmap_destroy (OIDC_access_token_map);
2371  GNUNET_free (api);
2373  "OpenID Connect REST plugin is finished\n");
2374  return NULL;
2375 }
2376 
2377 
2378 /* end of plugin_rest_openid_connect.c */
struct GNUNET_IDENTITY_Handle * GNUNET_IDENTITY_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_IDENTITY_Callback cb, void *cb_cls)
Connect to the identity service.
Definition: identity_api.c:527
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static void build_redirect(void *cls)
static int iterator(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Iterator over hash map entries.
Connection to the GNS service.
Definition: gns_api.h:35
void GNUNET_CONTAINER_multihashmap_iterator_destroy(struct GNUNET_CONTAINER_MultiHashMapIterator *iter)
Destroy a multihashmap iterator.
char * redirect_uri
The OIDC redirect uri.
char * scope
The list of oidc scopes.
Handle to the service.
Definition: reclaim_api.c:312
The authorization ticket.
#define OIDC_NONCE_KEY
OIDC nonce key.
void(* GNUNET_REST_ResultProcessor)(void *cls, struct MHD_Response *resp, int status)
Iterator called on obtained result for a REST result.
int GNUNET_CONTAINER_multihashmap_iterator_next(struct GNUNET_CONTAINER_MultiHashMapIterator *iter, struct GNUNET_HashCode *key, const void **value)
Retrieve the next element from the hash map at the iterator&#39;s position.
#define OIDC_CODE_CHALLENGE_KEY
OIDC PKCE code challenge.
struct GNUNET_RECLAIM_AttributeIterator * GNUNET_RECLAIM_get_attributes_start(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls, GNUNET_RECLAIM_AttributeResult proc, void *proc_cls, GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls)
List all attributes for a local identity.
Definition: reclaim_api.c:1293
int GNUNET_CONFIGURATION_get_value_time(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, struct GNUNET_TIME_Relative *time)
Get a configuration value that should be a relative time.
char * OIDC_id_token_new(const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, struct GNUNET_RECLAIM_AttributeList *attrs, struct GNUNET_RECLAIM_AttestationList *attests, const struct GNUNET_TIME_Relative *expiration_time, const char *nonce, const char *secret_key)
Create a JWT from attributes.
Definition: oidc_helper.c:124
struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_ticket_consume(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, const struct GNUNET_RECLAIM_Ticket *ticket, GNUNET_RECLAIM_AttributeTicketResult cb, void *cb_cls)
Consumes an issued ticket.
Definition: reclaim_api.c:1553
struct EgoEntry * ego_tail
Ego list.
struct GNUNET_RECLAIM_AttestationIterator * GNUNET_RECLAIM_get_attestations_start(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls, GNUNET_RECLAIM_AttestationResult proc, void *proc_cls, GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls)
List all attestations for a local identity.
Definition: reclaim_api.c:1402
void GNUNET_CONFIGURATION_iterate_section_values(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, GNUNET_CONFIGURATION_Iterator iter, void *iter_cls)
Iterate over values of a section in the configuration.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
If a value with the given key exists, replace it.
char * nonce
The OIDC nonce.
void GNUNET_RECLAIM_attribute_list_destroy(struct GNUNET_RECLAIM_AttributeList *attrs)
Destroy claim list.
#define GNUNET_GNS_EMPTY_LABEL_AT
String we use to indicate an empty label (top-level entry in the zone).
#define OIDC_GRANT_TYPE_KEY
OIDC grant_type key.
void GNUNET_RECLAIM_attestation_list_destroy(struct GNUNET_RECLAIM_AttestationList *attestations)
Destroy claim list.
#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE
OIDC expected response_type while authorizing.
char * OIDC_build_authz_code(const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, const struct GNUNET_RECLAIM_Ticket *ticket, struct GNUNET_RECLAIM_AttributeList *attrs, struct GNUNET_RECLAIM_AttestationList *attests, const char *nonce_str, const char *code_challenge)
Builds an OIDC authorization code including a reclaim ticket and nonce.
Definition: oidc_helper.c:431
struct GNUNET_CONTAINER_MultiHashMapIterator * GNUNET_CONTAINER_multihashmap_iterator_create(const struct GNUNET_CONTAINER_MultiHashMap *map)
Create an iterator for a multihashmap.
void * cls
The closure of the plugin.
size_t data_size
The POST data size.
struct GNUNET_RECLAIM_AttributeIterator * attr_it
Attribute iterator.
const char * name
The name of the attribute.
static void cookie_identity_interpretation(struct RequestHandle *handle)
Interprets cookie header and pass its identity keystring to handle.
static void persist_access_token(const struct RequestHandle *handle, const char *access_token, const struct GNUNET_RECLAIM_Ticket *ticket)
#define OIDC_CODE_KEY
OIDC code key.
struct GNUNET_RECLAIM_AttestationIterator * attest_it
Attestation iterator.
GNUNET_REST_ResultProcessor proc
The plugin result processor.
#define OIDC_ERROR_KEY_SERVER_ERROR
OIDC error key for generic server errors.
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition: time.c:246
static size_t data_size
Number of bytes in data.
Definition: gnunet-abd.c:187
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define OIDC_REDIRECT_URI_KEY
OIDC redirect_uri key.
#define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT
OIDC error key for unauthorized clients.
struct GNUNET_GNS_LookupRequest * gns_op
GNS lookup op.
#define OIDC_CLAIMS_KEY
OIDC claims key.
char * key
TLS key.
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Handle to a lookup request.
Definition: gns_api.c:48
const struct GNUNET_CRYPTO_EcdsaPrivateKey * GNUNET_IDENTITY_ego_get_private_key(const struct GNUNET_IDENTITY_Ego *ego)
Obtain the ECC key associated with a ego.
Definition: identity_api.c:555
void GNUNET_RECLAIM_disconnect(struct GNUNET_RECLAIM_Handle *h)
Disconnect from identity provider service.
Definition: reclaim_api.c:1066
#define OIDC_COOKIE_EXPIRATION
OIDC cookie expiration (in seconds)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
struct returned by the initialization function of the plugin
static void oidc_ticket_issue_cb(void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
Issues ticket and redirects to relying party with the authorization code as parameter.
struct GNUNET_RECLAIM_Attestation * attestation
The attestation.
helper library for OIDC related functions
#define GNUNET_NO
Definition: gnunet_common.h:86
#define OIDC_COOKIE_HEADER_INFORMATION_KEY
OIDC cookie header information key.
A list of GNUNET_RECLAIM_Attribute structures.
void GNUNET_RECLAIM_ticket_iteration_stop(struct GNUNET_RECLAIM_TicketIterator *it)
Stops iteration and releases the handle for further calls.
Definition: reclaim_api.c:1661
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:83
size_t data_size
Number of bytes in data.
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
A list of GNUNET_RECLAIM_Attestation structures.
static void tld_iter(void *cls, const char *section, const char *option, const char *value)
Iterate over tlds in config.
#define OIDC_COOKIE_HEADER_ACCESS_DENIED
OIDC cookie header if user cancelled.
int user_cancelled
User cancelled authorization/login.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
static void rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Private ECC key encoded for transmission.
void GNUNET_RECLAIM_get_attributes_next(struct GNUNET_RECLAIM_AttributeIterator *it)
Calls the record processor specified in GNUNET_RECLAIM_get_attributes_start for the next record...
Definition: reclaim_api.c:1339
#define OIDC_ERROR_KEY_INVALID_TOKEN
OIDC error key for invalid tokens.
void * libgnunet_plugin_rest_openid_connect_init(void *cls)
Entry point for the plugin.
Handle for an operation with the service.
Definition: reclaim_api.c:41
int GNUNET_CONTAINER_multihashmap_contains(const struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key)
Check if the map contains any value under the given key (including values that are NULL)...
void(* process_request)(struct GNUNET_REST_RequestHandle *handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function to process a REST call.
void OIDC_build_token_response(const char *access_token, const char *id_token, const struct GNUNET_TIME_Relative *expiration_time, char **token_response)
Build a token response for a token request TODO: Maybe we should add the scope here?
Definition: oidc_helper.c:729
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
static void login_redirect(void *cls)
Redirects to login page stored in configuration file.
void * proc_cls
The closure of the result processor.
uint64_t abs_value_us
The actual value.
char * edesc
Error response description.
struct OIDC_Variables * oidc
OIDC variables.
void GNUNET_RECLAIM_get_attestations_next(struct GNUNET_RECLAIM_AttestationIterator *ait)
Calls the record processor specified in #GNUNET_RECLAIM_get_attestation_start for the next record...
Definition: reclaim_api.c:1449
Internal representation of the hash map.
Handle for an operation with the identity service.
Definition: identity_api.c:39
#define GNUNET_REST_HANDLER_END
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:47
#define OIDC_STATE_KEY
OIDC state key.
struct GNUNET_RECLAIM_Attribute * attribute
The attribute claim.
The request handle.
void * GNUNET_CONTAINER_multihashmap_get(const struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key)
Given a key find a value in the map matching the key.
#define _(String)
GNU gettext support macro.
Definition: platform.h:180
static char * section
Name of the section.
Definition: gnunet-config.c:33
#define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE
OIDC error key for unsupported grants.
The ego list.
char * response_type
The OIDC response type.
#define OIDC_RESPONSE_TYPE_KEY
OIDC response_type key.
char * GNUNET_RECLAIM_attestation_value_to_string(uint32_t type, const void *data, size_t data_size)
Convert the &#39;claim&#39; of an attestation to a string.
struct GNUNET_RECLAIM_Identifier attestation
Referenced ID of Attestation (may be 0 if self-attested)
static struct GNUNET_RECLAIM_Ticket ticket
Ticket to consume.
struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey
The RP client public key.
struct GNUNET_IDENTITY_Ego * ego
The Ego.
void GNUNET_NAMESTORE_disconnect(struct GNUNET_NAMESTORE_Handle *h)
Disconnect from the namestore service (and free associated resources).
OIDC needed variables.
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
Handle for a zone iterator operation.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1271
Handle for an ego.
Definition: identity.h:245
int OIDC_parse_authz_code(const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv, const char *code, const char *code_verifier, struct GNUNET_RECLAIM_Ticket *ticket, struct GNUNET_RECLAIM_AttributeList **attrs, struct GNUNET_RECLAIM_AttestationList **attests, char **nonce_str)
Parse reclaim ticket and nonce from authorization code.
Definition: oidc_helper.c:584
Handle for a attribute iterator operation.
Definition: reclaim_api.c:177
enum State state
current state of profiling
static void do_timeout(void *cls)
Task run on timeout, sends error message.
const struct EgoEntry * find_ego(struct RequestHandle *handle, struct GNUNET_CRYPTO_EcdsaPublicKey *test_key)
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
static char * value
Value of the record to add/remove.
char * emsg
Error response message.
static void oidc_attr_collect(void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, const struct GNUNET_RECLAIM_Attribute *attr)
Collects all attributes for an ego if in scope parameter.
struct GNUNET_CONTAINER_MultiHashMap * url_param_map
Map of url parameters.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:48
const char * url
The url as string.
char * client_id
The OIDC client id of the RP.
Connection to the NAMESTORE service.
Handle for the service.
Definition: identity_api.c:95
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
struct GNUNET_RECLAIM_AttributeListEntry * list_tail
List tail.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1298
char * name
Plugin name.
void GNUNET_GNS_disconnect(struct GNUNET_GNS_Handle *handle)
Shutdown connection with the GNS service.
Definition: gns_api.c:290
#define OIDC_ERROR_KEY_INVALID_COOKIE
OIDC error key for invalid cookies.
#define OIDC_ERROR_KEY_INVALID_REQUEST
OIDC error key for invalid requests.
struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
static void lookup_redirect_uri_result(void *cls, uint32_t rd_count, const struct GNUNET_GNSRECORD_Data *rd)
struct GNUNET_RECLAIM_TicketIterator * ticket_it
Ticket iterator.
char * tld
The tld for redirect.
static char * get_url_parameter_copy(const struct RequestHandle *handle, const char *key)
static char * option
Name of the option.
Definition: gnunet-config.c:38
static void consume_ticket(void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, const struct GNUNET_RECLAIM_Attribute *attr, const struct GNUNET_RECLAIM_Attestation *attest)
Collects claims and stores them in handle.
static struct GNUNET_IDENTITY_Handle * identity_handle
Identity handle.
#define GNUNET_REST_API_NS_AUTHORIZE
Authorize endpoint.
static struct GNUNET_DNS_Handle * handle
Handle to transport service.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Multiply relative time by a given factor.
Definition: time.c:442
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
static void oidc_attest_collect(void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, const struct GNUNET_RECLAIM_Attestation *attest)
Collects all attributes for an ego if in scope parameter.
void GNUNET_IDENTITY_disconnect(struct GNUNET_IDENTITY_Handle *h)
Disconnect from identity service.
Definition: identity_api.c:837
struct GNUNET_RECLAIM_Identifier id
ID.
struct GNUNET_GNS_Handle * GNUNET_GNS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Initialize the connection with the GNS service.
Definition: gns_api.c:268
size_t data_size
Number of bytes in data.
#define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE
OIDC error key for unsupported response types.
#define OIDC_CODE_VERIFIER_KEY
OIDC PKCE code verifier.
size_t data_size
Number of bytes in data.
static void init_cont(struct RequestHandle *handle)
Handle rest request.
int GNUNET_REST_handle_request(struct GNUNET_REST_RequestHandle *conn, const struct GNUNET_REST_RequestHandler *handlers, struct GNUNET_REST_RequestHandlerError *err, void *cls)
Definition: rest.c:77
static void cleanup_handle(struct RequestHandle *handle)
Cleanup lookup handle.
struct GNUNET_REST_RequestHandle * rest_handle
Rest connection.
A 512-bit hashcode.
int response_code
Response code.
int state
The processing state.
struct GNUNET_RECLAIM_Attestation * GNUNET_RECLAIM_attestation_new(const char *name, uint32_t type, const void *data, size_t data_size)
Create a new attestation.
static void login_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Combines an identity with a login time and responds OK to login request.
static void code_redirect(void *cls)
Checks time and cookie and redirects accordingly.
static char * plugin
Solver plugin name as string.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:118
size_t GNUNET_STRINGS_base64_decode(const char *data, size_t len, void **output)
Decode from Base64.
Definition: strings.c:1959
const char * name
The name of the attribute.
struct GNUNET_RECLAIM_Identifier id
ID.
char * GNUNET_CRYPTO_ecdsa_public_key_to_string(const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
Convert a public key to a string.
Definition: crypto_ecc.c:223
int GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
const char * data
The POST data.
char * claims
The OIDC claims.
struct GNUNET_CRYPTO_EcdsaPublicKey identity
The ticket issuer (= the user)
uint32_t type
Type/Format of Claim.
char * keystring
Public key string.
static void oidc_attest_collect_finished_cb(void *cls)
struct GNUNET_RECLAIM_Handle * idp
Identity Provider.
static struct GNUNET_IDENTITY_Handle * identity
Which namespace do we publish to? NULL if we do not publish to a namespace.
struct GNUNET_CONTAINER_MultiHashMap * OIDC_access_token_map
Hash map that links the issued access token to the corresponding ticket and ego.
There must only be one value per key; storing a value should fail if a value under the same key alrea...
static void return_userinfo_response(void *cls)
Return attributes for claim.
#define GNUNET_SYSERR
Definition: gnunet_common.h:84
void GNUNET_CRYPTO_ecdsa_key_get_public(const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv, struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
Extract the public key for the given private key.
Definition: crypto_ecc.c:172
#define OIDC_ERROR_KEY_ACCESS_DENIED
OIDC error key for denied access.
struct GNUNET_RECLAIM_AttestationListEntry * list_head
List head.
static void userinfo_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Responds to userinfo GET and url-encoded POST request.
struct GNUNET_NAMESTORE_Handle * GNUNET_NAMESTORE_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Connect to the namestore service.
#define OIDC_AUTHORIZATION_HEADER_KEY
OIDC cookie header information key.
struct GNUNET_RECLAIM_AttributeListEntry * next
DLL.
#define OIDC_EXPECTED_AUTHORIZATION_SCOPE
OIDC expected scope part while authorizing.
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
#define GNUNET_REST_API_NS_LOGIN
Login namespace.
static struct GNUNET_SCHEDULER_Task * timeout_task
Task to be run on timeout.
Definition: gnunet-arm.c:124
static char * OIDC_ignored_parameter_array[]
OIDC ignored parameter array.
static struct Ego * ego_head
Head of DLL of all egos.
static int check_authorization(struct RequestHandle *handle, struct GNUNET_CRYPTO_EcdsaPublicKey *cid)
static void build_authz_response(void *cls)
Iteration over all results finished, build final response.
char * state
The OIDC state.
int GNUNET_CONTAINER_multihashmap_put(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
void GNUNET_IDENTITY_ego_get_public_key(const struct GNUNET_IDENTITY_Ego *ego, struct GNUNET_CRYPTO_EcdsaPublicKey *pk)
Get the identifier (public key) of an ego.
Definition: identity_api.c:568
struct GNUNET_RECLAIM_Attribute * GNUNET_RECLAIM_attribute_new(const char *attr_name, const struct GNUNET_RECLAIM_Identifier *attestation, uint32_t type, const void *data, size_t data_size)
Create a new attribute claim.
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
#define GNUNET_REST_API_NS_OIDC
REST root namespace.
static void client_redirect(void *cls)
Initiate redirect back to client.
static void authorize_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Responds to authorization GET and url-encoded POST request.
char * identifier
Ego Identifier.
static void do_error(void *cls)
Task run on error, sends error message.
struct GNUNET_RECLAIM_AttributeList * attr_list
Attribute claim list.
#define GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT
Record type for reclaim OIDC redirect URIs.
const void * data
Binary value stored as attribute value.
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
static void cleanup_handle_delayed(void *cls)
char * redirect_prefix
The redirect prefix.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_second_(void)
Return relative time of 1s.
Definition: time.c:183
static char * allow_methods
HTTP methods allows for this plugin.
struct GNUNET_RECLAIM_Ticket ticket
A ticket.
char * OIDC_access_token_new()
Generate a new access token.
Definition: oidc_helper.c:757
struct GNUNET_RECLAIM_AttestationListEntry * list_tail
List tail.
int GNUNET_CRYPTO_ecdsa_public_key_from_string(const char *enc, size_t enclen, struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
Convert a string representing a public key to a public key.
Definition: crypto_ecc.c:357
struct GNUNET_GNS_Handle * gns_handle
GNS handle.
configuration data
Definition: configuration.c:84
struct EgoEntry * ego_head
Ego list.
Handle for a plugin.
Definition: block.c:37
static void options_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Respond to OPTIONS request.
void GNUNET_RECLAIM_get_attributes_stop(struct GNUNET_RECLAIM_AttributeIterator *it)
Stops iteration and releases the handle for further calls.
Definition: reclaim_api.c:1360
Handle for a attestation iterator operation.
Definition: reclaim_api.c:244
struct GNUNET_CRYPTO_EcdsaPublicKey audience
The ticket audience (= relying party)
struct GNUNET_SCHEDULER_Task * timeout_task
ID of a task associated with the resolution process.
static void list_ego(void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, const char *identifier)
If listing is enabled, prints information about the egos.
static void token_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Responds to token url-encoded POST request.
char * redirect_suffix
The redirect suffix.
struct GNUNET_RECLAIM_AttestationList * attests_list
Attestation list.
#define OIDC_ERROR_KEY_INVALID_CLIENT
OIDC error key for invalid client.
struct MHD_Response * GNUNET_REST_create_response(const char *data)
Create REST MHD response.
Definition: rest.c:57
Public ECC key (always for Curve25519) encoded in a format suitable for network transmission and ECDS...
#define GNUNET_RECLAIM_id_is_equal(a, b)
Handle for a ticket iterator operation.
Definition: reclaim_api.c:114
#define GNUNET_log(kind,...)
const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration handle.
Entry in list of pending tasks.
Definition: scheduler.c:134
const void * data
Binary value stored as attribute value.
#define OIDC_SCOPE_KEY
OIDC scope key.
struct GNUNET_RECLAIM_Operation * idp_op
Idp Operation.
void * GNUNET_GNS_lookup_cancel(struct GNUNET_GNS_LookupRequest *lr)
Cancel pending lookup request.
Definition: gns_api.c:314
#define OIDC_GRANT_TYPE_VALUE
OIDC grant_type key.
char * GNUNET_RECLAIM_attribute_value_to_string(uint32_t type, const void *data, size_t data_size)
Convert the &#39;claim&#39; of an attribute to a string.
#define ID_REST_STATE_INIT
State while collecting all egos.
struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
uint32_t type
Type of Claim.
struct GNUNET_NAMESTORE_ZoneIterator * namestore_handle_it
Iterator for NAMESTORE.
#define OIDC_CLIENT_ID_KEY
OIDC client_id key.
char * code_verifier
The PKCE code_verifier.
Time for absolute times used by GNUnet, in microseconds.
json_t * response
The response JSON.
#define GNUNET_YES
Definition: gnunet_common.h:85
struct GNUNET_CONTAINER_MultiHashMap * header_param_map
Map of headers.
Defaults, look in cache, then in DHT.
struct EgoEntry * prev
DLL.
struct GNUNET_CONTAINER_MultiHashMap * OIDC_cookie_jar_map
OIDC Hash map that keeps track of issued cookies.
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:923
void * libgnunet_plugin_rest_openid_connect_done(void *cls)
Exit point from the plugin.
static struct Ego * ego_tail
Tail of DLL of all egos.
static struct GNUNET_ARM_Operation * op
Current operation.
Definition: gnunet-arm.c:144
char * code_challenge
The PKCE code_challenge.
struct EgoEntry * ego_entry
IDENTITY Operation.
struct GNUNET_GNS_LookupRequest * GNUNET_GNS_lookup(struct GNUNET_GNS_Handle *handle, const char *name, const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, uint32_t type, enum GNUNET_GNS_LocalOptions options, GNUNET_GNS_LookupResultProcessor proc, void *proc_cls)
Perform an asynchronous lookup operation on the GNS.
Definition: gns_api.c:412
static void oidc_iteration_error(void *cls)
Does internal server error when iteration failed.
struct GNUNET_RECLAIM_Handle * GNUNET_RECLAIM_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Connect to the re:claimID service.
Definition: reclaim_api.c:1026
uint32_t data
The data value.
#define OIDC_COOKIE_HEADER_KEY
OIDC cookie header key.
struct EgoEntry * next
DLL.
#define GNUNET_REST_API_NS_USERINFO
UserInfo endpoint.
void GNUNET_RECLAIM_get_attestations_stop(struct GNUNET_RECLAIM_AttestationIterator *ait)
Stops iteration and releases the handle for further calls.
Definition: reclaim_api.c:1471
struct GNUNET_RECLAIM_AttributeListEntry * list_head
List head.
int GNUNET_STRINGS_string_to_data(const char *enc, size_t enclen, void *out, size_t out_size)
Convert CrockfordBase32 encoding back to data.
Definition: strings.c:955
struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_ticket_issue(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss, const struct GNUNET_CRYPTO_EcdsaPublicKey *rp, const struct GNUNET_RECLAIM_AttributeList *attrs, GNUNET_RECLAIM_TicketCallback cb, void *cb_cls)
Issues a ticket to a relying party.
Definition: reclaim_api.c:1504
struct GNUNET_IDENTITY_Handle * identity_handle
Handle to Identity service.
#define ID_REST_STATE_POST_INIT
Done collecting egos.
#define GNUNET_free(ptr)
Wrapper around free.
Time for relative time used by GNUnet, in microseconds.
static void oidc_attr_collect_finished_cb(void *cls)
#define OIDC_ERROR_KEY_INVALID_SCOPE
OIDC error key for invalid scopes.
#define GNUNET_RECLAIM_id_is_zero(a)
#define GNUNET_REST_API_NS_TOKEN
Token endpoint.
struct GNUNET_NAMESTORE_Handle * namestore_handle
Handle to NAMESTORE.
char * login_identity
The identity chosen by the user to login.
struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key
Pointer to ego private key.
static void do_userinfo_error(void *cls)
Task run on error in userinfo endpoint, sends error header.
static void do_redirect_error(void *cls)
Task run on error, sends error message and redirects.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:974
char * url
The url.