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"
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 
580 static void
582 {
583  cleanup_handle (cls);
584 }
585 
586 
592 static void
593 do_error (void *cls)
594 {
595  struct RequestHandle *handle = cls;
596  struct MHD_Response *resp;
597  char *json_error;
598 
599  GNUNET_asprintf (&json_error,
600  "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
601  handle->emsg,
602  (NULL != handle->edesc) ? handle->edesc : "",
603  (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
604  (NULL != handle->oidc->state) ? handle->oidc->state : "",
605  (NULL != handle->oidc->state) ? "\"" : "");
606  if (0 == handle->response_code)
607  handle->response_code = MHD_HTTP_BAD_REQUEST;
608  resp = GNUNET_REST_create_response (json_error);
609  if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
610  MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Basic");
611  MHD_add_response_header (resp,
612  MHD_HTTP_HEADER_CONTENT_TYPE,
613  "application/json");
614  handle->proc (handle->proc_cls, resp, handle->response_code);
616  GNUNET_free (json_error);
617 }
618 
619 
626 static void
627 do_userinfo_error (void *cls)
628 {
629  struct RequestHandle *handle = cls;
630  struct MHD_Response *resp;
631  char *error;
632 
633  GNUNET_asprintf (&error,
634  "error=\"%s\", error_description=\"%s\"",
635  handle->emsg,
636  (NULL != handle->edesc) ? handle->edesc : "");
637  resp = GNUNET_REST_create_response ("");
638  MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Bearer");
639  handle->proc (handle->proc_cls, resp, handle->response_code);
641  GNUNET_free (error);
642 }
643 
644 
650 static void
651 do_redirect_error (void *cls)
652 {
653  struct RequestHandle *handle = cls;
654  struct MHD_Response *resp;
655  char *redirect;
656 
657  GNUNET_asprintf (&redirect,
658  "%s?error=%s&error_description=%s%s%s",
659  handle->oidc->redirect_uri,
660  handle->emsg,
661  handle->edesc,
662  (NULL != handle->oidc->state) ? "&state=" : "",
663  (NULL != handle->oidc->state) ? handle->oidc->state : "");
664  resp = GNUNET_REST_create_response ("");
665  MHD_add_response_header (resp, "Location", redirect);
666  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
668  GNUNET_free (redirect);
669 }
670 
671 
677 static void
678 do_timeout (void *cls)
679 {
680  struct RequestHandle *handle = cls;
681 
682  handle->timeout_task = NULL;
683  do_error (handle);
684 }
685 
686 
692 static void
694 {
695  char *result_str;
696  struct RequestHandle *handle = cls;
697  struct MHD_Response *resp;
698 
699  result_str = json_dumps (handle->oidc->response, 0);
700 
701  resp = GNUNET_REST_create_response (result_str);
702  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
703  GNUNET_free (result_str);
704  cleanup_handle (handle);
705 }
706 
707 
715 static void
717  const char *url,
718  void *cls)
719 {
720  struct MHD_Response *resp;
721  struct RequestHandle *handle = cls;
722 
723  // For now, independent of path return all options
724  resp = GNUNET_REST_create_response (NULL);
725  MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
726  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
727  cleanup_handle (handle);
728  return;
729 }
730 
731 
735 static void
737 {
738  struct GNUNET_HashCode cache_key;
739  char *cookies;
740  struct GNUNET_TIME_Absolute current_time, *relog_time;
741  char delimiter[] = "; ";
742  char *tmp_cookies;
743  char *token;
744  char *value;
745 
746  // gets identity of login try with cookie
748  strlen (OIDC_COOKIE_HEADER_KEY),
749  &cache_key);
752  &cache_key))
753  {
754  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cookie found\n");
755  return;
756  }
757  // splits cookies and find 'Identity' cookie
758  tmp_cookies =
760  &cache_key);
761  cookies = GNUNET_strdup (tmp_cookies);
762  token = strtok (cookies, delimiter);
763  handle->oidc->user_cancelled = GNUNET_NO;
764  handle->oidc->login_identity = NULL;
765  if (NULL == token)
766  {
768  "Unable to parse cookie: %s\n",
769  cookies);
770  GNUNET_free (cookies);
771  return;
772  }
773 
774  while (NULL != token)
775  {
776  if (0 == strcmp (token, OIDC_COOKIE_HEADER_ACCESS_DENIED))
777  {
778  handle->oidc->user_cancelled = GNUNET_YES;
779  GNUNET_free (cookies);
780  return;
781  }
782  if (NULL != strstr (token, OIDC_COOKIE_HEADER_INFORMATION_KEY))
783  break;
784  token = strtok (NULL, delimiter);
785  }
786  if (NULL == token)
787  {
789  "No cookie value to process: %s\n",
790  cookies);
791  GNUNET_free (cookies);
792  return;
793  }
794  GNUNET_CRYPTO_hash (token, strlen (token), &cache_key);
795  if (GNUNET_NO ==
796  GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
797  {
798  GNUNET_log (
800  "Found cookie `%s', but no corresponding expiration entry present...\n",
801  token);
802  GNUNET_free (cookies);
803  return;
804  }
805  relog_time =
806  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
807  current_time = GNUNET_TIME_absolute_get ();
808  // 30 min after old login -> redirect to login
809  if (current_time.abs_value_us > relog_time->abs_value_us)
810  {
812  "Found cookie `%s', but it is expired.\n",
813  token);
814  GNUNET_free (cookies);
815  return;
816  }
817  value = strtok (token, OIDC_COOKIE_HEADER_INFORMATION_KEY);
818  GNUNET_assert (NULL != value);
819  handle->oidc->login_identity = GNUNET_strdup (value);
820  GNUNET_free (cookies);
821 }
822 
823 
827 static void
828 login_redirect (void *cls)
829 {
830  char *login_base_url;
831  char *new_redirect;
832  struct MHD_Response *resp;
833  struct RequestHandle *handle = cls;
834 
836  "reclaim-rest-plugin",
837  "address",
838  &login_base_url))
839  {
840  GNUNET_asprintf (&new_redirect,
841  "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
842  login_base_url,
844  handle->oidc->response_type,
846  handle->oidc->client_id,
848  handle->oidc->redirect_uri,
850  handle->oidc->scope,
852  (NULL != handle->oidc->state) ? handle->oidc->state : "",
854  (NULL != handle->oidc->code_challenge) ?
855  handle->oidc->code_challenge : "",
857  (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "");
858  resp = GNUNET_REST_create_response ("");
859  MHD_add_response_header (resp, "Location", new_redirect);
860  GNUNET_free (login_base_url);
861  }
862  else
863  {
865  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
866  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
868  return;
869  }
870  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
871  GNUNET_free (new_redirect);
873 }
874 
875 
879 static void
881 {
882  struct RequestHandle *handle = cls;
883 
885  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
887 }
888 
889 
894 static void
896 {
897  struct RequestHandle *handle = cls;
898  struct MHD_Response *resp;
899  char *ticket_str;
900  char *redirect_uri;
901  char *code_string;
902 
903  handle->idp_op = NULL;
904  if (NULL == ticket)
905  {
907  handle->edesc = GNUNET_strdup ("Server cannot generate ticket.");
909  return;
910  }
911  handle->ticket = *ticket;
912  ticket_str =
914  sizeof(struct GNUNET_RECLAIM_Ticket));
915  // TODO change if more attributes are needed (see max_age)
916  code_string = OIDC_build_authz_code (&handle->priv_key,
917  &handle->ticket,
918  handle->attr_list,
919  handle->oidc->nonce,
920  handle->oidc->code_challenge);
921  if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
922  (NULL != handle->tld))
923  {
924  GNUNET_asprintf (&redirect_uri,
925  "%s.%s/%s?%s=%s&state=%s",
926  handle->redirect_prefix,
927  handle->tld,
928  handle->redirect_suffix,
929  handle->oidc->response_type,
930  code_string,
931  handle->oidc->state);
932  }
933  else
934  {
935  GNUNET_asprintf (&redirect_uri,
936  "%s?%s=%s&state=%s",
937  handle->oidc->redirect_uri,
938  handle->oidc->response_type,
939  code_string,
940  handle->oidc->state);
941  }
942  resp = GNUNET_REST_create_response ("");
943  MHD_add_response_header (resp, "Location", redirect_uri);
944  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
946  GNUNET_free (redirect_uri);
947  GNUNET_free (ticket_str);
948  GNUNET_free (code_string);
949 }
950 
951 
952 static void
954 {
955  struct RequestHandle *handle = cls;
956 
957  handle->attr_it = NULL;
958  handle->ticket_it = NULL;
959  if (NULL == handle->attr_list->list_head)
960  {
962  handle->edesc = GNUNET_strdup ("The requested scope is not available.");
964  return;
965  }
966  handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp,
967  &handle->priv_key,
968  &handle->oidc->client_pkey,
969  handle->attr_list,
971  handle);
972 }
973 
974 
978 static void
979 oidc_attr_collect (void *cls,
981  const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
982 {
983  struct RequestHandle *handle = cls;
985  char *scope_variables;
986  char *scope_variable;
987  char delimiter[] = " ";
988 
989  if ((NULL == attr->name) || (NULL == attr->data))
990  {
992  return;
993  }
994 
995  scope_variables = GNUNET_strdup (handle->oidc->scope);
996  scope_variable = strtok (scope_variables, delimiter);
997  while (NULL != scope_variable)
998  {
999  if (0 == strcmp (attr->name, scope_variable))
1000  break;
1001  scope_variable = strtok (NULL, delimiter);
1002  }
1003  if (NULL == scope_variable)
1004  {
1006  GNUNET_free (scope_variables);
1007  return;
1008  }
1009  GNUNET_free (scope_variables);
1010 
1013  attr->type,
1014  attr->data,
1015  attr->data_size);
1016  le->claim->id = attr->id;
1017  le->claim->version = attr->version;
1019  handle->attr_list->list_tail,
1020  le);
1022 }
1023 
1024 
1028 static void
1029 code_redirect (void *cls)
1030 {
1031  struct RequestHandle *handle = cls;
1032  struct GNUNET_TIME_Absolute current_time;
1033  struct GNUNET_TIME_Absolute *relog_time;
1034  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
1035  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pkey;
1036  struct GNUNET_HashCode cache_key;
1037  char *identity_cookie;
1038 
1039  GNUNET_asprintf (&identity_cookie,
1040  "Identity=%s",
1041  handle->oidc->login_identity);
1042  GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1043  GNUNET_free (identity_cookie);
1044  // No login time for identity -> redirect to login
1045  if (GNUNET_YES ==
1046  GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
1047  {
1048  relog_time =
1049  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
1050  current_time = GNUNET_TIME_absolute_get ();
1051  // 30 min after old login -> redirect to login
1052  if (current_time.abs_value_us <= relog_time->abs_value_us)
1053  {
1054  if (GNUNET_OK !=
1056  ->login_identity,
1057  strlen (
1058  handle->oidc
1059  ->login_identity),
1060  &pubkey))
1061  {
1063  handle->edesc =
1064  GNUNET_strdup ("The cookie of a login identity is not valid");
1066  return;
1067  }
1068  // iterate over egos and compare their public key
1069  for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
1070  handle->ego_entry = handle->ego_entry->next)
1071  {
1072  GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1073  if (0 == GNUNET_memcmp (&ego_pkey, &pubkey))
1074  {
1075  handle->priv_key =
1077  handle->idp = GNUNET_RECLAIM_connect (cfg);
1078  handle->attr_list =
1080  handle->attr_it =
1082  &handle->priv_key,
1084  handle,
1086  handle,
1088  handle);
1089  return;
1090  }
1091  }
1093  return;
1094  }
1095  }
1096 }
1097 
1098 
1099 static void
1100 build_redirect (void *cls)
1101 {
1102  struct RequestHandle *handle = cls;
1103  struct MHD_Response *resp;
1104  char *redirect_uri;
1105 
1106  if (GNUNET_YES == handle->oidc->user_cancelled)
1107  {
1108  if ((NULL != handle->redirect_prefix) &&
1109  (NULL != handle->redirect_suffix) && (NULL != handle->tld))
1110  {
1111  GNUNET_asprintf (&redirect_uri,
1112  "%s.%s/%s?error=%s&error_description=%s&state=%s",
1113  handle->redirect_prefix,
1114  handle->tld,
1115  handle->redirect_suffix,
1116  "access_denied",
1117  "User denied access",
1118  handle->oidc->state);
1119  }
1120  else
1121  {
1122  GNUNET_asprintf (&redirect_uri,
1123  "%s?error=%s&error_description=%s&state=%s",
1124  handle->oidc->redirect_uri,
1125  "access_denied",
1126  "User denied access",
1127  handle->oidc->state);
1128  }
1129  resp = GNUNET_REST_create_response ("");
1130  MHD_add_response_header (resp, "Location", redirect_uri);
1131  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1133  GNUNET_free (redirect_uri);
1134  return;
1135  }
1137 }
1138 
1139 
1140 static void
1142  uint32_t rd_count,
1143  const struct GNUNET_GNSRECORD_Data *rd)
1144 {
1145  struct RequestHandle *handle = cls;
1146  char *tmp;
1147  char *tmp_key_str;
1148  char *pos;
1149  struct GNUNET_CRYPTO_EcdsaPublicKey redirect_zone;
1150 
1151  handle->gns_op = NULL;
1152  if (0 == rd_count)
1153  {
1155  handle->edesc =
1156  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1158  return;
1159  }
1160  for (int i = 0; i < rd_count; i++)
1161  {
1162  if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type)
1163  continue;
1164  if (0 != strncmp (rd[i].data, handle->oidc->redirect_uri, rd[i].data_size))
1165  continue;
1166  tmp = GNUNET_strndup (rd[i].data, rd[i].data_size);
1167  if (NULL == strstr (tmp, handle->oidc->client_id))
1168  {
1170  "Redirect uri %s does not contain client_id %s\n",
1171  tmp,
1172  handle->oidc->client_id);
1173  }
1174  else
1175  {
1176  pos = strrchr (tmp, (unsigned char) '.');
1177  if (NULL == pos)
1178  {
1180  "Redirect uri %s contains client_id but is malformed\n",
1181  tmp);
1182  GNUNET_free (tmp);
1183  continue;
1184  }
1185  *pos = '\0';
1186  handle->redirect_prefix = GNUNET_strdup (tmp);
1187  tmp_key_str = pos + 1;
1188  pos = strchr (tmp_key_str, (unsigned char) '/');
1189  if (NULL == pos)
1190  {
1192  "Redirect uri %s contains client_id but is malformed\n",
1193  tmp);
1194  GNUNET_free (tmp);
1195  continue;
1196  }
1197  *pos = '\0';
1198  handle->redirect_suffix = GNUNET_strdup (pos + 1);
1199 
1200  GNUNET_STRINGS_string_to_data (tmp_key_str,
1201  strlen (tmp_key_str),
1202  &redirect_zone,
1203  sizeof(redirect_zone));
1204  }
1206  GNUNET_free (tmp);
1207  return;
1208  }
1210  handle->edesc =
1211  GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1213 }
1214 
1215 
1219 static void
1220 client_redirect (void *cls)
1221 {
1222  struct RequestHandle *handle = cls;
1223 
1224  /* Lookup client redirect uri to verify request */
1225  handle->gns_op =
1226  GNUNET_GNS_lookup (handle->gns_handle,
1228  &handle->oidc->client_pkey,
1232  handle);
1233 }
1234 
1235 
1236 static char *
1237 get_url_parameter_copy (const struct RequestHandle *handle, const char *key)
1238 {
1239  struct GNUNET_HashCode hc;
1240  char *value;
1241 
1242  GNUNET_CRYPTO_hash (key, strlen (key), &hc);
1244  ->url_param_map,
1245  &hc))
1246  return NULL;
1247  value =
1249  if (NULL == value)
1250  return NULL;
1251  return GNUNET_strdup (value);
1252 }
1253 
1254 
1261 static void
1263 {
1264  struct RequestHandle *handle = cls;
1265  struct GNUNET_HashCode cache_key;
1266 
1267  char *expected_scope;
1268  char delimiter[] = " ";
1269  int number_of_ignored_parameter, iterator;
1270 
1271 
1272  // REQUIRED value: redirect_uri
1273  handle->oidc->redirect_uri =
1275  if (NULL == handle->oidc->redirect_uri)
1276  {
1278  handle->edesc = GNUNET_strdup ("missing parameter redirect_uri");
1280  return;
1281  }
1282 
1283  // REQUIRED value: response_type
1284  handle->oidc->response_type =
1286  if (NULL == handle->oidc->response_type)
1287  {
1289  handle->edesc = GNUNET_strdup ("missing parameter response_type");
1291  return;
1292  }
1293 
1294  // REQUIRED value: scope
1295  handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
1296  if (NULL == handle->oidc->scope)
1297  {
1299  handle->edesc = GNUNET_strdup ("missing parameter scope");
1301  return;
1302  }
1303 
1304  // OPTIONAL value: nonce
1305  handle->oidc->nonce = get_url_parameter_copy (handle, OIDC_NONCE_KEY);
1306 
1307  // TODO check other values if needed
1308  number_of_ignored_parameter =
1309  sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1310  for (iterator = 0; iterator < number_of_ignored_parameter; iterator++)
1311  {
1313  strlen (OIDC_ignored_parameter_array[iterator]),
1314  &cache_key);
1315  if (GNUNET_YES ==
1317  ->url_param_map,
1318  &cache_key))
1319  {
1321  GNUNET_asprintf (&handle->edesc,
1322  "Server will not handle parameter: %s",
1323  OIDC_ignored_parameter_array[iterator]);
1325  return;
1326  }
1327  }
1328 
1329  // We only support authorization code flows.
1330  if (0 != strcmp (handle->oidc->response_type,
1332  {
1334  handle->edesc = GNUNET_strdup ("The authorization server does not support "
1335  "obtaining this authorization code.");
1337  return;
1338  }
1339 
1340  // Checks if scope contains 'openid'
1341  expected_scope = GNUNET_strdup (handle->oidc->scope);
1342  char *test;
1343  test = strtok (expected_scope, delimiter);
1344  while (NULL != test)
1345  {
1346  if (0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope))
1347  break;
1348  test = strtok (NULL, delimiter);
1349  }
1350  if (NULL == test)
1351  {
1353  handle->edesc =
1354  GNUNET_strdup ("The requested scope is invalid, unknown, or malformed.");
1356  GNUNET_free (expected_scope);
1357  return;
1358  }
1359 
1360  GNUNET_free (expected_scope);
1361  if ((NULL == handle->oidc->login_identity) &&
1362  (GNUNET_NO == handle->oidc->user_cancelled))
1364  else
1366 }
1367 
1368 
1372 static void
1373 tld_iter (void *cls, const char *section, const char *option, const char *value)
1374 {
1375  struct RequestHandle *handle = cls;
1376  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1377 
1378  if (GNUNET_OK !=
1379  GNUNET_CRYPTO_ecdsa_public_key_from_string (value, strlen (value), &pkey))
1380  {
1381  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping non key %s\n", value);
1382  return;
1383  }
1384  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1385  handle->tld = GNUNET_strdup (option + 1);
1386 }
1387 
1388 
1396 static void
1398  const char *url,
1399  void *cls)
1400 {
1401  struct RequestHandle *handle = cls;
1402  struct EgoEntry *tmp_ego;
1403  const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1404  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1405 
1407 
1408  // RECOMMENDED value: state - REQUIRED for answers
1409  handle->oidc->state = get_url_parameter_copy (handle, OIDC_STATE_KEY);
1410 
1411  // REQUIRED value: client_id
1413  if (NULL == handle->oidc->client_id)
1414  {
1416  handle->edesc = GNUNET_strdup ("missing parameter client_id");
1417  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1419  return;
1420  }
1421 
1422  // OPTIONAL value: code_challenge
1423  handle->oidc->code_challenge = get_url_parameter_copy (handle,
1425  if (NULL == handle->oidc->code_challenge)
1426  {
1428  "OAuth authorization request does not contain PKCE parameters!\n");
1429  }
1430 
1431  if (GNUNET_OK !=
1433  strlen (
1434  handle->oidc->client_id),
1435  &handle->oidc->client_pkey))
1436  {
1438  handle->edesc = GNUNET_strdup ("The client is not authorized to request an "
1439  "authorization code using this method.");
1440  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1442  return;
1443  }
1444 
1445  // If we know this identity, translated the corresponding TLD
1446  // TODO: We might want to have a reverse lookup functionality for TLDs?
1447  for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
1448  {
1449  priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
1450  GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, &pkey);
1451  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1452  {
1453  handle->tld = GNUNET_strdup (tmp_ego->identifier);
1454  handle->ego_entry = handle->ego_tail;
1455  }
1456  }
1457  if (NULL == handle->tld)
1459  if (NULL == handle->tld)
1460  handle->tld = GNUNET_strdup (handle->oidc->client_id);
1462 }
1463 
1464 
1472 static void
1474  const char *url,
1475  void *cls)
1476 {
1477  struct MHD_Response *resp = GNUNET_REST_create_response ("");
1478  struct RequestHandle *handle = cls;
1479  struct GNUNET_HashCode cache_key;
1480  struct GNUNET_TIME_Absolute *current_time;
1481  struct GNUNET_TIME_Absolute *last_time;
1482  char *cookie;
1483  char *header_val;
1484  json_t *root;
1485  json_error_t error;
1486  json_t *identity;
1487  char term_data[handle->rest_handle->data_size + 1];
1488 
1489  term_data[handle->rest_handle->data_size] = '\0';
1490  GNUNET_memcpy (term_data,
1491  handle->rest_handle->data,
1492  handle->rest_handle->data_size);
1493  root = json_loads (term_data, JSON_DECODE_ANY, &error);
1494  identity = json_object_get (root, "identity");
1495  if (! json_is_string (identity))
1496  {
1498  "Error parsing json string from %s\n",
1499  term_data);
1500  handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1501  json_decref (root);
1503  return;
1504  }
1505  GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1506  GNUNET_asprintf (&header_val,
1507  "%s;Max-Age=%d",
1508  cookie,
1510  MHD_add_response_header (resp, "Set-Cookie", header_val);
1511  MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST");
1512  GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1513 
1514  if (0 != strcmp (json_string_value (identity), "Denied"))
1515  {
1516  current_time = GNUNET_new (struct GNUNET_TIME_Absolute);
1517  *current_time = GNUNET_TIME_relative_to_absolute (
1520  last_time =
1521  GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
1522  GNUNET_free_non_null (last_time);
1523  GNUNET_CONTAINER_multihashmap_put (OIDC_cookie_jar_map,
1524  &cache_key,
1525  current_time,
1527  }
1528  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1529  GNUNET_free (cookie);
1530  GNUNET_free (header_val);
1531  json_decref (root);
1533 }
1534 
1535 
1536 static int
1538  struct GNUNET_CRYPTO_EcdsaPublicKey *cid)
1539 {
1540  struct GNUNET_HashCode cache_key;
1541  char *authorization;
1542  char *credentials;
1543  char *basic_authorization;
1544  char *client_id;
1545  char *pass;
1546  char *expected_pass;
1547 
1550  &cache_key);
1552  ->header_param_map,
1553  &cache_key))
1554  {
1556  handle->edesc = GNUNET_strdup ("missing authorization");
1557  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1558  return GNUNET_SYSERR;
1559  }
1560  authorization =
1562  &cache_key);
1563 
1564  // split header in "Basic" and [content]
1565  credentials = strtok (authorization, " ");
1566  if ((NULL == credentials) || (0 != strcmp ("Basic", credentials)))
1567  {
1569  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1570  return GNUNET_SYSERR;
1571  }
1572  credentials = strtok (NULL, " ");
1573  if (NULL == credentials)
1574  {
1576  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1577  return GNUNET_SYSERR;
1578  }
1579  GNUNET_STRINGS_base64_decode (credentials,
1580  strlen (credentials),
1581  (void **) &basic_authorization);
1582 
1583  if (NULL == basic_authorization)
1584  {
1586  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1587  return GNUNET_SYSERR;
1588  }
1589  client_id = strtok (basic_authorization, ":");
1590  if (NULL == client_id)
1591  {
1592  GNUNET_free_non_null (basic_authorization);
1594  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1595  return GNUNET_SYSERR;
1596  }
1597  pass = strtok (NULL, ":");
1598  if (NULL == pass)
1599  {
1600  GNUNET_free_non_null (basic_authorization);
1602  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1603  return GNUNET_SYSERR;
1604  }
1605 
1606  // check client password
1608  "reclaim-rest-plugin",
1609  "OIDC_CLIENT_SECRET",
1610  &expected_pass))
1611  {
1612  if (0 != strcmp (expected_pass, pass))
1613  {
1614  GNUNET_free_non_null (basic_authorization);
1615  GNUNET_free (expected_pass);
1617  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1618  return GNUNET_SYSERR;
1619  }
1620  GNUNET_free (expected_pass);
1621  }
1622  else
1623  {
1624  GNUNET_free_non_null (basic_authorization);
1626  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1627  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1628  return GNUNET_SYSERR;
1629  }
1630 
1631  // check client_id
1632  for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
1633  handle->ego_entry = handle->ego_entry->next)
1634  {
1635  if (0 == strcmp (handle->ego_entry->keystring, client_id))
1636  break;
1637  }
1638  if (NULL == handle->ego_entry)
1639  {
1640  GNUNET_free_non_null (basic_authorization);
1642  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1643  return GNUNET_SYSERR;
1644  }
1645  GNUNET_STRINGS_string_to_data (client_id,
1646  strlen (client_id),
1647  cid,
1648  sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
1649 
1650  GNUNET_free (basic_authorization);
1651  return GNUNET_OK;
1652 }
1653 
1654 
1655 const struct EgoEntry *
1657  struct GNUNET_CRYPTO_EcdsaPublicKey *test_key)
1658 {
1659  struct EgoEntry *ego_entry;
1660  struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1661 
1662  for (ego_entry = handle->ego_head; NULL != ego_entry;
1663  ego_entry = ego_entry->next)
1664  {
1665  GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
1666  if (0 == GNUNET_memcmp (&pub_key, test_key))
1667  return ego_entry;
1668  }
1669  return NULL;
1670 }
1671 
1672 
1673 static void
1675  const char *access_token,
1676  const struct GNUNET_RECLAIM_Ticket *ticket)
1677 {
1678  struct GNUNET_HashCode hc;
1679  struct GNUNET_RECLAIM_Ticket *ticketbuf;
1680 
1681  GNUNET_CRYPTO_hash (access_token, strlen (access_token), &hc);
1682  ticketbuf = GNUNET_new (struct GNUNET_RECLAIM_Ticket);
1683  *ticketbuf = *ticket;
1686  OIDC_access_token_map,
1687  &hc,
1688  ticketbuf,
1690 }
1691 
1692 
1700 static void
1702  const char *url,
1703  void *cls)
1704 {
1705  struct RequestHandle *handle = cls;
1706  const struct EgoEntry *ego_entry;
1707  struct GNUNET_TIME_Relative expiration_time;
1709  struct GNUNET_RECLAIM_Ticket ticket;
1710  struct GNUNET_CRYPTO_EcdsaPublicKey cid;
1711  const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
1712  struct GNUNET_HashCode cache_key;
1713  struct MHD_Response *resp;
1714  char *grant_type;
1715  char *code;
1716  char *json_response;
1717  char *id_token;
1718  char *access_token;
1719  char *jwt_secret;
1720  char *nonce;
1721  char *code_verifier;
1722 
1723  /*
1724  * Check Authorization
1725  */
1726  if (GNUNET_SYSERR == check_authorization (handle, &cid))
1727  {
1729  "OIDC authorization for token endpoint failed\n");
1731  return;
1732  }
1733 
1734  /*
1735  * Check parameter
1736  */
1737 
1738  // TODO Do not allow multiple equal parameter names
1739  // REQUIRED grant_type
1741  strlen (OIDC_GRANT_TYPE_KEY),
1742  &cache_key);
1743  grant_type = get_url_parameter_copy (handle, OIDC_GRANT_TYPE_KEY);
1744  if (NULL == grant_type)
1745  {
1747  handle->edesc = GNUNET_strdup ("missing parameter grant_type");
1748  handle->response_code = MHD_HTTP_BAD_REQUEST;
1750  return;
1751  }
1752 
1753  // Check parameter grant_type == "authorization_code"
1754  if (0 != strcmp (OIDC_GRANT_TYPE_VALUE, grant_type))
1755  {
1757  handle->response_code = MHD_HTTP_BAD_REQUEST;
1758  GNUNET_free (grant_type);
1760  return;
1761  }
1762  GNUNET_free (grant_type);
1763  // REQUIRED code
1764  code = get_url_parameter_copy (handle, OIDC_CODE_KEY);
1765  if (NULL == code)
1766  {
1768  handle->edesc = GNUNET_strdup ("missing parameter code");
1769  handle->response_code = MHD_HTTP_BAD_REQUEST;
1771  return;
1772  }
1773  ego_entry = find_ego (handle, &cid);
1774  if (NULL == ego_entry)
1775  {
1777  handle->edesc = GNUNET_strdup ("Unknown client");
1778  handle->response_code = MHD_HTTP_BAD_REQUEST;
1779  GNUNET_free (code);
1781  return;
1782  }
1783  privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1784 
1785  // REQUIRED code verifier
1786  code_verifier = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY);
1787  if (NULL == code_verifier)
1788  {
1790  "OAuth authorization request does not contain PKCE parameters!\n");
1791 
1792  }
1793 
1794  // decode code
1795  if (GNUNET_OK != OIDC_parse_authz_code (privkey, code, code_verifier, &ticket,
1796  &cl, &nonce))
1797  {
1799  handle->edesc = GNUNET_strdup ("invalid code");
1800  handle->response_code = MHD_HTTP_BAD_REQUEST;
1801  GNUNET_free (code);
1803  return;
1804  }
1805  GNUNET_free (code);
1806 
1807  // create jwt
1809  "reclaim-rest-plugin",
1810  "expiration_time",
1811  &expiration_time))
1812  {
1814  handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1815  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1817  return;
1818  }
1819 
1820 
1821  // TODO OPTIONAL acr,amr,azp
1823  "reclaim-rest-plugin",
1824  "jwt_secret",
1825  &jwt_secret))
1826  {
1828  handle->edesc = GNUNET_strdup ("No signing secret configured!");
1829  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1831  return;
1832  }
1833  id_token = OIDC_id_token_new (&ticket.audience,
1834  &ticket.identity,
1835  cl,
1836  &expiration_time,
1837  (NULL != nonce) ? nonce : NULL,
1838  jwt_secret);
1839  access_token = OIDC_access_token_new ();
1840  OIDC_build_token_response (access_token,
1841  id_token,
1842  &expiration_time,
1843  &json_response);
1844 
1845  persist_access_token (handle, access_token, &ticket);
1846  resp = GNUNET_REST_create_response (json_response);
1847  MHD_add_response_header (resp, "Cache-Control", "no-store");
1848  MHD_add_response_header (resp, "Pragma", "no-cache");
1849  MHD_add_response_header (resp, "Content-Type", "application/json");
1850  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1852  GNUNET_free (access_token);
1853  GNUNET_free (json_response);
1854  GNUNET_free (id_token);
1856 }
1857 
1858 
1862 static void
1863 consume_ticket (void *cls,
1864  const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1865  const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
1866 {
1867  struct RequestHandle *handle = cls;
1868  char *tmp_value;
1869  json_t *value;
1870 
1871  if (NULL == identity)
1872  {
1874  return;
1875  }
1877  attr->data,
1878  attr->data_size);
1879  value = json_string (tmp_value);
1880  json_object_set_new (handle->oidc->response, attr->name, value);
1881  GNUNET_free (tmp_value);
1882 }
1883 
1884 
1892 static void
1894  const char *url,
1895  void *cls)
1896 {
1897  // TODO expiration time
1898  struct RequestHandle *handle = cls;
1899  char delimiter[] = " ";
1900  struct GNUNET_HashCode cache_key;
1901  char *authorization;
1902  char *authorization_type;
1903  char *authorization_access_token;
1904  struct GNUNET_RECLAIM_Ticket *ticket;
1905  const struct EgoEntry *ego_entry;
1906  const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
1907 
1910  &cache_key);
1912  ->header_param_map,
1913  &cache_key))
1914  {
1916  handle->edesc = GNUNET_strdup ("No Access Token");
1917  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1919  return;
1920  }
1921  authorization =
1923  &cache_key);
1924 
1925  // split header in "Bearer" and access_token
1926  authorization = GNUNET_strdup (authorization);
1927  authorization_type = strtok (authorization, delimiter);
1928  if ((NULL == authorization_type) ||
1929  (0 != strcmp ("Bearer", authorization_type)))
1930  {
1932  handle->edesc = GNUNET_strdup ("No Access Token");
1933  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1935  GNUNET_free (authorization);
1936  return;
1937  }
1938  authorization_access_token = strtok (NULL, delimiter);
1939  if (NULL == authorization_access_token)
1940  {
1942  handle->edesc = GNUNET_strdup ("Access token missing");
1943  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1945  GNUNET_free (authorization);
1946  return;
1947  }
1948 
1949  GNUNET_CRYPTO_hash (authorization_access_token,
1950  strlen (authorization_access_token),
1951  &cache_key);
1952  if (GNUNET_NO ==
1953  GNUNET_CONTAINER_multihashmap_contains (OIDC_access_token_map,
1954  &cache_key))
1955  {
1957  handle->edesc = GNUNET_strdup ("The access token expired");
1958  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1960  GNUNET_free (authorization);
1961  return;
1962  }
1963  ticket =
1964  GNUNET_CONTAINER_multihashmap_get (OIDC_access_token_map, &cache_key);
1965  GNUNET_assert (NULL != ticket);
1966  ego_entry = find_ego (handle, &ticket->audience);
1967  if (NULL == ego_entry)
1968  {
1970  handle->edesc = GNUNET_strdup ("The access token expired");
1971  handle->response_code = MHD_HTTP_UNAUTHORIZED;
1973  GNUNET_free (authorization);
1974  return;
1975  }
1976 
1977  handle->idp = GNUNET_RECLAIM_connect (cfg);
1978  handle->oidc->response = json_object ();
1979  json_object_set_new (handle->oidc->response,
1980  "sub",
1981  json_string (ego_entry->keystring));
1982  privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1983  handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
1984  privkey,
1985  ticket,
1987  handle);
1988  GNUNET_free (authorization);
1989 }
1990 
1991 
1997 static void
1999 {
2001  static const struct GNUNET_REST_RequestHandler handlers[] =
2002  { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint },
2003  { MHD_HTTP_METHOD_POST,
2005  &authorize_endpoint }, // url-encoded
2006  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont },
2007  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
2008  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2009  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2010  { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, &options_cont },
2012 
2013  if (GNUNET_NO ==
2014  GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
2015  {
2016  handle->response_code = err.error_code;
2018  }
2019 }
2020 
2021 
2055 static void
2056 list_ego (void *cls,
2057  struct GNUNET_IDENTITY_Ego *ego,
2058  void **ctx,
2059  const char *identifier)
2060 {
2061  struct RequestHandle *handle = cls;
2062  struct EgoEntry *ego_entry;
2063  struct GNUNET_CRYPTO_EcdsaPublicKey pk;
2064 
2065  if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
2066  {
2067  handle->state = ID_REST_STATE_POST_INIT;
2068  init_cont (handle);
2069  return;
2070  }
2071  GNUNET_assert (NULL != ego);
2072  if (ID_REST_STATE_INIT == handle->state)
2073 
2074  {
2075  ego_entry = GNUNET_new (struct EgoEntry);
2078  ego_entry->ego = ego;
2079  ego_entry->identifier = GNUNET_strdup (identifier);
2081  handle->ego_tail,
2082  ego_entry);
2083  return;
2084  }
2085  /* Ego renamed or added */
2086  if (identifier != NULL)
2087  {
2088  for (ego_entry = handle->ego_head; NULL != ego_entry;
2089  ego_entry = ego_entry->next)
2090  {
2091  if (ego_entry->ego == ego)
2092  {
2093  /* Rename */
2094  GNUNET_free (ego_entry->identifier);
2095  ego_entry->identifier = GNUNET_strdup (identifier);
2096  break;
2097  }
2098  }
2099  if (NULL == ego_entry)
2100  {
2101  /* Add */
2102  ego_entry = GNUNET_new (struct EgoEntry);
2105  ego_entry->ego = ego;
2106  ego_entry->identifier = GNUNET_strdup (identifier);
2108  handle->ego_tail,
2109  ego_entry);
2110  }
2111  }
2112  else
2113  {
2114  /* Delete */
2115  for (ego_entry = handle->ego_head; NULL != ego_entry;
2116  ego_entry = ego_entry->next)
2117  {
2118  if (ego_entry->ego == ego)
2119  break;
2120  }
2121  if (NULL != ego_entry)
2123  handle->ego_tail,
2124  ego_entry);
2125  }
2126 }
2127 
2128 
2129 static void
2132  void *proc_cls)
2133 {
2134  struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
2135 
2136  handle->oidc = GNUNET_new (struct OIDC_Variables);
2137  if (NULL == OIDC_cookie_jar_map)
2138  OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2139  if (NULL == OIDC_access_token_map)
2140  OIDC_access_token_map =
2142  handle->response_code = 0;
2144  handle->proc_cls = proc_cls;
2145  handle->proc = proc;
2146  handle->state = ID_REST_STATE_INIT;
2147  handle->rest_handle = rest_handle;
2148 
2149  handle->url = GNUNET_strdup (rest_handle->url);
2150  if (handle->url[strlen (handle->url) - 1] == '/')
2151  handle->url[strlen (handle->url) - 1] = '\0';
2152  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
2153  handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
2154  handle->gns_handle = GNUNET_GNS_connect (cfg);
2156  handle->timeout_task =
2157  GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
2158  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
2159 }
2160 
2161 
2168 void *
2170 {
2171  static struct Plugin plugin;
2172  struct GNUNET_REST_Plugin *api;
2173 
2174  cfg = cls;
2175  if (NULL != plugin.cfg)
2176  return NULL; /* can only initialize once! */
2177  memset (&plugin, 0, sizeof(struct Plugin));
2178  plugin.cfg = cfg;
2179  api = GNUNET_new (struct GNUNET_REST_Plugin);
2180  api->cls = &plugin;
2184  "%s, %s, %s, %s, %s",
2185  MHD_HTTP_METHOD_GET,
2186  MHD_HTTP_METHOD_POST,
2187  MHD_HTTP_METHOD_PUT,
2188  MHD_HTTP_METHOD_DELETE,
2189  MHD_HTTP_METHOD_OPTIONS);
2190 
2192  _ ("OpenID Connect REST API initialized\n"));
2193  return api;
2194 }
2195 
2196 
2203 void *
2205 {
2206  struct GNUNET_REST_Plugin *api = cls;
2207  struct Plugin *plugin = api->cls;
2208 
2209  plugin->cfg = NULL;
2210 
2211  struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2212  void *value = NULL;
2213  hashmap_it =
2214  GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_cookie_jar_map);
2215  while (GNUNET_YES ==
2216  GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2217  GNUNET_free_non_null (value);
2219  GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map);
2220 
2221  hashmap_it =
2222  GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_access_token_map);
2223  while (GNUNET_YES ==
2224  GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2225  GNUNET_free_non_null (value);
2226  GNUNET_CONTAINER_multihashmap_destroy (OIDC_access_token_map);
2229  GNUNET_free (api);
2231  "OpenID Connect REST plugin is finished\n");
2232  return NULL;
2233 }
2234 
2235 
2236 /* 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.
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:235
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:954
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
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.
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:555
void GNUNET_RECLAIM_disconnect(struct GNUNET_RECLAIM_Handle *h)
Disconnect from identity provider service.
Definition: reclaim_api.c:819
#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:1209
#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:1000
#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:741
#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:47
#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.
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:1253
Handle for an ego.
Definition: identity.h:245
Handle for a attribute iterator operation.
Definition: reclaim_api.c:167
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.
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_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:1280
char * name
Plugin name.
void GNUNET_GNS_disconnect(struct GNUNET_GNS_Handle *handle)
Shutdown connection with the GNS service.
Definition: gns_api.c:284
#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_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:1052
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:442
#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:837
struct GNUNET_GNS_Handle * GNUNET_GNS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Initialize the connection with the GNS service.
Definition: gns_api.c:262
#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: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.
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: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:332
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:239
#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:598
#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.
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:568
#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:769
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:466
struct GNUNET_GNS_Handle * gns_handle
GNS handle.
configuration data
Definition: configuration.c:85
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:1021
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:57
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:104
#define GNUNET_log(kind,...)
const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration handle.
Entry in list of pending tasks.
Definition: scheduler.c:134
#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:308
#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:1101
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:920
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:144
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:463
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:336
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:779
uint32_t data
The data value.
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry * next
DLL.
#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:119
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:952
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:966
char * url
The url.