GNUnet  0.10.x
plugin_rest_openid_connect.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2012-2018 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
27 #include "platform.h"
28 #include <inttypes.h>
29 #include <jansson.h>
30 
31 #include "gnunet_gns_service.h"
32 #include "gnunet_gnsrecord_lib.h"
36 #include "gnunet_reclaim_service.h"
37 #include "gnunet_rest_lib.h"
38 #include "gnunet_rest_plugin.h"
39 #include "gnunet_signatures.h"
40 #include "microhttpd.h"
41 #include "oidc_helper.h"
45 #define GNUNET_REST_API_NS_OIDC "/openid"
46 
50 #define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize"
51 
55 #define GNUNET_REST_API_NS_TOKEN "/openid/token"
56 
60 #define GNUNET_REST_API_NS_USERINFO "/openid/userinfo"
61 
65 #define GNUNET_REST_API_NS_LOGIN "/openid/login"
66 
70 #define ID_REST_STATE_INIT 0
71 
75 #define ID_REST_STATE_POST_INIT 1
76 
80 #define OIDC_GRANT_TYPE_KEY "grant_type"
81 
85 #define OIDC_GRANT_TYPE_VALUE "authorization_code"
86 
90 #define OIDC_CODE_KEY "code"
91 
95 #define OIDC_RESPONSE_TYPE_KEY "response_type"
96 
100 #define OIDC_CLIENT_ID_KEY "client_id"
101 
105 #define OIDC_SCOPE_KEY "scope"
106 
110 #define OIDC_REDIRECT_URI_KEY "redirect_uri"
111 
115 #define OIDC_STATE_KEY "state"
116 
120 #define OIDC_NONCE_KEY "nonce"
121 
125 #define OIDC_CODE_CHALLENGE_KEY "code_challenge"
126 
130 #define OIDC_CODE_VERIFIER_KEY "code_verifier"
131 
135 #define OIDC_COOKIE_EXPIRATION 3
136 
140 #define OIDC_COOKIE_HEADER_KEY "cookie"
141 
145 #define OIDC_AUTHORIZATION_HEADER_KEY "authorization"
146 
150 #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
151 
155 #define OIDC_COOKIE_HEADER_ACCESS_DENIED "Identity=Denied"
156 
160 #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
161 
165 #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
166 
170 #define OIDC_ERROR_KEY_INVALID_CLIENT "invalid_client"
171 
175 #define OIDC_ERROR_KEY_INVALID_SCOPE "invalid_scope"
176 
180 #define OIDC_ERROR_KEY_INVALID_REQUEST "invalid_request"
181 
185 #define OIDC_ERROR_KEY_INVALID_TOKEN "invalid_token"
186 
190 #define OIDC_ERROR_KEY_INVALID_COOKIE "invalid_cookie"
191 
195 #define OIDC_ERROR_KEY_SERVER_ERROR "server_error"
196 
200 #define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE "unsupported_grant_type"
201 
205 #define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE "unsupported_response_type"
206 
210 #define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT "unauthorized_client"
211 
215 #define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied"
216 
217 
221 static char *OIDC_ignored_parameter_array[] = { "display",
222  "prompt",
223  "ui_locales",
224  "response_mode",
225  "id_token_hint",
226  "login_hint",
227  "acr_values" };
228 
233 
239 
244 
248 static char *allow_methods;
249 
253 struct Plugin
254 {
255  const struct GNUNET_CONFIGURATION_Handle *cfg;
256 };
257 
262 {
266  struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
267 
271  char *client_id;
272 
277 
281  char *scope;
282 
286  char *state;
287 
291  char *nonce;
292 
297 
302 
307 
312 
317 
321  json_t *response;
322 };
323 
327 struct EgoEntry
328 {
332  struct EgoEntry *next;
333 
337  struct EgoEntry *prev;
338 
342  char *identifier;
343 
347  char *keystring;
348 
352  struct GNUNET_IDENTITY_Ego *ego;
353 };
354 
355 
356 struct RequestHandle
357 {
361  struct EgoEntry *ego_head;
362 
366  struct EgoEntry *ego_tail;
367 
371  struct EgoEntry *ego_entry;
372 
377 
382 
386  int state;
387 
392 
396  struct GNUNET_REST_RequestHandle *rest_handle;
397 
402 
407 
412 
417 
422 
427 
432 
437 
442 
447 
452 
457 
462 
467 
471  void *proc_cls;
472 
476  char *url;
477 
481  char *tld;
482 
487 
492 
496  char *emsg;
497 
501  char *edesc;
502 
506  int response_code;
507 };
508 
513 static void
515 {
516  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry;
517  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
518  struct EgoEntry *ego_entry;
519  struct EgoEntry *ego_tmp;
520 
521  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
522  if (NULL != handle->timeout_task)
524  if (NULL != handle->identity_handle)
526  if (NULL != handle->attr_it)
528  if (NULL != handle->ticket_it)
530  if (NULL != handle->idp)
531  GNUNET_RECLAIM_disconnect (handle->idp);
532  GNUNET_free_non_null (handle->url);
533  GNUNET_free_non_null (handle->tld);
536  GNUNET_free_non_null (handle->emsg);
537  GNUNET_free_non_null (handle->edesc);
538  if (NULL != handle->gns_op)
540  if (NULL != handle->gns_handle)
542 
543  if (NULL != handle->namestore_handle)
545  if (NULL != handle->oidc)
546  {
549  GNUNET_free_non_null (handle->oidc->nonce);
552  GNUNET_free_non_null (handle->oidc->scope);
553  GNUNET_free_non_null (handle->oidc->state);
554  json_decref (handle->oidc->response);
555  GNUNET_free (handle->oidc);
556  }
557  if (NULL != handle->attr_list)
558  {
559  for (claim_entry = handle->attr_list->list_head; NULL != claim_entry;)
560  {
561  claim_tmp = claim_entry;
562  claim_entry = claim_entry->next;
563  GNUNET_free (claim_tmp->claim);
564  GNUNET_free (claim_tmp);
565  }
566  GNUNET_free (handle->attr_list);
567  }
568  for (ego_entry = handle->ego_head; NULL != ego_entry;)
569  {
570  ego_tmp = ego_entry;
571  ego_entry = ego_entry->next;
572  GNUNET_free (ego_tmp->identifier);
573  GNUNET_free (ego_tmp->keystring);
574  GNUNET_free (ego_tmp);
575  }
576  GNUNET_free (handle);
577 }
578 
579 static void
581 {
582  cleanup_handle (cls);
583 }
584 
585 
591 static void
592 do_error (void *cls)
593 {
594  struct RequestHandle *handle = cls;
595  struct MHD_Response *resp;
596  char *json_error;
597 
598  GNUNET_asprintf (&json_error,
599  "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
600  handle->emsg,
601  (NULL != handle->edesc) ? handle->edesc : "",
602  (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
603  (NULL != handle->oidc->state) ? handle->oidc->state : "",
604  (NULL != handle->oidc->state) ? "\"" : "");
605  if (0 == handle->response_code)
606  handle->response_code = MHD_HTTP_BAD_REQUEST;
607  resp = GNUNET_REST_create_response (json_error);
608  if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
609  MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Basic");
610  MHD_add_response_header (resp,
611  MHD_HTTP_HEADER_CONTENT_TYPE,
612  "application/json");
613  handle->proc (handle->proc_cls, resp, handle->response_code);
615  GNUNET_free (json_error);
616 }
617 
618 
625 static void
626 do_userinfo_error (void *cls)
627 {
628  struct RequestHandle *handle = cls;
629  struct MHD_Response *resp;
630  char *error;
631 
632  GNUNET_asprintf (&error,
633  "error=\"%s\", error_description=\"%s\"",
634  handle->emsg,
635  (NULL != handle->edesc) ? handle->edesc : "");
636  resp = GNUNET_REST_create_response ("");
637  MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Bearer");
638  handle->proc (handle->proc_cls, resp, handle->response_code);
640  GNUNET_free (error);
641 }
642 
643 
649 static void
650 do_redirect_error (void *cls)
651 {
652  struct RequestHandle *handle = cls;
653  struct MHD_Response *resp;
654  char *redirect;
655 
656  GNUNET_asprintf (&redirect,
657  "%s?error=%s&error_description=%s%s%s",
658  handle->oidc->redirect_uri,
659  handle->emsg,
660  handle->edesc,
661  (NULL != handle->oidc->state) ? "&state=" : "",
662  (NULL != handle->oidc->state) ? handle->oidc->state : "");
663  resp = GNUNET_REST_create_response ("");
664  MHD_add_response_header (resp, "Location", redirect);
665  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
667  GNUNET_free (redirect);
668 }
669 
675 static void
676 do_timeout (void *cls)
677 {
678  struct RequestHandle *handle = cls;
679 
680  handle->timeout_task = NULL;
681  do_error (handle);
682 }
683 
689 static void
691 {
692  char *result_str;
693  struct RequestHandle *handle = cls;
694  struct MHD_Response *resp;
695 
696  result_str = json_dumps (handle->oidc->response, 0);
697 
698  resp = GNUNET_REST_create_response (result_str);
699  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
700  GNUNET_free (result_str);
701  cleanup_handle (handle);
702 }
703 
704 
712 static void
714  const char *url,
715  void *cls)
716 {
717  struct MHD_Response *resp;
718  struct RequestHandle *handle = cls;
719 
720  // For now, independent of path return all options
721  resp = GNUNET_REST_create_response (NULL);
722  MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
723  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
724  cleanup_handle (handle);
725  return;
726 }
727 
728 
732 static void
734 {
735  struct GNUNET_HashCode cache_key;
736  char *cookies;
737  struct GNUNET_TIME_Absolute current_time, *relog_time;
738  char delimiter[] = "; ";
739  char *tmp_cookies;
740  char *token;
741  char *value;
742 
743  // gets identity of login try with cookie
745  strlen (OIDC_COOKIE_HEADER_KEY),
746  &cache_key);
749  &cache_key))
750  {
751  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cookie found\n");
752  return;
753  }
754  // splits cookies and find 'Identity' cookie
755  tmp_cookies =
757  &cache_key);
758  cookies = GNUNET_strdup (tmp_cookies);
759  token = strtok (cookies, delimiter);
760  handle->oidc->user_cancelled = GNUNET_NO;
761  handle->oidc->login_identity = NULL;
762  if (NULL == token)
763  {
765  "Unable to parse cookie: %s\n",
766  cookies);
767  GNUNET_free (cookies);
768  return;
769  }
770 
771  while (NULL != token)
772  {
773  if (0 == strcmp (token, OIDC_COOKIE_HEADER_ACCESS_DENIED))
774  {
775  handle->oidc->user_cancelled = GNUNET_YES;
776  GNUNET_free (cookies);
777  return;
778  }
779  if (NULL != strstr (token, OIDC_COOKIE_HEADER_INFORMATION_KEY))
780  break;
781  token = strtok (NULL, delimiter);
782  }
783  if (NULL == token)
784  {
786  "No cookie value to process: %s\n",
787  cookies);
788  GNUNET_free (cookies);
789  return;
790  }
791  GNUNET_CRYPTO_hash (token, strlen (token), &cache_key);
792  if (GNUNET_NO ==
793  GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
794  {
795  GNUNET_log (
797  "Found cookie `%s', but no corresponding expiration entry present...\n",
798  token);
799  GNUNET_free (cookies);
800  return;
801  }
802  relog_time =
803  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
804  current_time = GNUNET_TIME_absolute_get ();
805  // 30 min after old login -> redirect to login
806  if (current_time.abs_value_us > relog_time->abs_value_us)
807  {
809  "Found cookie `%s', but it is expired.\n",
810  token);
811  GNUNET_free (cookies);
812  return;
813  }
814  value = strtok (token, OIDC_COOKIE_HEADER_INFORMATION_KEY);
815  GNUNET_assert (NULL != value);
816  handle->oidc->login_identity = GNUNET_strdup (value);
817  GNUNET_free (cookies);
818 }
819 
823 static void
824 login_redirect (void *cls)
825 {
826  char *login_base_url;
827  char *new_redirect;
828  struct MHD_Response *resp;
829  struct RequestHandle *handle = cls;
830 
832  "reclaim-rest-plugin",
833  "address",
834  &login_base_url))
835  {
836  GNUNET_asprintf (&new_redirect,
837  "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
838  login_base_url,
840  handle->oidc->response_type,
842  handle->oidc->client_id,
844  handle->oidc->redirect_uri,
846  handle->oidc->scope,
848  (NULL != handle->oidc->state) ? handle->oidc->state : "",
850  (NULL != handle->oidc->code_challenge) ?
851  handle->oidc->code_challenge : "",
853  (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "");
854  resp = GNUNET_REST_create_response ("");
855  MHD_add_response_header (resp, "Location", new_redirect);
856  GNUNET_free (login_base_url);
857  }
858  else
859  {
861  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
862  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
864  return;
865  }
866  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
867  GNUNET_free (new_redirect);
869 }
870 
874 static void
876 {
877  struct RequestHandle *handle = cls;
878 
880  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
882 }
883 
884 
889 static void
891 {
892  struct RequestHandle *handle = cls;
893  struct MHD_Response *resp;
894  char *ticket_str;
895  char *redirect_uri;
896  char *code_string;
897 
898  handle->idp_op = NULL;
899  if (NULL == ticket)
900  {
902  handle->edesc = GNUNET_strdup ("Server cannot generate ticket.");
904  return;
905  }
906  handle->ticket = *ticket;
907  ticket_str =
909  sizeof(struct GNUNET_RECLAIM_Ticket));
910  // TODO change if more attributes are needed (see max_age)
911  code_string = OIDC_build_authz_code (&handle->priv_key,
912  &handle->ticket,
913  handle->attr_list,
914  handle->oidc->nonce,
915  handle->oidc->code_challenge);
916  if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
917  (NULL != handle->tld))
918  {
919  GNUNET_asprintf (&redirect_uri,
920  "%s.%s/%s?%s=%s&state=%s",
921  handle->redirect_prefix,
922  handle->tld,
923  handle->redirect_suffix,
924  handle->oidc->response_type,
925  code_string,
926  handle->oidc->state);
927  }
928  else
929  {
930  GNUNET_asprintf (&redirect_uri,
931  "%s?%s=%s&state=%s",
932  handle->oidc->redirect_uri,
933  handle->oidc->response_type,
934  code_string,
935  handle->oidc->state);
936  }
937  resp = GNUNET_REST_create_response ("");
938  MHD_add_response_header (resp, "Location", redirect_uri);
939  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
941  GNUNET_free (redirect_uri);
942  GNUNET_free (ticket_str);
943  GNUNET_free (code_string);
944 }
945 
946 static void
948 {
949  struct RequestHandle *handle = cls;
950 
951  handle->attr_it = NULL;
952  handle->ticket_it = NULL;
953  if (NULL == handle->attr_list->list_head)
954  {
956  handle->edesc = GNUNET_strdup ("The requested scope is not available.");
958  return;
959  }
960  handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp,
961  &handle->priv_key,
962  &handle->oidc->client_pkey,
963  handle->attr_list,
965  handle);
966 }
967 
968 
972 static void
973 oidc_attr_collect (void *cls,
975  const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
976 {
977  struct RequestHandle *handle = cls;
979  char *scope_variables;
980  char *scope_variable;
981  char delimiter[] = " ";
982 
983  if ((NULL == attr->name) || (NULL == attr->data))
984  {
986  return;
987  }
988 
989  scope_variables = GNUNET_strdup (handle->oidc->scope);
990  scope_variable = strtok (scope_variables, delimiter);
991  while (NULL != scope_variable)
992  {
993  if (0 == strcmp (attr->name, scope_variable))
994  break;
995  scope_variable = strtok (NULL, delimiter);
996  }
997  if (NULL == scope_variable)
998  {
1000  GNUNET_free (scope_variables);
1001  return;
1002  }
1003  GNUNET_free (scope_variables);
1004 
1007  attr->type,
1008  attr->data,
1009  attr->data_size);
1010  le->claim->id = attr->id;
1011  le->claim->version = attr->version;
1013  handle->attr_list->list_tail,
1014  le);
1016 }
1017 
1018 
1022 static void
1023 code_redirect (void *cls)
1024 {
1025  struct RequestHandle *handle = cls;
1026  struct GNUNET_TIME_Absolute current_time;
1027  struct GNUNET_TIME_Absolute *relog_time;
1028  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
1029  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pkey;
1030  struct GNUNET_HashCode cache_key;
1031  char *identity_cookie;
1032 
1033  GNUNET_asprintf (&identity_cookie,
1034  "Identity=%s",
1035  handle->oidc->login_identity);
1036  GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1037  GNUNET_free (identity_cookie);
1038  // No login time for identity -> redirect to login
1039  if (GNUNET_YES ==
1040  GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
1041  {
1042  relog_time =
1043  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
1044  current_time = GNUNET_TIME_absolute_get ();
1045  // 30 min after old login -> redirect to login
1046  if (current_time.abs_value_us <= relog_time->abs_value_us)
1047  {
1048  if (GNUNET_OK !=
1050  ->login_identity,
1051  strlen (
1052  handle->oidc
1053  ->login_identity),
1054  &pubkey))
1055  {
1057  handle->edesc =
1058  GNUNET_strdup ("The cookie of a login identity is not valid");
1060  return;
1061  }
1062  // iterate over egos and compare their public key
1063  for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
1064  handle->ego_entry = handle->ego_entry->next)
1065  {
1066  GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1067  if (0 == GNUNET_memcmp (&ego_pkey, &pubkey))
1068  {
1069  handle->priv_key =
1071  handle->idp = GNUNET_RECLAIM_connect (cfg);
1072  handle->attr_list =
1074  handle->attr_it =
1076  &handle->priv_key,
1078  handle,
1080  handle,
1082  handle);
1083  return;
1084  }
1085  }
1087  return;
1088  }
1089  }
1090 }
1091 
1092 
1093 static void
1094 build_redirect (void *cls)
1095 {
1096  struct RequestHandle *handle = cls;
1097  struct MHD_Response *resp;
1098  char *redirect_uri;
1099 
1100  if (GNUNET_YES == handle->oidc->user_cancelled)
1101  {
1102  if ((NULL != handle->redirect_prefix) &&
1103  (NULL != handle->redirect_suffix) && (NULL != handle->tld))
1104  {
1105  GNUNET_asprintf (&redirect_uri,
1106  "%s.%s/%s?error=%s&error_description=%s&state=%s",
1107  handle->redirect_prefix,
1108  handle->tld,
1109  handle->redirect_suffix,
1110  "access_denied",
1111  "User denied access",
1112  handle->oidc->state);
1113  }
1114  else
1115  {
1116  GNUNET_asprintf (&redirect_uri,
1117  "%s?error=%s&error_description=%s&state=%s",
1118  handle->oidc->redirect_uri,
1119  "access_denied",
1120  "User denied access",
1121  handle->oidc->state);
1122  }
1123  resp = GNUNET_REST_create_response ("");
1124  MHD_add_response_header (resp, "Location", redirect_uri);
1125  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1127  GNUNET_free (redirect_uri);
1128  return;
1129  }
1131 }
1132 
1133 
1134 static void
1136  uint32_t rd_count,
1137  const struct GNUNET_GNSRECORD_Data *rd)
1138 {
1139  struct RequestHandle *handle = cls;
1140  char *tmp;
1141  char *tmp_key_str;
1142  char *pos;
1143  struct GNUNET_CRYPTO_EcdsaPublicKey redirect_zone;
1144 
1145  handle->gns_op = NULL;
1146  if (0 == rd_count)
1147  {
1149  handle->edesc =
1150  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1152  return;
1153  }
1154  for (int i = 0; i < rd_count; i++)
1155  {
1156  if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type)
1157  continue;
1158  if (0 != strncmp (rd[i].data, handle->oidc->redirect_uri, rd[i].data_size))
1159  continue;
1160  tmp = GNUNET_strndup (rd[i].data, rd[i].data_size);
1161  if (NULL == strstr (tmp, handle->oidc->client_id))
1162  {
1164  "Redirect uri %s does not contain client_id %s\n",
1165  tmp,
1166  handle->oidc->client_id);
1167  }
1168  else
1169  {
1170  pos = strrchr (tmp, (unsigned char) '.');
1171  if (NULL == pos)
1172  {
1174  "Redirect uri %s contains client_id but is malformed\n",
1175  tmp);
1176  GNUNET_free (tmp);
1177  continue;
1178  }
1179  *pos = '\0';
1180  handle->redirect_prefix = GNUNET_strdup (tmp);
1181  tmp_key_str = pos + 1;
1182  pos = strchr (tmp_key_str, (unsigned char) '/');
1183  if (NULL == pos)
1184  {
1186  "Redirect uri %s contains client_id but is malformed\n",
1187  tmp);
1188  GNUNET_free (tmp);
1189  continue;
1190  }
1191  *pos = '\0';
1192  handle->redirect_suffix = GNUNET_strdup (pos + 1);
1193 
1194  GNUNET_STRINGS_string_to_data (tmp_key_str,
1195  strlen (tmp_key_str),
1196  &redirect_zone,
1197  sizeof(redirect_zone));
1198  }
1200  GNUNET_free (tmp);
1201  return;
1202  }
1204  handle->edesc =
1205  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1207 }
1208 
1209 
1213 static void
1214 client_redirect (void *cls)
1215 {
1216  struct RequestHandle *handle = cls;
1217 
1218  /* Lookup client redirect uri to verify request */
1219  handle->gns_op =
1220  GNUNET_GNS_lookup (handle->gns_handle,
1222  &handle->oidc->client_pkey,
1226  handle);
1227 }
1228 
1229 static char *
1230 get_url_parameter_copy (const struct RequestHandle *handle, const char *key)
1231 {
1232  struct GNUNET_HashCode hc;
1233  char *value;
1234 
1235  GNUNET_CRYPTO_hash (key, strlen (key), &hc);
1237  ->url_param_map,
1238  &hc))
1239  return NULL;
1240  value =
1242  if (NULL == value)
1243  return NULL;
1244  return GNUNET_strdup (value);
1245 }
1246 
1247 
1254 static void
1256 {
1257  struct RequestHandle *handle = cls;
1258  struct GNUNET_HashCode cache_key;
1259 
1260  char *expected_scope;
1261  char delimiter[] = " ";
1262  int number_of_ignored_parameter, iterator;
1263 
1264 
1265  // REQUIRED value: redirect_uri
1266  handle->oidc->redirect_uri =
1268  if (NULL == handle->oidc->redirect_uri)
1269  {
1271  handle->edesc = GNUNET_strdup ("missing parameter redirect_uri");
1273  return;
1274  }
1275 
1276  // REQUIRED value: response_type
1277  handle->oidc->response_type =
1279  if (NULL == handle->oidc->response_type)
1280  {
1282  handle->edesc = GNUNET_strdup ("missing parameter response_type");
1284  return;
1285  }
1286 
1287  // REQUIRED value: scope
1288  handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
1289  if (NULL == handle->oidc->scope)
1290  {
1292  handle->edesc = GNUNET_strdup ("missing parameter scope");
1294  return;
1295  }
1296 
1297  // OPTIONAL value: nonce
1298  handle->oidc->nonce = get_url_parameter_copy (handle, OIDC_NONCE_KEY);
1299 
1300  // TODO check other values if needed
1301  number_of_ignored_parameter =
1302  sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1303  for (iterator = 0; iterator < number_of_ignored_parameter; iterator++)
1304  {
1306  strlen (OIDC_ignored_parameter_array[iterator]),
1307  &cache_key);
1308  if (GNUNET_YES ==
1310  ->url_param_map,
1311  &cache_key))
1312  {
1314  GNUNET_asprintf (&handle->edesc,
1315  "Server will not handle parameter: %s",
1316  OIDC_ignored_parameter_array[iterator]);
1318  return;
1319  }
1320  }
1321 
1322  // We only support authorization code flows.
1323  if (0 != strcmp (handle->oidc->response_type,
1325  {
1327  handle->edesc = GNUNET_strdup ("The authorization server does not support "
1328  "obtaining this authorization code.");
1330  return;
1331  }
1332 
1333  // Checks if scope contains 'openid'
1334  expected_scope = GNUNET_strdup (handle->oidc->scope);
1335  char *test;
1336  test = strtok (expected_scope, delimiter);
1337  while (NULL != test)
1338  {
1339  if (0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope))
1340  break;
1341  test = strtok (NULL, delimiter);
1342  }
1343  if (NULL == test)
1344  {
1346  handle->edesc =
1347  GNUNET_strdup ("The requested scope is invalid, unknown, or malformed.");
1349  GNUNET_free (expected_scope);
1350  return;
1351  }
1352 
1353  GNUNET_free (expected_scope);
1354  if ((NULL == handle->oidc->login_identity) &&
1355  (GNUNET_NO == handle->oidc->user_cancelled))
1357  else
1359 }
1360 
1364 static void
1365 tld_iter (void *cls, const char *section, const char *option, const char *value)
1366 {
1367  struct RequestHandle *handle = cls;
1368  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1369 
1370  if (GNUNET_OK !=
1371  GNUNET_CRYPTO_ecdsa_public_key_from_string (value, strlen (value), &pkey))
1372  {
1373  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping non key %s\n", value);
1374  return;
1375  }
1376  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1377  handle->tld = GNUNET_strdup (option + 1);
1378 }
1379 
1387 static void
1389  const char *url,
1390  void *cls)
1391 {
1392  struct RequestHandle *handle = cls;
1393  struct EgoEntry *tmp_ego;
1394  const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1395  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1396 
1398 
1399  // RECOMMENDED value: state - REQUIRED for answers
1400  handle->oidc->state = get_url_parameter_copy (handle, OIDC_STATE_KEY);
1401 
1402  // REQUIRED value: client_id
1404  if (NULL == handle->oidc->client_id)
1405  {
1407  handle->edesc = GNUNET_strdup ("missing parameter client_id");
1408  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1410  return;
1411  }
1412 
1413  // OPTIONAL value: code_challenge
1414  handle->oidc->code_challenge = get_url_parameter_copy (handle,
1416  if (NULL == handle->oidc->code_challenge)
1417  {
1419  "OAuth authorization request does not contain PKCE parameters!\n");
1420  }
1421 
1422  if (GNUNET_OK !=
1424  strlen (
1425  handle->oidc->client_id),
1426  &handle->oidc->client_pkey))
1427  {
1429  handle->edesc = GNUNET_strdup ("The client is not authorized to request an "
1430  "authorization code using this method.");
1431  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1433  return;
1434  }
1435 
1436  // If we know this identity, translated the corresponding TLD
1437  // TODO: We might want to have a reverse lookup functionality for TLDs?
1438  for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
1439  {
1440  priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
1441  GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, &pkey);
1442  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1443  {
1444  handle->tld = GNUNET_strdup (tmp_ego->identifier);
1445  handle->ego_entry = handle->ego_tail;
1446  }
1447  }
1448  if (NULL == handle->tld)
1450  if (NULL == handle->tld)
1451  handle->tld = GNUNET_strdup (handle->oidc->client_id);
1453 }
1454 
1462 static void
1464  const char *url,
1465  void *cls)
1466 {
1467  struct MHD_Response *resp = GNUNET_REST_create_response ("");
1468  struct RequestHandle *handle = cls;
1469  struct GNUNET_HashCode cache_key;
1470  struct GNUNET_TIME_Absolute *current_time;
1471  struct GNUNET_TIME_Absolute *last_time;
1472  char *cookie;
1473  char *header_val;
1474  json_t *root;
1475  json_error_t error;
1476  json_t *identity;
1477  char term_data[handle->rest_handle->data_size + 1];
1478 
1479  term_data[handle->rest_handle->data_size] = '\0';
1480  GNUNET_memcpy (term_data,
1481  handle->rest_handle->data,
1482  handle->rest_handle->data_size);
1483  root = json_loads (term_data, JSON_DECODE_ANY, &error);
1484  identity = json_object_get (root, "identity");
1485  if (! json_is_string (identity))
1486  {
1488  "Error parsing json string from %s\n",
1489  term_data);
1490  handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1491  json_decref (root);
1493  return;
1494  }
1495  GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1496  GNUNET_asprintf (&header_val,
1497  "%s;Max-Age=%d",
1498  cookie,
1500  MHD_add_response_header (resp, "Set-Cookie", header_val);
1501  MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST");
1502  GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1503 
1504  if (0 != strcmp (json_string_value (identity), "Denied"))
1505  {
1506  current_time = GNUNET_new (struct GNUNET_TIME_Absolute);
1507  *current_time = GNUNET_TIME_relative_to_absolute (
1510  last_time =
1511  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
1512  GNUNET_free_non_null (last_time);
1513  GNUNET_CONTAINER_multihashmap_put (OIDC_cookie_jar_map,
1514  &cache_key,
1515  current_time,
1517  }
1518  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1519  GNUNET_free (cookie);
1520  GNUNET_free (header_val);
1521  json_decref (root);
1523 }
1524 
1525 static int
1527  struct GNUNET_CRYPTO_EcdsaPublicKey *cid)
1528 {
1529  struct GNUNET_HashCode cache_key;
1530  char *authorization;
1531  char *credentials;
1532  char *basic_authorization;
1533  char *client_id;
1534  char *pass;
1535  char *expected_pass;
1536 
1539  &cache_key);
1541  ->header_param_map,
1542  &cache_key))
1543  {
1545  handle->edesc = GNUNET_strdup ("missing authorization");
1546  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1547  return GNUNET_SYSERR;
1548  }
1549  authorization =
1551  &cache_key);
1552 
1553  // split header in "Basic" and [content]
1554  credentials = strtok (authorization, " ");
1555  if ((NULL == credentials) || (0 != strcmp ("Basic", credentials)))
1556  {
1558  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1559  return GNUNET_SYSERR;
1560  }
1561  credentials = strtok (NULL, " ");
1562  if (NULL == credentials)
1563  {
1565  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1566  return GNUNET_SYSERR;
1567  }
1568  GNUNET_STRINGS_base64_decode (credentials,
1569  strlen (credentials),
1570  (void **) &basic_authorization);
1571 
1572  if (NULL == basic_authorization)
1573  {
1575  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1576  return GNUNET_SYSERR;
1577  }
1578  client_id = strtok (basic_authorization, ":");
1579  if (NULL == client_id)
1580  {
1581  GNUNET_free_non_null (basic_authorization);
1583  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1584  return GNUNET_SYSERR;
1585  }
1586  pass = strtok (NULL, ":");
1587  if (NULL == pass)
1588  {
1589  GNUNET_free_non_null (basic_authorization);
1591  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1592  return GNUNET_SYSERR;
1593  }
1594 
1595  // check client password
1597  "reclaim-rest-plugin",
1598  "OIDC_CLIENT_SECRET",
1599  &expected_pass))
1600  {
1601  if (0 != strcmp (expected_pass, pass))
1602  {
1603  GNUNET_free_non_null (basic_authorization);
1604  GNUNET_free (expected_pass);
1606  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1607  return GNUNET_SYSERR;
1608  }
1609  GNUNET_free (expected_pass);
1610  }
1611  else
1612  {
1613  GNUNET_free_non_null (basic_authorization);
1615  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1616  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1617  return GNUNET_SYSERR;
1618  }
1619 
1620  // check client_id
1621  for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
1622  handle->ego_entry = handle->ego_entry->next)
1623  {
1624  if (0 == strcmp (handle->ego_entry->keystring, client_id))
1625  break;
1626  }
1627  if (NULL == handle->ego_entry)
1628  {
1629  GNUNET_free_non_null (basic_authorization);
1631  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1632  return GNUNET_SYSERR;
1633  }
1634  GNUNET_STRINGS_string_to_data (client_id,
1635  strlen (client_id),
1636  cid,
1637  sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
1638 
1639  GNUNET_free (basic_authorization);
1640  return GNUNET_OK;
1641 }
1642 
1643 const struct EgoEntry *
1645  struct GNUNET_CRYPTO_EcdsaPublicKey *test_key)
1646 {
1647  struct EgoEntry *ego_entry;
1648  struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1649 
1650  for (ego_entry = handle->ego_head; NULL != ego_entry;
1651  ego_entry = ego_entry->next)
1652  {
1653  GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
1654  if (0 == GNUNET_memcmp (&pub_key, test_key))
1655  return ego_entry;
1656  }
1657  return NULL;
1658 }
1659 
1660 static void
1662  const char *access_token,
1663  const struct GNUNET_RECLAIM_Ticket *ticket)
1664 {
1665  struct GNUNET_HashCode hc;
1666  struct GNUNET_RECLAIM_Ticket *ticketbuf;
1667 
1668  GNUNET_CRYPTO_hash (access_token, strlen (access_token), &hc);
1669  ticketbuf = GNUNET_new (struct GNUNET_RECLAIM_Ticket);
1670  *ticketbuf = *ticket;
1673  OIDC_access_token_map,
1674  &hc,
1675  ticketbuf,
1677 }
1678 
1686 static void
1688  const char *url,
1689  void *cls)
1690 {
1691  struct RequestHandle *handle = cls;
1692  const struct EgoEntry *ego_entry;
1693  struct GNUNET_TIME_Relative expiration_time;
1695  struct GNUNET_RECLAIM_Ticket ticket;
1696  struct GNUNET_CRYPTO_EcdsaPublicKey cid;
1697  const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
1698  struct GNUNET_HashCode cache_key;
1699  struct MHD_Response *resp;
1700  char *grant_type;
1701  char *code;
1702  char *json_response;
1703  char *id_token;
1704  char *access_token;
1705  char *jwt_secret;
1706  char *nonce;
1707  char *code_verifier;
1708 
1709  /*
1710  * Check Authorization
1711  */
1712  if (GNUNET_SYSERR == check_authorization (handle, &cid))
1713  {
1715  "OIDC authorization for token endpoint failed\n");
1717  return;
1718  }
1719 
1720  /*
1721  * Check parameter
1722  */
1723 
1724  // TODO Do not allow multiple equal parameter names
1725  // REQUIRED grant_type
1727  strlen (OIDC_GRANT_TYPE_KEY),
1728  &cache_key);
1729  grant_type = get_url_parameter_copy (handle, OIDC_GRANT_TYPE_KEY);
1730  if (NULL == grant_type)
1731  {
1733  handle->edesc = GNUNET_strdup ("missing parameter grant_type");
1734  handle->response_code = MHD_HTTP_BAD_REQUEST;
1736  return;
1737  }
1738 
1739  // Check parameter grant_type == "authorization_code"
1740  if (0 != strcmp (OIDC_GRANT_TYPE_VALUE, grant_type))
1741  {
1743  handle->response_code = MHD_HTTP_BAD_REQUEST;
1744  GNUNET_free (grant_type);
1746  return;
1747  }
1748  GNUNET_free (grant_type);
1749  // REQUIRED code
1750  code = get_url_parameter_copy (handle, OIDC_CODE_KEY);
1751  if (NULL == code)
1752  {
1754  handle->edesc = GNUNET_strdup ("missing parameter code");
1755  handle->response_code = MHD_HTTP_BAD_REQUEST;
1757  return;
1758  }
1759  ego_entry = find_ego (handle, &cid);
1760  if (NULL == ego_entry)
1761  {
1763  handle->edesc = GNUNET_strdup ("Unknown client");
1764  handle->response_code = MHD_HTTP_BAD_REQUEST;
1765  GNUNET_free (code);
1767  return;
1768  }
1769  privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1770 
1771  // REQUIRED code verifier
1772  code_verifier = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY);
1773  if (NULL == code_verifier)
1774  {
1776  "OAuth authorization request does not contain PKCE parameters!\n");
1777 
1778  }
1779 
1780  // decode code
1781  if (GNUNET_OK != OIDC_parse_authz_code (privkey, code, code_verifier, &ticket,
1782  &cl, &nonce))
1783  {
1785  handle->edesc = GNUNET_strdup ("invalid code");
1786  handle->response_code = MHD_HTTP_BAD_REQUEST;
1787  GNUNET_free (code);
1789  return;
1790  }
1791  GNUNET_free (code);
1792 
1793  // create jwt
1795  "reclaim-rest-plugin",
1796  "expiration_time",
1797  &expiration_time))
1798  {
1800  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1801  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1803  return;
1804  }
1805 
1806 
1807  // TODO OPTIONAL acr,amr,azp
1809  "reclaim-rest-plugin",
1810  "jwt_secret",
1811  &jwt_secret))
1812  {
1814  handle->edesc = GNUNET_strdup ("No signing secret configured!");
1815  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1817  return;
1818  }
1819  id_token = OIDC_id_token_new (&ticket.audience,
1820  &ticket.identity,
1821  cl,
1822  &expiration_time,
1823  (NULL != nonce) ? nonce : NULL,
1824  jwt_secret);
1825  access_token = OIDC_access_token_new ();
1826  OIDC_build_token_response (access_token,
1827  id_token,
1828  &expiration_time,
1829  &json_response);
1830 
1831  persist_access_token (handle, access_token, &ticket);
1832  resp = GNUNET_REST_create_response (json_response);
1833  MHD_add_response_header (resp, "Cache-Control", "no-store");
1834  MHD_add_response_header (resp, "Pragma", "no-cache");
1835  MHD_add_response_header (resp, "Content-Type", "application/json");
1836  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1838  GNUNET_free (access_token);
1839  GNUNET_free (json_response);
1840  GNUNET_free (id_token);
1842 }
1843 
1847 static void
1848 consume_ticket (void *cls,
1849  const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1850  const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
1851 {
1852  struct RequestHandle *handle = cls;
1853  char *tmp_value;
1854  json_t *value;
1855 
1856  if (NULL == identity)
1857  {
1859  return;
1860  }
1862  attr->data,
1863  attr->data_size);
1864  value = json_string (tmp_value);
1865  json_object_set_new (handle->oidc->response, attr->name, value);
1866  GNUNET_free (tmp_value);
1867 }
1868 
1876 static void
1878  const char *url,
1879  void *cls)
1880 {
1881  // TODO expiration time
1882  struct RequestHandle *handle = cls;
1883  char delimiter[] = " ";
1884  struct GNUNET_HashCode cache_key;
1885  char *authorization;
1886  char *authorization_type;
1887  char *authorization_access_token;
1888  struct GNUNET_RECLAIM_Ticket *ticket;
1889  const struct EgoEntry *ego_entry;
1890  const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
1891 
1894  &cache_key);
1896  ->header_param_map,
1897  &cache_key))
1898  {
1900  handle->edesc = GNUNET_strdup ("No Access Token");
1901  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1903  return;
1904  }
1905  authorization =
1907  &cache_key);
1908 
1909  // split header in "Bearer" and access_token
1910  authorization = GNUNET_strdup (authorization);
1911  authorization_type = strtok (authorization, delimiter);
1912  if ((NULL == authorization_type) ||
1913  (0 != strcmp ("Bearer", authorization_type)))
1914  {
1916  handle->edesc = GNUNET_strdup ("No Access Token");
1917  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1919  GNUNET_free (authorization);
1920  return;
1921  }
1922  authorization_access_token = strtok (NULL, delimiter);
1923  if (NULL == authorization_access_token)
1924  {
1926  handle->edesc = GNUNET_strdup ("Access token missing");
1927  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1929  GNUNET_free (authorization);
1930  return;
1931  }
1932 
1933  GNUNET_CRYPTO_hash (authorization_access_token,
1934  strlen (authorization_access_token),
1935  &cache_key);
1936  if (GNUNET_NO ==
1937  GNUNET_CONTAINER_multihashmap_contains (OIDC_access_token_map,
1938  &cache_key))
1939  {
1941  handle->edesc = GNUNET_strdup ("The access token expired");
1942  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1944  GNUNET_free (authorization);
1945  return;
1946  }
1947  ticket =
1948  GNUNET_CONTAINER_multihashmap_get (OIDC_access_token_map, &cache_key);
1949  GNUNET_assert (NULL != ticket);
1950  ego_entry = find_ego (handle, &ticket->audience);
1951  if (NULL == ego_entry)
1952  {
1954  handle->edesc = GNUNET_strdup ("The access token expired");
1955  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1957  GNUNET_free (authorization);
1958  return;
1959  }
1960 
1961  handle->idp = GNUNET_RECLAIM_connect (cfg);
1962  handle->oidc->response = json_object ();
1963  json_object_set_new (handle->oidc->response,
1964  "sub",
1965  json_string (ego_entry->keystring));
1966  privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1967  handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
1968  privkey,
1969  ticket,
1971  handle);
1972  GNUNET_free (authorization);
1973 }
1974 
1975 
1981 static void
1983 {
1985  static const struct GNUNET_REST_RequestHandler handlers[] =
1986  { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint },
1987  { MHD_HTTP_METHOD_POST,
1989  &authorize_endpoint }, // url-encoded
1990  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont },
1991  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
1992  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
1993  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
1994  { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, &options_cont },
1996 
1997  if (GNUNET_NO ==
1998  GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1999  {
2000  handle->response_code = err.error_code;
2002  }
2003 }
2004 
2038 static void
2039 list_ego (void *cls,
2040  struct GNUNET_IDENTITY_Ego *ego,
2041  void **ctx,
2042  const char *identifier)
2043 {
2044  struct RequestHandle *handle = cls;
2045  struct EgoEntry *ego_entry;
2046  struct GNUNET_CRYPTO_EcdsaPublicKey pk;
2047 
2048  if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
2049  {
2050  handle->state = ID_REST_STATE_POST_INIT;
2051  init_cont (handle);
2052  return;
2053  }
2054  GNUNET_assert (NULL != ego);
2055  if (ID_REST_STATE_INIT == handle->state)
2056 
2057  {
2058  ego_entry = GNUNET_new (struct EgoEntry);
2061  ego_entry->ego = ego;
2062  ego_entry->identifier = GNUNET_strdup (identifier);
2064  handle->ego_tail,
2065  ego_entry);
2066  return;
2067  }
2068  /* Ego renamed or added */
2069  if (identifier != NULL)
2070  {
2071  for (ego_entry = handle->ego_head; NULL != ego_entry;
2072  ego_entry = ego_entry->next)
2073  {
2074  if (ego_entry->ego == ego)
2075  {
2076  /* Rename */
2077  GNUNET_free (ego_entry->identifier);
2078  ego_entry->identifier = GNUNET_strdup (identifier);
2079  break;
2080  }
2081  }
2082  if (NULL == ego_entry)
2083  {
2084  /* Add */
2085  ego_entry = GNUNET_new (struct EgoEntry);
2088  ego_entry->ego = ego;
2089  ego_entry->identifier = GNUNET_strdup (identifier);
2091  handle->ego_tail,
2092  ego_entry);
2093  }
2094  }
2095  else
2096  {
2097  /* Delete */
2098  for (ego_entry = handle->ego_head; NULL != ego_entry;
2099  ego_entry = ego_entry->next)
2100  {
2101  if (ego_entry->ego == ego)
2102  break;
2103  }
2104  if (NULL != ego_entry)
2106  handle->ego_tail,
2107  ego_entry);
2108  }
2109 }
2110 
2111 static void
2114  void *proc_cls)
2115 {
2116  struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
2117 
2118  handle->oidc = GNUNET_new (struct OIDC_Variables);
2119  if (NULL == OIDC_cookie_jar_map)
2120  OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2121  if (NULL == OIDC_access_token_map)
2122  OIDC_access_token_map =
2124  handle->response_code = 0;
2126  handle->proc_cls = proc_cls;
2127  handle->proc = proc;
2128  handle->state = ID_REST_STATE_INIT;
2129  handle->rest_handle = rest_handle;
2130 
2131  handle->url = GNUNET_strdup (rest_handle->url);
2132  if (handle->url[strlen (handle->url) - 1] == '/')
2133  handle->url[strlen (handle->url) - 1] = '\0';
2134  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
2135  handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
2136  handle->gns_handle = GNUNET_GNS_connect (cfg);
2138  handle->timeout_task =
2139  GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
2140  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
2141 }
2142 
2149 void *
2151 {
2152  static struct Plugin plugin;
2153  struct GNUNET_REST_Plugin *api;
2154 
2155  cfg = cls;
2156  if (NULL != plugin.cfg)
2157  return NULL; /* can only initialize once! */
2158  memset (&plugin, 0, sizeof(struct Plugin));
2159  plugin.cfg = cfg;
2160  api = GNUNET_new (struct GNUNET_REST_Plugin);
2161  api->cls = &plugin;
2165  "%s, %s, %s, %s, %s",
2166  MHD_HTTP_METHOD_GET,
2167  MHD_HTTP_METHOD_POST,
2168  MHD_HTTP_METHOD_PUT,
2169  MHD_HTTP_METHOD_DELETE,
2170  MHD_HTTP_METHOD_OPTIONS);
2171 
2173  _ ("OpenID Connect REST API initialized\n"));
2174  return api;
2175 }
2176 
2177 
2184 void *
2186 {
2187  struct GNUNET_REST_Plugin *api = cls;
2188  struct Plugin *plugin = api->cls;
2189 
2190  plugin->cfg = NULL;
2191 
2192  struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2193  void *value = NULL;
2194  hashmap_it =
2195  GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_cookie_jar_map);
2196  while (GNUNET_YES ==
2197  GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2198  GNUNET_free_non_null (value);
2200  GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map);
2201 
2202  hashmap_it =
2203  GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_access_token_map);
2204  while (GNUNET_YES ==
2205  GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2206  GNUNET_free_non_null (value);
2207  GNUNET_CONTAINER_multihashmap_destroy (OIDC_access_token_map);
2210  GNUNET_free (api);
2212  "OpenID Connect REST plugin is finished\n");
2213  return NULL;
2214 }
2215 
2216 /* 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:525
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static void build_redirect(void *cls)
static int iterator(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Iterator over hash map entries.
const char * name
The name of the attribute.
struct GNUNET_RECLAIM_ATTRIBUTE_Claim * claim
The attribute claim.
Connection to the GNS service.
Definition: gns_api.h:35
void GNUNET_CONTAINER_multihashmap_iterator_destroy(struct GNUNET_CONTAINER_MultiHashMapIterator *iter)
Destroy a multihashmap iterator.
char * GNUNET_RECLAIM_ATTRIBUTE_value_to_string(uint32_t type, const void *data, size_t data_size)
Convert the &#39;claim&#39; of an attribute to a string.
char * redirect_uri
The OIDC redirect uri.
char * scope
The list of oidc scopes.
Handle to the service.
Definition: reclaim_api.c:232
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:948
int GNUNET_CONFIGURATION_get_value_time(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, struct GNUNET_TIME_Relative *time)
Get a configuration value that should be a relative time.
struct EgoEntry * ego_tail
Ego list.
void GNUNET_CONFIGURATION_iterate_section_values(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, GNUNET_CONFIGURATION_Iterator iter, void *iter_cls)
Iterate over values of a section in the configuration.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
If a value with the given key exists, replace it.
char * nonce
The OIDC nonce.
size_t data_size
Number of bytes in data.
#define GNUNET_GNS_EMPTY_LABEL_AT
String we use to indicate an empty label (top-level entry in the zone).
#define OIDC_GRANT_TYPE_KEY
OIDC grant_type key.
#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE
OIDC expected response_type while authorizing.
struct GNUNET_CONTAINER_MultiHashMapIterator * GNUNET_CONTAINER_multihashmap_iterator_create(const struct GNUNET_CONTAINER_MultiHashMap *map)
Create an iterator for a multihashmap.
void * cls
The closure of the plugin.
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry * list_tail
List tail.
size_t data_size
The POST data size.
struct GNUNET_RECLAIM_AttributeIterator * attr_it
Attribute iterator.
static void cookie_identity_interpretation(struct RequestHandle *handle)
Interprets cookie header and pass its identity keystring to handle.
static void persist_access_token(const struct RequestHandle *handle, const char *access_token, const struct GNUNET_RECLAIM_Ticket *ticket)
#define OIDC_CODE_KEY
OIDC code key.
GNUNET_REST_ResultProcessor proc
The plugin result processor.
#define OIDC_ERROR_KEY_SERVER_ERROR
OIDC error key for generic server errors.
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition: time.c:246
#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.
char * key
TLS key.
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Handle to a lookup request.
Definition: gns_api.c:42
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:553
void GNUNET_RECLAIM_disconnect(struct GNUNET_RECLAIM_Handle *h)
Disconnect from identity provider service.
Definition: reclaim_api.c:814
#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.
helper library for OIDC related functions
#define GNUNET_NO
Definition: gnunet_common.h:78
#define OIDC_COOKIE_HEADER_INFORMATION_KEY
OIDC cookie header information key.
void GNUNET_RECLAIM_ticket_iteration_stop(struct GNUNET_RECLAIM_TicketIterator *it)
Stops iteration and releases the handle for further calls.
Definition: reclaim_api.c:1203
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
size_t data_size
Number of bytes in data.
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
static void tld_iter(void *cls, const char *section, const char *option, const char *value)
Iterate over tlds in config.
#define OIDC_COOKIE_HEADER_ACCESS_DENIED
OIDC cookie header if user cancelled.
int user_cancelled
User cancelled authorization/login.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
static void rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Private ECC key encoded for transmission.
void GNUNET_RECLAIM_get_attributes_next(struct GNUNET_RECLAIM_AttributeIterator *it)
Calls the record processor specified in GNUNET_RECLAIM_get_attributes_start for the next record...
Definition: reclaim_api.c:994
#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:733
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
static void login_redirect(void *cls)
Redirects to login page stored in configuration file.
void * proc_cls
The closure of the result processor.
uint64_t abs_value_us
The actual value.
char * edesc
Error response description.
struct OIDC_Variables * oidc
OIDC variables.
Internal representation of the hash map.
Handle for an operation with the identity service.
Definition: identity_api.c:39
#define GNUNET_REST_HANDLER_END
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:46
#define OIDC_STATE_KEY
OIDC state key.
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:181
static char * section
Name of the section.
Definition: gnunet-config.c:33
const void * data
Binary value stored as attribute value.
#define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE
OIDC error key for unsupported grants.
The ego list.
char * response_type
The OIDC response type.
#define OIDC_RESPONSE_TYPE_KEY
OIDC response_type key.
static struct GNUNET_RECLAIM_Ticket ticket
Ticket to consume.
struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey
The RP client public key.
struct GNUNET_IDENTITY_Ego * ego
The Ego.
void GNUNET_NAMESTORE_disconnect(struct GNUNET_NAMESTORE_Handle *h)
Disconnect from the namestore service (and free associated resources).
OIDC needed variables.
static struct GNUNET_ATS_SolverFunctions * plugin
Our solver.
void GNUNET_RECLAIM_ATTRIBUTE_list_destroy(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
Destroy claim list.
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
Handle for a zone iterator operation.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1237
Handle for an ego.
Definition: identity.h:237
Handle for a attribute iterator operation.
Definition: reclaim_api.c:165
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
User defined timestamp for completing operations.
Definition: gnunet-arm.c:114
static char * value
Value of the record to add/remove.
char * emsg
Error response message.
struct GNUNET_CONTAINER_MultiHashMap * url_param_map
Map of url parameters.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:44
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:94
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1264
char * name
Plugin name.
void GNUNET_GNS_disconnect(struct GNUNET_GNS_Handle *handle)
Shutdown connection with the GNS service.
Definition: gns_api.c:282
#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
Timeout.
static void lookup_redirect_uri_result(void *cls, uint32_t rd_count, const struct GNUNET_GNSRECORD_Data *rd)
struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_ticket_issue(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss, const struct GNUNET_CRYPTO_EcdsaPublicKey *rp, const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, GNUNET_RECLAIM_TicketCallback cb, void *cb_cls)
Issues a ticket to a relying party.
Definition: reclaim_api.c:1046
struct GNUNET_RECLAIM_TicketIterator * ticket_it
Ticket iterator.
char * tld
The tld for redirect.
static char * get_url_parameter_copy(const struct RequestHandle *handle, const char *key)
static char * option
Name of the option.
Definition: gnunet-config.c:38
static struct GNUNET_IDENTITY_Handle * identity_handle
Identity handle.
#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:440
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
void GNUNET_IDENTITY_disconnect(struct GNUNET_IDENTITY_Handle *h)
Disconnect from identity service.
Definition: identity_api.c:835
struct GNUNET_GNS_Handle * GNUNET_GNS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Initialize the connection with the GNS service.
Definition: gns_api.c:260
#define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE
OIDC error key for unsupported response types.
#define OIDC_CODE_VERIFIER_KEY
OIDC PKCE code verifier.
static void init_cont(struct RequestHandle *handle)
Handle rest request.
int GNUNET_REST_handle_request(struct GNUNET_REST_RequestHandle *conn, const struct GNUNET_REST_RequestHandler *handlers, struct GNUNET_REST_RequestHandlerError *err, void *cls)
Definition: rest.c:75
static void cleanup_handle(struct RequestHandle *handle)
Cleanup lookup handle.
struct GNUNET_REST_RequestHandle * rest_handle
Handle to rest request.
A 512-bit hashcode.
int response_code
HTTP response code.
int state
The processing state.
static void login_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Combines an identity with a login time and responds OK to login request.
static void code_redirect(void *cls)
Checks time and cookie and redirects accordingly.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:118
size_t GNUNET_STRINGS_base64_decode(const char *data, size_t len, void **output)
Decode from Base64.
Definition: strings.c:1920
char * GNUNET_CRYPTO_ecdsa_public_key_to_string(const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
Convert a public key to a string.
Definition: crypto_ecc.c:334
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.
struct GNUNET_CRYPTO_EcdsaPublicKey identity
The ticket issuer (= the user)
char * keystring
Public key string.
struct GNUNET_RECLAIM_Handle * idp
Identity Provider.
static struct GNUNET_IDENTITY_Handle * identity
Which namespace do we publish to? NULL if we do not publish to a namespace.
struct GNUNET_CONTAINER_MultiHashMap * OIDC_access_token_map
Hash map that links the issued access token to the corresponding ticket and ego.
There must only be one value per key; storing a value should fail if a value under the same key alrea...
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList * attr_list
Attribute claim list.
static void return_userinfo_response(void *cls)
Return attributes for claim.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
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:241
#define OIDC_ERROR_KEY_ACCESS_DENIED
OIDC error key for denied access.
static void userinfo_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Responds to userinfo GET and url-encoded POST request.
struct GNUNET_NAMESTORE_Handle * GNUNET_NAMESTORE_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Connect to the namestore service.
#define OIDC_AUTHORIZATION_HEADER_KEY
OIDC cookie header information key.
static void oidc_attr_collect(void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
Collects all attributes for an ego if in scope parameter.
int OIDC_parse_authz_code(const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv, const char *code, const char *code_verifier, struct GNUNET_RECLAIM_Ticket *ticket, struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList **attrs, char **nonce_str)
Parse reclaim ticket and nonce from authorization code.
Definition: oidc_helper.c:590
#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:119
static char * OIDC_ignored_parameter_array[]
OIDC ignored parameter array.
static struct Ego * ego_head
Head of DLL of all egos.
static int check_authorization(struct RequestHandle *handle, struct GNUNET_CRYPTO_EcdsaPublicKey *cid)
static void build_authz_response(void *cls)
Iteration over all results finished, build final response.
static void consume_ticket(void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
Collects claims and stores them in handle.
char * state
The OIDC state.
int GNUNET_CONTAINER_multihashmap_put(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
void GNUNET_IDENTITY_ego_get_public_key(const struct GNUNET_IDENTITY_Ego *ego, struct GNUNET_CRYPTO_EcdsaPublicKey *pk)
Get the identifier (public key) of an ego.
Definition: identity_api.c:566
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
#define GNUNET_REST_API_NS_OIDC
REST root namespace.
static void client_redirect(void *cls)
Initiate redirect back to client.
static void authorize_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Responds to authorization GET and url-encoded POST request.
char * identifier
Ego Identifier.
static void do_error(void *cls)
Task run on error, sends error message.
#define GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT
Record type for reclaim OIDC redirect URIs.
#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:760
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:468
struct GNUNET_GNS_Handle * gns_handle
GNS handle.
configuration data
Definition: configuration.c:83
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:1015
struct GNUNET_RECLAIM_ATTRIBUTE_Claim * GNUNET_RECLAIM_ATTRIBUTE_claim_new(const char *attr_name, uint32_t type, const void *data, size_t data_size)
Create a new attribute claim.
struct GNUNET_CRYPTO_EcdsaPublicKey audience
The ticket audience (= relying party)
struct GNUNET_SCHEDULER_Task * timeout_task
ID of a task associated with the resolution process.
static void list_ego(void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, const char *identifier)
If listing is enabled, prints information about the egos.
static void token_endpoint(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Responds to token url-encoded POST request.
char * redirect_suffix
The redirect suffix.
#define OIDC_ERROR_KEY_INVALID_CLIENT
OIDC error key for invalid client.
struct MHD_Response * GNUNET_REST_create_response(const char *data)
Create REST MHD response.
Definition: rest.c:56
Public ECC key (always for Curve25519) encoded in a format suitable for network transmission and ECDS...
A list of GNUNET_RECLAIM_ATTRIBUTE_Claim structures.
Handle for a ticket iterator operation.
Definition: reclaim_api.c:103
#define GNUNET_log(kind,...)
const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration handle.
Entry in list of pending tasks.
Definition: scheduler.c:131
#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:306
#define OIDC_GRANT_TYPE_VALUE
OIDC grant_type key.
#define ID_REST_STATE_INIT
State while collecting all egos.
struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
struct GNUNET_NAMESTORE_ZoneIterator * namestore_handle_it
Iterator for NAMESTORE.
#define OIDC_CLIENT_ID_KEY
OIDC client_id key.
char * code_verifier
The PKCE code_verifier.
struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_ticket_consume(struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, const struct GNUNET_RECLAIM_Ticket *ticket, GNUNET_RECLAIM_AttributeResult cb, void *cb_cls)
Consumes an issued ticket.
Definition: reclaim_api.c:1095
Time for absolute times used by GNUnet, in microseconds.
json_t * response
The response JSON.
#define GNUNET_YES
Definition: gnunet_common.h:77
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:921
static void oidc_collect_finished_cb(void *cls)
void * libgnunet_plugin_rest_openid_connect_done(void *cls)
Exit point from the plugin.
static struct Ego * ego_tail
Tail of DLL of all egos.
static struct GNUNET_ARM_Operation * op
Current operation.
Definition: gnunet-arm.c:139
char * OIDC_build_authz_code(const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, const struct GNUNET_RECLAIM_Ticket *ticket, struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, const char *nonce_str, const char *code_challenge)
Builds an OIDC authorization code including a reclaim ticket and nonce.
Definition: oidc_helper.c:455
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:334
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:774
uint32_t data
The data value.
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry * next
DLL.
static size_t data_size
Number of bytes in data.
#define OIDC_COOKIE_HEADER_KEY
OIDC cookie header key.
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry * list_head
List head.
char * OIDC_id_token_new(const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, const struct GNUNET_TIME_Relative *expiration_time, const char *nonce, const char *secret_key)
Create a JWT from attributes.
Definition: oidc_helper.c:116
struct EgoEntry * next
DLL.
#define GNUNET_REST_API_NS_USERINFO
UserInfo endpoint.
int GNUNET_STRINGS_string_to_data(const char *enc, size_t enclen, void *out, size_t out_size)
Convert CrockfordBase32 encoding back to data.
Definition: strings.c:953
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.
#define OIDC_ERROR_KEY_INVALID_SCOPE
OIDC error key for invalid scopes.
#define GNUNET_REST_API_NS_TOKEN
Token endpoint.
struct GNUNET_NAMESTORE_Handle * namestore_handle
Handle to NAMESTORE.
char * login_identity
The identity chosen by the user to login.
struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key
Pointer to ego private key.
static void do_userinfo_error(void *cls)
Task run on error in userinfo endpoint, sends error header.
static void do_redirect_error(void *cls)
Task run on error, sends error message and redirects.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:956
char * url
The url.