plugin_rest_openid_connect.c 77 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2012-2018 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @author Martin Schanzenbach
  18. * @author Philippe Buschmann
  19. * @file identity/plugin_rest_openid_connect.c
  20. * @brief GNUnet Namestore REST plugin
  21. *
  22. */
  23. #include "platform.h"
  24. #include <inttypes.h>
  25. #include <jansson.h>
  26. #include "gnunet_buffer_lib.h"
  27. #include "gnunet_strings_lib.h"
  28. #include "gnunet_gns_service.h"
  29. #include "gnunet_gnsrecord_lib.h"
  30. #include "gnunet_identity_service.h"
  31. #include "gnunet_namestore_service.h"
  32. #include "gnunet_reclaim_lib.h"
  33. #include "gnunet_reclaim_service.h"
  34. #include "gnunet_rest_lib.h"
  35. #include "gnunet_rest_plugin.h"
  36. #include "gnunet_signatures.h"
  37. #include "microhttpd.h"
  38. #include "oidc_helper.h"
  39. /**
  40. * REST root namespace
  41. */
  42. #define GNUNET_REST_API_NS_OIDC "/openid"
  43. /**
  44. * Authorize endpoint
  45. */
  46. #define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize"
  47. /**
  48. * Token endpoint
  49. */
  50. #define GNUNET_REST_API_NS_TOKEN "/openid/token"
  51. /**
  52. * UserInfo endpoint
  53. */
  54. #define GNUNET_REST_API_NS_USERINFO "/openid/userinfo"
  55. /**
  56. * Login namespace
  57. */
  58. #define GNUNET_REST_API_NS_LOGIN "/openid/login"
  59. /**
  60. * State while collecting all egos
  61. */
  62. #define ID_REST_STATE_INIT 0
  63. /**
  64. * Done collecting egos
  65. */
  66. #define ID_REST_STATE_POST_INIT 1
  67. /**
  68. * OIDC grant_type key
  69. */
  70. #define OIDC_GRANT_TYPE_KEY "grant_type"
  71. /**
  72. * OIDC grant_type key
  73. */
  74. #define OIDC_GRANT_TYPE_VALUE "authorization_code"
  75. /**
  76. * OIDC code key
  77. */
  78. #define OIDC_CODE_KEY "code"
  79. /**
  80. * OIDC response_type key
  81. */
  82. #define OIDC_RESPONSE_TYPE_KEY "response_type"
  83. /**
  84. * OIDC client_id key
  85. */
  86. #define OIDC_CLIENT_ID_KEY "client_id"
  87. /**
  88. * OIDC scope key
  89. */
  90. #define OIDC_SCOPE_KEY "scope"
  91. /**
  92. * OIDC redirect_uri key
  93. */
  94. #define OIDC_REDIRECT_URI_KEY "redirect_uri"
  95. /**
  96. * OIDC state key
  97. */
  98. #define OIDC_STATE_KEY "state"
  99. /**
  100. * OIDC nonce key
  101. */
  102. #define OIDC_NONCE_KEY "nonce"
  103. /**
  104. * OIDC claims key
  105. */
  106. #define OIDC_CLAIMS_KEY "claims"
  107. /**
  108. * OIDC PKCE code challenge
  109. */
  110. #define OIDC_CODE_CHALLENGE_KEY "code_challenge"
  111. /**
  112. * OIDC PKCE code verifier
  113. */
  114. #define OIDC_CODE_VERIFIER_KEY "code_verifier"
  115. /**
  116. * OIDC cookie expiration (in seconds)
  117. */
  118. #define OIDC_COOKIE_EXPIRATION 3
  119. /**
  120. * OIDC cookie header key
  121. */
  122. #define OIDC_COOKIE_HEADER_KEY "cookie"
  123. /**
  124. * OIDC cookie header information key
  125. */
  126. #define OIDC_AUTHORIZATION_HEADER_KEY "authorization"
  127. /**
  128. * OIDC cookie header information key
  129. */
  130. #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
  131. /**
  132. * OIDC cookie header if user cancelled
  133. */
  134. #define OIDC_COOKIE_HEADER_ACCESS_DENIED "Identity=Denied"
  135. /**
  136. * OIDC expected response_type while authorizing
  137. */
  138. #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
  139. /**
  140. * OIDC expected scope part while authorizing
  141. */
  142. #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
  143. /**
  144. * OIDC error key for invalid client
  145. */
  146. #define OIDC_ERROR_KEY_INVALID_CLIENT "invalid_client"
  147. /**
  148. * OIDC error key for invalid scopes
  149. */
  150. #define OIDC_ERROR_KEY_INVALID_SCOPE "invalid_scope"
  151. /**
  152. * OIDC error key for invalid requests
  153. */
  154. #define OIDC_ERROR_KEY_INVALID_REQUEST "invalid_request"
  155. /**
  156. * OIDC error key for invalid tokens
  157. */
  158. #define OIDC_ERROR_KEY_INVALID_TOKEN "invalid_token"
  159. /**
  160. * OIDC error key for invalid cookies
  161. */
  162. #define OIDC_ERROR_KEY_INVALID_COOKIE "invalid_cookie"
  163. /**
  164. * OIDC error key for generic server errors
  165. */
  166. #define OIDC_ERROR_KEY_SERVER_ERROR "server_error"
  167. /**
  168. * OIDC error key for unsupported grants
  169. */
  170. #define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE "unsupported_grant_type"
  171. /**
  172. * OIDC error key for unsupported response types
  173. */
  174. #define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE "unsupported_response_type"
  175. /**
  176. * OIDC error key for unauthorized clients
  177. */
  178. #define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT "unauthorized_client"
  179. /**
  180. * OIDC error key for denied access
  181. */
  182. #define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied"
  183. /**
  184. * OIDC ignored parameter array
  185. */
  186. static char *OIDC_ignored_parameter_array[] = { "display",
  187. "prompt",
  188. "ui_locales",
  189. "response_mode",
  190. "id_token_hint",
  191. "login_hint",
  192. "acr_values" };
  193. /**
  194. * OIDC Hash map that keeps track of issued cookies
  195. */
  196. struct GNUNET_CONTAINER_MultiHashMap *OIDC_cookie_jar_map;
  197. /**
  198. * Hash map that links the issued access token to the corresponding ticket and
  199. * ego
  200. */
  201. struct GNUNET_CONTAINER_MultiHashMap *OIDC_access_token_map;
  202. /**
  203. * The configuration handle
  204. */
  205. const struct GNUNET_CONFIGURATION_Handle *cfg;
  206. /**
  207. * HTTP methods allows for this plugin
  208. */
  209. static char *allow_methods;
  210. /**
  211. * @brief struct returned by the initialization function of the plugin
  212. */
  213. struct Plugin
  214. {
  215. const struct GNUNET_CONFIGURATION_Handle *cfg;
  216. };
  217. /**
  218. * OIDC needed variables
  219. */
  220. struct OIDC_Variables
  221. {
  222. /**
  223. * The RP client public key
  224. */
  225. struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
  226. /**
  227. * The OIDC client id of the RP
  228. */
  229. char *client_id;
  230. /**
  231. * The OIDC redirect uri
  232. */
  233. char *redirect_uri;
  234. /**
  235. * The list of oidc scopes
  236. */
  237. char *scope;
  238. /**
  239. * The OIDC state
  240. */
  241. char *state;
  242. /**
  243. * The OIDC nonce
  244. */
  245. char *nonce;
  246. /**
  247. * The OIDC claims
  248. */
  249. char *claims;
  250. /**
  251. * The OIDC response type
  252. */
  253. char *response_type;
  254. /**
  255. * The identity chosen by the user to login
  256. */
  257. char *login_identity;
  258. /**
  259. * User cancelled authorization/login
  260. */
  261. int user_cancelled;
  262. /**
  263. * The PKCE code_challenge
  264. */
  265. char *code_challenge;
  266. /**
  267. * The PKCE code_verifier
  268. */
  269. char *code_verifier;
  270. /**
  271. * The response JSON
  272. */
  273. json_t *response;
  274. };
  275. /**
  276. * The ego list
  277. */
  278. struct EgoEntry
  279. {
  280. /**
  281. * DLL
  282. */
  283. struct EgoEntry *next;
  284. /**
  285. * DLL
  286. */
  287. struct EgoEntry *prev;
  288. /**
  289. * Ego Identifier
  290. */
  291. char *identifier;
  292. /**
  293. * Public key string
  294. */
  295. char *keystring;
  296. /**
  297. * The Ego
  298. */
  299. struct GNUNET_IDENTITY_Ego *ego;
  300. };
  301. struct RequestHandle
  302. {
  303. /**
  304. * Ego list
  305. */
  306. struct EgoEntry *ego_head;
  307. /**
  308. * Ego list
  309. */
  310. struct EgoEntry *ego_tail;
  311. /**
  312. * Selected ego
  313. */
  314. struct EgoEntry *ego_entry;
  315. /**
  316. * Pointer to ego private key
  317. */
  318. struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
  319. /**
  320. * OIDC variables
  321. */
  322. struct OIDC_Variables *oidc;
  323. /**
  324. * The processing state
  325. */
  326. int state;
  327. /**
  328. * Handle to Identity service.
  329. */
  330. struct GNUNET_IDENTITY_Handle *identity_handle;
  331. /**
  332. * Rest connection
  333. */
  334. struct GNUNET_REST_RequestHandle *rest_handle;
  335. /**
  336. * GNS handle
  337. */
  338. struct GNUNET_GNS_Handle *gns_handle;
  339. /**
  340. * GNS lookup op
  341. */
  342. struct GNUNET_GNS_LookupRequest *gns_op;
  343. /**
  344. * Handle to NAMESTORE
  345. */
  346. struct GNUNET_NAMESTORE_Handle *namestore_handle;
  347. /**
  348. * Iterator for NAMESTORE
  349. */
  350. struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
  351. /**
  352. * Attribute claim list for id_token
  353. */
  354. struct GNUNET_RECLAIM_AttributeList *attr_idtoken_list;
  355. /**
  356. * Attribute claim list for userinfo
  357. */
  358. struct GNUNET_RECLAIM_AttributeList *attr_userinfo_list;
  359. /**
  360. * Attestation list
  361. */
  362. struct GNUNET_RECLAIM_AttestationList *attests_list;
  363. /**
  364. * IDENTITY Operation
  365. */
  366. struct GNUNET_IDENTITY_Operation *op;
  367. /**
  368. * Identity Provider
  369. */
  370. struct GNUNET_RECLAIM_Handle *idp;
  371. /**
  372. * Idp Operation
  373. */
  374. struct GNUNET_RECLAIM_Operation *idp_op;
  375. /**
  376. * Attribute iterator
  377. */
  378. struct GNUNET_RECLAIM_AttributeIterator *attr_it;
  379. /**
  380. * Attestation iterator
  381. */
  382. struct GNUNET_RECLAIM_AttestationIterator *attest_it;
  383. /**
  384. * Ticket iterator
  385. */
  386. struct GNUNET_RECLAIM_TicketIterator *ticket_it;
  387. /**
  388. * A ticket
  389. */
  390. struct GNUNET_RECLAIM_Ticket ticket;
  391. /**
  392. * Desired timeout for the lookup (default is no timeout).
  393. */
  394. struct GNUNET_TIME_Relative timeout;
  395. /**
  396. * ID of a task associated with the resolution process.
  397. */
  398. struct GNUNET_SCHEDULER_Task *timeout_task;
  399. /**
  400. * The plugin result processor
  401. */
  402. GNUNET_REST_ResultProcessor proc;
  403. /**
  404. * The closure of the result processor
  405. */
  406. void *proc_cls;
  407. /**
  408. * The url
  409. */
  410. char *url;
  411. /**
  412. * The tld for redirect
  413. */
  414. char *tld;
  415. /**
  416. * The redirect prefix
  417. */
  418. char *redirect_prefix;
  419. /**
  420. * The redirect suffix
  421. */
  422. char *redirect_suffix;
  423. /**
  424. * Error response message
  425. */
  426. char *emsg;
  427. /**
  428. * Error response description
  429. */
  430. char *edesc;
  431. /**
  432. * Reponse code
  433. */
  434. int response_code;
  435. };
  436. /**
  437. * Cleanup lookup handle
  438. * @param handle Handle to clean up
  439. */
  440. static void
  441. cleanup_handle (struct RequestHandle *handle)
  442. {
  443. struct EgoEntry *ego_entry;
  444. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
  445. if (NULL != handle->timeout_task)
  446. GNUNET_SCHEDULER_cancel (handle->timeout_task);
  447. if (NULL != handle->identity_handle)
  448. GNUNET_IDENTITY_disconnect (handle->identity_handle);
  449. if (NULL != handle->attr_it)
  450. GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
  451. if (NULL != handle->attest_it)
  452. GNUNET_RECLAIM_get_attestations_stop (handle->attest_it);
  453. if (NULL != handle->ticket_it)
  454. GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
  455. if (NULL != handle->idp_op)
  456. GNUNET_RECLAIM_cancel (handle->idp_op);
  457. if (NULL != handle->idp)
  458. GNUNET_RECLAIM_disconnect (handle->idp);
  459. GNUNET_free (handle->url);
  460. GNUNET_free (handle->tld);
  461. GNUNET_free (handle->redirect_prefix);
  462. GNUNET_free (handle->redirect_suffix);
  463. GNUNET_free (handle->emsg);
  464. GNUNET_free (handle->edesc);
  465. if (NULL != handle->gns_op)
  466. GNUNET_GNS_lookup_cancel (handle->gns_op);
  467. if (NULL != handle->gns_handle)
  468. GNUNET_GNS_disconnect (handle->gns_handle);
  469. if (NULL != handle->namestore_handle)
  470. GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
  471. if (NULL != handle->oidc)
  472. {
  473. GNUNET_free (handle->oidc->client_id);
  474. GNUNET_free (handle->oidc->login_identity);
  475. GNUNET_free (handle->oidc->nonce);
  476. GNUNET_free (handle->oidc->redirect_uri);
  477. GNUNET_free (handle->oidc->response_type);
  478. GNUNET_free (handle->oidc->scope);
  479. GNUNET_free (handle->oidc->state);
  480. json_decref (handle->oidc->response);
  481. GNUNET_free (handle->oidc);
  482. }
  483. if (NULL!=handle->attr_idtoken_list)
  484. GNUNET_RECLAIM_attribute_list_destroy (handle->attr_idtoken_list);
  485. if (NULL!=handle->attr_userinfo_list)
  486. GNUNET_RECLAIM_attribute_list_destroy (handle->attr_userinfo_list);
  487. if (NULL!=handle->attests_list)
  488. GNUNET_RECLAIM_attestation_list_destroy (handle->attests_list);
  489. while (NULL != (ego_entry = handle->ego_head))
  490. {
  491. GNUNET_CONTAINER_DLL_remove (handle->ego_head,
  492. handle->ego_tail,
  493. ego_entry);
  494. GNUNET_free (ego_entry->identifier);
  495. GNUNET_free (ego_entry->keystring);
  496. GNUNET_free (ego_entry);
  497. }
  498. GNUNET_free (handle);
  499. }
  500. static void
  501. cleanup_handle_delayed (void *cls)
  502. {
  503. cleanup_handle (cls);
  504. }
  505. /**
  506. * Task run on error, sends error message. Cleans up everything.
  507. *
  508. * @param cls the `struct RequestHandle`
  509. */
  510. static void
  511. do_error (void *cls)
  512. {
  513. struct RequestHandle *handle = cls;
  514. struct MHD_Response *resp;
  515. char *json_error;
  516. GNUNET_asprintf (&json_error,
  517. "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
  518. handle->emsg,
  519. (NULL != handle->edesc) ? handle->edesc : "",
  520. (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
  521. (NULL != handle->oidc->state) ? handle->oidc->state : "",
  522. (NULL != handle->oidc->state) ? "\"" : "");
  523. if (0 == handle->response_code)
  524. handle->response_code = MHD_HTTP_BAD_REQUEST;
  525. resp = GNUNET_REST_create_response (json_error);
  526. if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
  527. MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Basic");
  528. MHD_add_response_header (resp,
  529. MHD_HTTP_HEADER_CONTENT_TYPE,
  530. "application/json");
  531. handle->proc (handle->proc_cls, resp, handle->response_code);
  532. GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
  533. GNUNET_free (json_error);
  534. }
  535. /**
  536. * Task run on error in userinfo endpoint, sends error header. Cleans up
  537. * everything
  538. *
  539. * @param cls the `struct RequestHandle`
  540. */
  541. static void
  542. do_userinfo_error (void *cls)
  543. {
  544. struct RequestHandle *handle = cls;
  545. struct MHD_Response *resp;
  546. char *error;
  547. GNUNET_asprintf (&error,
  548. "error=\"%s\", error_description=\"%s\"",
  549. handle->emsg,
  550. (NULL != handle->edesc) ? handle->edesc : "");
  551. resp = GNUNET_REST_create_response ("");
  552. MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Bearer");
  553. handle->proc (handle->proc_cls, resp, handle->response_code);
  554. GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
  555. GNUNET_free (error);
  556. }
  557. /**
  558. * Task run on error, sends error message and redirects. Cleans up everything.
  559. *
  560. * @param cls the `struct RequestHandle`
  561. */
  562. static void
  563. do_redirect_error (void *cls)
  564. {
  565. struct RequestHandle *handle = cls;
  566. struct MHD_Response *resp;
  567. char *redirect;
  568. GNUNET_asprintf (&redirect,
  569. "%s?error=%s&error_description=%s%s%s",
  570. handle->oidc->redirect_uri,
  571. handle->emsg,
  572. handle->edesc,
  573. (NULL != handle->oidc->state) ? "&state=" : "",
  574. (NULL != handle->oidc->state) ? handle->oidc->state : "");
  575. resp = GNUNET_REST_create_response ("");
  576. MHD_add_response_header (resp, "Location", redirect);
  577. handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
  578. GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
  579. GNUNET_free (redirect);
  580. }
  581. /**
  582. * Task run on timeout, sends error message. Cleans up everything.
  583. *
  584. * @param cls the `struct RequestHandle`
  585. */
  586. static void
  587. do_timeout (void *cls)
  588. {
  589. struct RequestHandle *handle = cls;
  590. handle->timeout_task = NULL;
  591. do_error (handle);
  592. }
  593. /**
  594. * Return attributes for claim
  595. *
  596. * @param cls the request handle
  597. */
  598. static void
  599. return_userinfo_response (void *cls)
  600. {
  601. char *result_str;
  602. struct RequestHandle *handle = cls;
  603. struct MHD_Response *resp;
  604. result_str = json_dumps (handle->oidc->response, 0);
  605. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"ID-Token: %s\n",result_str);
  606. resp = GNUNET_REST_create_response (result_str);
  607. handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
  608. GNUNET_free (result_str);
  609. cleanup_handle (handle);
  610. }
  611. /**
  612. * Respond to OPTIONS request
  613. *
  614. * @param con_handle the connection handle
  615. * @param url the url
  616. * @param cls the RequestHandle
  617. */
  618. static void
  619. options_cont (struct GNUNET_REST_RequestHandle *con_handle,
  620. const char *url,
  621. void *cls)
  622. {
  623. struct MHD_Response *resp;
  624. struct RequestHandle *handle = cls;
  625. // For now, independent of path return all options
  626. resp = GNUNET_REST_create_response (NULL);
  627. MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
  628. handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
  629. cleanup_handle (handle);
  630. return;
  631. }
  632. /**
  633. * Interprets cookie header and pass its identity keystring to handle
  634. */
  635. static void
  636. cookie_identity_interpretation (struct RequestHandle *handle)
  637. {
  638. struct GNUNET_HashCode cache_key;
  639. char *cookies;
  640. struct GNUNET_TIME_Absolute current_time, *relog_time;
  641. char delimiter[] = "; ";
  642. char *tmp_cookies;
  643. char *token;
  644. char *value;
  645. // gets identity of login try with cookie
  646. GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY,
  647. strlen (OIDC_COOKIE_HEADER_KEY),
  648. &cache_key);
  649. if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
  650. ->header_param_map,
  651. &cache_key))
  652. {
  653. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cookie found\n");
  654. return;
  655. }
  656. // splits cookies and find 'Identity' cookie
  657. tmp_cookies =
  658. GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
  659. &cache_key);
  660. cookies = GNUNET_strdup (tmp_cookies);
  661. token = strtok (cookies, delimiter);
  662. handle->oidc->user_cancelled = GNUNET_NO;
  663. handle->oidc->login_identity = NULL;
  664. if (NULL == token)
  665. {
  666. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  667. "Unable to parse cookie: %s\n",
  668. cookies);
  669. GNUNET_free (cookies);
  670. return;
  671. }
  672. while (NULL != token)
  673. {
  674. if (0 == strcmp (token, OIDC_COOKIE_HEADER_ACCESS_DENIED))
  675. {
  676. handle->oidc->user_cancelled = GNUNET_YES;
  677. GNUNET_free (cookies);
  678. return;
  679. }
  680. if (NULL != strstr (token, OIDC_COOKIE_HEADER_INFORMATION_KEY))
  681. break;
  682. token = strtok (NULL, delimiter);
  683. }
  684. if (NULL == token)
  685. {
  686. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  687. "No cookie value to process: %s\n",
  688. cookies);
  689. GNUNET_free (cookies);
  690. return;
  691. }
  692. GNUNET_CRYPTO_hash (token, strlen (token), &cache_key);
  693. if (GNUNET_NO ==
  694. GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
  695. {
  696. GNUNET_log (
  697. GNUNET_ERROR_TYPE_WARNING,
  698. "Found cookie `%s', but no corresponding expiration entry present...\n",
  699. token);
  700. GNUNET_free (cookies);
  701. return;
  702. }
  703. relog_time =
  704. GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
  705. current_time = GNUNET_TIME_absolute_get ();
  706. // 30 min after old login -> redirect to login
  707. if (current_time.abs_value_us > relog_time->abs_value_us)
  708. {
  709. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  710. "Found cookie `%s', but it is expired.\n",
  711. token);
  712. GNUNET_free (cookies);
  713. return;
  714. }
  715. value = strtok (token, OIDC_COOKIE_HEADER_INFORMATION_KEY);
  716. GNUNET_assert (NULL != value);
  717. handle->oidc->login_identity = GNUNET_strdup (value);
  718. GNUNET_free (cookies);
  719. }
  720. /**
  721. * Redirects to login page stored in configuration file
  722. */
  723. static void
  724. login_redirect (void *cls)
  725. {
  726. char *login_base_url;
  727. char *new_redirect;
  728. struct MHD_Response *resp;
  729. struct GNUNET_Buffer buf = { 0 };
  730. struct RequestHandle *handle = cls;
  731. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
  732. "reclaim-rest-plugin",
  733. "address",
  734. &login_base_url))
  735. {
  736. GNUNET_buffer_write_str (&buf, login_base_url);
  737. GNUNET_buffer_write_fstr (&buf,
  738. "?%s=%s",
  739. OIDC_RESPONSE_TYPE_KEY,
  740. handle->oidc->response_type);
  741. GNUNET_buffer_write_fstr (&buf,
  742. "&%s=%s",
  743. OIDC_CLIENT_ID_KEY,
  744. handle->oidc->client_id);
  745. GNUNET_buffer_write_fstr (&buf,
  746. "&%s=%s",
  747. OIDC_REDIRECT_URI_KEY,
  748. handle->oidc->redirect_uri);
  749. GNUNET_buffer_write_fstr (&buf,
  750. "&%s=%s",
  751. OIDC_SCOPE_KEY,
  752. handle->oidc->scope);
  753. if (NULL != handle->oidc->state)
  754. {
  755. GNUNET_buffer_write_fstr (&buf,
  756. "&%s=%s",
  757. OIDC_STATE_KEY,
  758. handle->oidc->state);
  759. }
  760. if (NULL != handle->oidc->code_challenge)
  761. {
  762. GNUNET_buffer_write_fstr (&buf,
  763. "&%s=%s",
  764. OIDC_CODE_CHALLENGE_KEY,
  765. handle->oidc->code_challenge);
  766. }
  767. if (NULL != handle->oidc->nonce)
  768. {
  769. GNUNET_buffer_write_fstr (&buf,
  770. "&%s=%s",
  771. OIDC_NONCE_KEY,
  772. handle->oidc->nonce);
  773. }
  774. if (NULL != handle->oidc->claims)
  775. {
  776. GNUNET_buffer_write_fstr (&buf,
  777. "&%s=%s",
  778. OIDC_CLAIMS_KEY,
  779. handle->oidc->claims);
  780. }
  781. new_redirect = GNUNET_buffer_reap_str (&buf);
  782. resp = GNUNET_REST_create_response ("");
  783. MHD_add_response_header (resp, "Location", new_redirect);
  784. GNUNET_free (login_base_url);
  785. }
  786. else
  787. {
  788. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
  789. handle->edesc = GNUNET_strdup ("gnunet configuration failed");
  790. handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
  791. GNUNET_SCHEDULER_add_now (&do_error, handle);
  792. return;
  793. }
  794. handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
  795. GNUNET_free (new_redirect);
  796. GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
  797. }
  798. /**
  799. * Does internal server error when iteration failed.
  800. */
  801. static void
  802. oidc_iteration_error (void *cls)
  803. {
  804. struct RequestHandle *handle = cls;
  805. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
  806. handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
  807. GNUNET_SCHEDULER_add_now (&do_error, handle);
  808. }
  809. /**
  810. * Issues ticket and redirects to relying party with the authorization code as
  811. * parameter. Otherwise redirects with error
  812. */
  813. static void
  814. oidc_ticket_issue_cb (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
  815. {
  816. struct RequestHandle *handle = cls;
  817. struct MHD_Response *resp;
  818. char *ticket_str;
  819. char *redirect_uri;
  820. char *code_string;
  821. handle->idp_op = NULL;
  822. if (NULL == ticket)
  823. {
  824. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
  825. handle->edesc = GNUNET_strdup ("Server cannot generate ticket.");
  826. GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
  827. return;
  828. }
  829. handle->ticket = *ticket;
  830. ticket_str =
  831. GNUNET_STRINGS_data_to_string_alloc (&handle->ticket,
  832. sizeof(struct GNUNET_RECLAIM_Ticket));
  833. code_string = OIDC_build_authz_code (&handle->priv_key,
  834. &handle->ticket,
  835. handle->attr_idtoken_list,
  836. handle->attests_list,
  837. handle->oidc->nonce,
  838. handle->oidc->code_challenge);
  839. if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
  840. (NULL != handle->tld))
  841. {
  842. GNUNET_asprintf (&redirect_uri,
  843. "%s.%s/%s?%s=%s&state=%s",
  844. handle->redirect_prefix,
  845. handle->tld,
  846. handle->redirect_suffix,
  847. handle->oidc->response_type,
  848. code_string,
  849. handle->oidc->state);
  850. }
  851. else
  852. {
  853. GNUNET_asprintf (&redirect_uri,
  854. "%s?%s=%s&state=%s",
  855. handle->oidc->redirect_uri,
  856. handle->oidc->response_type,
  857. code_string,
  858. handle->oidc->state);
  859. }
  860. resp = GNUNET_REST_create_response ("");
  861. MHD_add_response_header (resp, "Location", redirect_uri);
  862. handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
  863. GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
  864. GNUNET_free (redirect_uri);
  865. GNUNET_free (ticket_str);
  866. GNUNET_free (code_string);
  867. }
  868. static struct GNUNET_RECLAIM_AttributeList*
  869. attribute_list_merge (struct GNUNET_RECLAIM_AttributeList *list_a,
  870. struct GNUNET_RECLAIM_AttributeList *list_b)
  871. {
  872. struct GNUNET_RECLAIM_AttributeList *merged_list;
  873. struct GNUNET_RECLAIM_AttributeListEntry *le_a;
  874. struct GNUNET_RECLAIM_AttributeListEntry *le_b;
  875. struct GNUNET_RECLAIM_AttributeListEntry *le_m;
  876. merged_list = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
  877. for (le_a = list_a->list_head; NULL != le_a; le_a = le_a->next)
  878. {
  879. le_m = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
  880. le_m->attribute = GNUNET_RECLAIM_attribute_new (le_a->attribute->name,
  881. &le_a->attribute->
  882. attestation,
  883. le_a->attribute->type,
  884. le_a->attribute->data,
  885. le_a->attribute->data_size);
  886. le_m->attribute->id = le_a->attribute->id;
  887. le_m->attribute->flag = le_a->attribute->flag;
  888. le_m->attribute->attestation = le_a->attribute->attestation;
  889. GNUNET_CONTAINER_DLL_insert (merged_list->list_head,
  890. merged_list->list_tail,
  891. le_m);
  892. }
  893. le_m = NULL;
  894. for (le_b = list_b->list_head; NULL != le_b; le_b = le_b->next)
  895. {
  896. for (le_m = merged_list->list_head; NULL != le_m; le_m = le_m->next)
  897. {
  898. if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (&le_m->attribute->id,
  899. &le_b->attribute->id))
  900. break; /** Attribute already in list **/
  901. }
  902. if (NULL != le_m)
  903. continue; /** Attribute already in list **/
  904. le_m = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
  905. le_m->attribute = GNUNET_RECLAIM_attribute_new (le_b->attribute->name,
  906. &le_b->attribute->
  907. attestation,
  908. le_b->attribute->type,
  909. le_b->attribute->data,
  910. le_b->attribute->data_size);
  911. le_m->attribute->id = le_b->attribute->id;
  912. le_m->attribute->flag = le_b->attribute->flag;
  913. le_m->attribute->attestation = le_b->attribute->attestation;
  914. GNUNET_CONTAINER_DLL_insert (merged_list->list_head,
  915. merged_list->list_tail,
  916. le_m);
  917. }
  918. return merged_list;
  919. }
  920. static void
  921. oidc_attest_collect_finished_cb (void *cls)
  922. {
  923. struct RequestHandle *handle = cls;
  924. struct GNUNET_RECLAIM_AttributeList *merged_list;
  925. handle->attest_it = NULL;
  926. merged_list = attribute_list_merge (handle->attr_idtoken_list,
  927. handle->attr_userinfo_list);
  928. handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp,
  929. &handle->priv_key,
  930. &handle->oidc->client_pkey,
  931. merged_list,
  932. &oidc_ticket_issue_cb,
  933. handle);
  934. GNUNET_RECLAIM_attribute_list_destroy (merged_list);
  935. }
  936. /**
  937. * Collects all attributes for an ego if in scope parameter
  938. */
  939. static void
  940. oidc_attest_collect (void *cls,
  941. const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
  942. const struct GNUNET_RECLAIM_Attestation *attest)
  943. {
  944. struct RequestHandle *handle = cls;
  945. struct GNUNET_RECLAIM_AttributeListEntry *le;
  946. struct GNUNET_RECLAIM_AttestationListEntry *ale;
  947. for (ale = handle->attests_list->list_head; NULL != ale; ale = ale->next)
  948. {
  949. if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (&ale->attestation->id,
  950. &attest->id))
  951. continue;
  952. /** Attestation already in list **/
  953. GNUNET_RECLAIM_get_attestations_next (handle->attest_it);
  954. return;
  955. }
  956. for (le = handle->attr_idtoken_list->list_head; NULL != le; le = le->next)
  957. {
  958. if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (&le->attribute->attestation,
  959. &attest->id))
  960. continue;
  961. /** Attestation matches for attribute, add **/
  962. ale = GNUNET_new (struct GNUNET_RECLAIM_AttestationListEntry);
  963. ale->attestation = GNUNET_RECLAIM_attestation_new (attest->name,
  964. attest->type,
  965. attest->data,
  966. attest->data_size);
  967. GNUNET_CONTAINER_DLL_insert (handle->attests_list->list_head,
  968. handle->attests_list->list_tail,
  969. ale);
  970. }
  971. GNUNET_RECLAIM_get_attestations_next (handle->attest_it);
  972. }
  973. static void
  974. oidc_attr_collect_finished_cb (void *cls)
  975. {
  976. struct RequestHandle *handle = cls;
  977. handle->attr_it = NULL;
  978. handle->ticket_it = NULL;
  979. if (NULL == handle->attr_idtoken_list->list_head)
  980. {
  981. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE);
  982. handle->edesc = GNUNET_strdup ("The requested scope is not available.");
  983. GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
  984. return;
  985. }
  986. handle->attests_list = GNUNET_new (struct GNUNET_RECLAIM_AttestationList);
  987. handle->attest_it =
  988. GNUNET_RECLAIM_get_attestations_start (handle->idp,
  989. &handle->priv_key,
  990. &oidc_iteration_error,
  991. handle,
  992. &oidc_attest_collect,
  993. handle,
  994. &oidc_attest_collect_finished_cb,
  995. handle);
  996. }
  997. static int
  998. attr_in_claims_request (struct RequestHandle *handle,
  999. const char *attr_name,
  1000. const char *claims_parameter)
  1001. {
  1002. char *scope_variables;
  1003. char *scope_variable;
  1004. char delimiter[] = " ";
  1005. int ret = GNUNET_NO;
  1006. json_t *root;
  1007. json_error_t error;
  1008. json_t *claims_j;
  1009. const char *key;
  1010. json_t *value;
  1011. scope_variables = GNUNET_strdup (handle->oidc->scope);
  1012. scope_variable = strtok (scope_variables, delimiter);
  1013. while (NULL != scope_variable)
  1014. {
  1015. if (0 == strcmp (attr_name, scope_variable))
  1016. break;
  1017. scope_variable = strtok (NULL, delimiter);
  1018. }
  1019. if (NULL != scope_variable)
  1020. ret = GNUNET_YES;
  1021. GNUNET_free (scope_variables);
  1022. /** Try claims parameter if no in scope */
  1023. if ((NULL != handle->oidc->claims) &&
  1024. (GNUNET_YES != ret))
  1025. {
  1026. root = json_loads (handle->oidc->claims, JSON_DECODE_ANY, &error);
  1027. claims_j = json_object_get (root, claims_parameter);
  1028. /* obj is a JSON object */
  1029. if (NULL != claims_j)
  1030. {
  1031. json_object_foreach (claims_j, key, value) {
  1032. if (0 != strcmp (attr_name, key))
  1033. continue;
  1034. ret = GNUNET_YES;
  1035. break;
  1036. }
  1037. }
  1038. json_decref (root);
  1039. }
  1040. return ret;
  1041. }
  1042. static int
  1043. attr_in_idtoken_request (struct RequestHandle *handle,
  1044. const char *attr_name)
  1045. {
  1046. return attr_in_claims_request (handle, attr_name, "id_token");
  1047. }
  1048. static int
  1049. attr_in_userinfo_request (struct RequestHandle *handle,
  1050. const char *attr_name)
  1051. {
  1052. return attr_in_claims_request (handle, attr_name, "userinfo");
  1053. }
  1054. /**
  1055. * Collects all attributes for an ego if in scope parameter
  1056. */
  1057. static void
  1058. oidc_attr_collect (void *cls,
  1059. const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
  1060. const struct GNUNET_RECLAIM_Attribute *attr)
  1061. {
  1062. struct RequestHandle *handle = cls;
  1063. struct GNUNET_RECLAIM_AttributeListEntry *le;
  1064. if (GNUNET_YES == attr_in_idtoken_request (handle, attr->name))
  1065. {
  1066. le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
  1067. le->attribute = GNUNET_RECLAIM_attribute_new (attr->name,
  1068. &attr->attestation,
  1069. attr->type,
  1070. attr->data,
  1071. attr->data_size);
  1072. le->attribute->id = attr->id;
  1073. le->attribute->flag = attr->flag;
  1074. le->attribute->attestation = attr->attestation;
  1075. GNUNET_CONTAINER_DLL_insert (handle->attr_idtoken_list->list_head,
  1076. handle->attr_idtoken_list->list_tail,
  1077. le);
  1078. }
  1079. if (GNUNET_YES == attr_in_userinfo_request (handle, attr->name))
  1080. {
  1081. le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
  1082. le->attribute = GNUNET_RECLAIM_attribute_new (attr->name,
  1083. &attr->attestation,
  1084. attr->type,
  1085. attr->data,
  1086. attr->data_size);
  1087. le->attribute->id = attr->id;
  1088. le->attribute->flag = attr->flag;
  1089. le->attribute->attestation = attr->attestation;
  1090. GNUNET_CONTAINER_DLL_insert (handle->attr_userinfo_list->list_head,
  1091. handle->attr_userinfo_list->list_tail,
  1092. le);
  1093. }
  1094. GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
  1095. }
  1096. /**
  1097. * Checks time and cookie and redirects accordingly
  1098. */
  1099. static void
  1100. code_redirect (void *cls)
  1101. {
  1102. struct RequestHandle *handle = cls;
  1103. struct GNUNET_TIME_Absolute current_time;
  1104. struct GNUNET_TIME_Absolute *relog_time;
  1105. struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
  1106. struct GNUNET_CRYPTO_EcdsaPublicKey ego_pkey;
  1107. struct GNUNET_HashCode cache_key;
  1108. char *identity_cookie;
  1109. GNUNET_asprintf (&identity_cookie,
  1110. "Identity=%s",
  1111. handle->oidc->login_identity);
  1112. GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
  1113. GNUNET_free (identity_cookie);
  1114. // No login time for identity -> redirect to login
  1115. if (GNUNET_YES ==
  1116. GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
  1117. {
  1118. relog_time =
  1119. GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
  1120. current_time = GNUNET_TIME_absolute_get ();
  1121. // 30 min after old login -> redirect to login
  1122. if (current_time.abs_value_us <= relog_time->abs_value_us)
  1123. {
  1124. if (GNUNET_OK !=
  1125. GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc
  1126. ->login_identity,
  1127. strlen (
  1128. handle->oidc
  1129. ->login_identity),
  1130. &pubkey))
  1131. {
  1132. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_COOKIE);
  1133. handle->edesc =
  1134. GNUNET_strdup ("The cookie of a login identity is not valid");
  1135. GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
  1136. return;
  1137. }
  1138. // iterate over egos and compare their public key
  1139. for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
  1140. handle->ego_entry = handle->ego_entry->next)
  1141. {
  1142. GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
  1143. if (0 == GNUNET_memcmp (&ego_pkey, &pubkey))
  1144. {
  1145. handle->priv_key =
  1146. *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
  1147. handle->idp = GNUNET_RECLAIM_connect (cfg);
  1148. handle->attr_idtoken_list =
  1149. GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
  1150. handle->attr_userinfo_list =
  1151. GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
  1152. handle->attr_it =
  1153. GNUNET_RECLAIM_get_attributes_start (handle->idp,
  1154. &handle->priv_key,
  1155. &oidc_iteration_error,
  1156. handle,
  1157. &oidc_attr_collect,
  1158. handle,
  1159. &oidc_attr_collect_finished_cb,
  1160. handle);
  1161. return;
  1162. }
  1163. }
  1164. GNUNET_SCHEDULER_add_now (&login_redirect, handle);
  1165. return;
  1166. }
  1167. }
  1168. }
  1169. static void
  1170. build_redirect (void *cls)
  1171. {
  1172. struct RequestHandle *handle = cls;
  1173. struct MHD_Response *resp;
  1174. char *redirect_uri;
  1175. if (GNUNET_YES == handle->oidc->user_cancelled)
  1176. {
  1177. if ((NULL != handle->redirect_prefix) &&
  1178. (NULL != handle->redirect_suffix) && (NULL != handle->tld))
  1179. {
  1180. GNUNET_asprintf (&redirect_uri,
  1181. "%s.%s/%s?error=%s&error_description=%s&state=%s",
  1182. handle->redirect_prefix,
  1183. handle->tld,
  1184. handle->redirect_suffix,
  1185. "access_denied",
  1186. "User denied access",
  1187. handle->oidc->state);
  1188. }
  1189. else
  1190. {
  1191. GNUNET_asprintf (&redirect_uri,
  1192. "%s?error=%s&error_description=%s&state=%s",
  1193. handle->oidc->redirect_uri,
  1194. "access_denied",
  1195. "User denied access",
  1196. handle->oidc->state);
  1197. }
  1198. resp = GNUNET_REST_create_response ("");
  1199. MHD_add_response_header (resp, "Location", redirect_uri);
  1200. handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
  1201. GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
  1202. GNUNET_free (redirect_uri);
  1203. return;
  1204. }
  1205. GNUNET_SCHEDULER_add_now (&code_redirect, handle);
  1206. }
  1207. static void
  1208. lookup_redirect_uri_result (void *cls,
  1209. uint32_t rd_count,
  1210. const struct GNUNET_GNSRECORD_Data *rd)
  1211. {
  1212. struct RequestHandle *handle = cls;
  1213. char *tmp;
  1214. char *tmp_key_str;
  1215. char *pos;
  1216. struct GNUNET_CRYPTO_EcdsaPublicKey redirect_zone;
  1217. handle->gns_op = NULL;
  1218. if (0 == rd_count)
  1219. {
  1220. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
  1221. handle->edesc =
  1222. GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
  1223. GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
  1224. return;
  1225. }
  1226. for (int i = 0; i < rd_count; i++)
  1227. {
  1228. if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type)
  1229. continue;
  1230. if (0 != strncmp (rd[i].data, handle->oidc->redirect_uri, rd[i].data_size))
  1231. continue;
  1232. tmp = GNUNET_strndup (rd[i].data, rd[i].data_size);
  1233. if (NULL == strstr (tmp, handle->oidc->client_id))
  1234. {
  1235. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1236. "Redirect uri %s does not contain client_id %s\n",
  1237. tmp,
  1238. handle->oidc->client_id);
  1239. }
  1240. else
  1241. {
  1242. pos = strrchr (tmp, (unsigned char) '.');
  1243. if (NULL == pos)
  1244. {
  1245. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1246. "Redirect uri %s contains client_id but is malformed\n",
  1247. tmp);
  1248. GNUNET_free (tmp);
  1249. continue;
  1250. }
  1251. *pos = '\0';
  1252. handle->redirect_prefix = GNUNET_strdup (tmp);
  1253. tmp_key_str = pos + 1;
  1254. pos = strchr (tmp_key_str, (unsigned char) '/');
  1255. if (NULL == pos)
  1256. {
  1257. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1258. "Redirect uri %s contains client_id but is malformed\n",
  1259. tmp);
  1260. GNUNET_free (tmp);
  1261. continue;
  1262. }
  1263. *pos = '\0';
  1264. handle->redirect_suffix = GNUNET_strdup (pos + 1);
  1265. GNUNET_STRINGS_string_to_data (tmp_key_str,
  1266. strlen (tmp_key_str),
  1267. &redirect_zone,
  1268. sizeof(redirect_zone));
  1269. }
  1270. GNUNET_SCHEDULER_add_now (&build_redirect, handle);
  1271. GNUNET_free (tmp);
  1272. return;
  1273. }
  1274. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
  1275. handle->edesc =
  1276. GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
  1277. GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
  1278. }
  1279. /**
  1280. * Initiate redirect back to client.
  1281. */
  1282. static void
  1283. client_redirect (void *cls)
  1284. {
  1285. struct RequestHandle *handle = cls;
  1286. /* Lookup client redirect uri to verify request */
  1287. handle->gns_op =
  1288. GNUNET_GNS_lookup (handle->gns_handle,
  1289. GNUNET_GNS_EMPTY_LABEL_AT,
  1290. &handle->oidc->client_pkey,
  1291. GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT,
  1292. GNUNET_GNS_LO_DEFAULT,
  1293. &lookup_redirect_uri_result,
  1294. handle);
  1295. }
  1296. static char *
  1297. get_url_parameter_copy (const struct RequestHandle *handle, const char *key)
  1298. {
  1299. struct GNUNET_HashCode hc;
  1300. char *value;
  1301. GNUNET_CRYPTO_hash (key, strlen (key), &hc);
  1302. if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
  1303. ->url_param_map,
  1304. &hc))
  1305. return NULL;
  1306. value =
  1307. GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, &hc);
  1308. if (NULL == value)
  1309. return NULL;
  1310. return GNUNET_strdup (value);
  1311. }
  1312. /**
  1313. * Iteration over all results finished, build final
  1314. * response.
  1315. *
  1316. * @param cls the `struct RequestHandle`
  1317. */
  1318. static void
  1319. build_authz_response (void *cls)
  1320. {
  1321. struct RequestHandle *handle = cls;
  1322. struct GNUNET_HashCode cache_key;
  1323. char *expected_scope;
  1324. char delimiter[] = " ";
  1325. int number_of_ignored_parameter, iterator;
  1326. // REQUIRED value: redirect_uri
  1327. handle->oidc->redirect_uri =
  1328. get_url_parameter_copy (handle, OIDC_REDIRECT_URI_KEY);
  1329. if (NULL == handle->oidc->redirect_uri)
  1330. {
  1331. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
  1332. handle->edesc = GNUNET_strdup ("missing parameter redirect_uri");
  1333. GNUNET_SCHEDULER_add_now (&do_error, handle);
  1334. return;
  1335. }
  1336. // REQUIRED value: response_type
  1337. handle->oidc->response_type =
  1338. get_url_parameter_copy (handle, OIDC_RESPONSE_TYPE_KEY);
  1339. if (NULL == handle->oidc->response_type)
  1340. {
  1341. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
  1342. handle->edesc = GNUNET_strdup ("missing parameter response_type");
  1343. GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
  1344. return;
  1345. }
  1346. // REQUIRED value: scope
  1347. handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
  1348. if (NULL == handle->oidc->scope)
  1349. {
  1350. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE);
  1351. handle->edesc = GNUNET_strdup ("missing parameter scope");
  1352. GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
  1353. return;
  1354. }
  1355. // OPTIONAL value: nonce
  1356. handle->oidc->nonce = get_url_parameter_copy (handle, OIDC_NONCE_KEY);
  1357. // OPTIONAL value: claims
  1358. handle->oidc->claims = get_url_parameter_copy (handle, OIDC_CLAIMS_KEY);
  1359. // TODO check other values if needed
  1360. number_of_ignored_parameter =
  1361. sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
  1362. for (iterator = 0; iterator < number_of_ignored_parameter; iterator++)
  1363. {
  1364. GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
  1365. strlen (OIDC_ignored_parameter_array[iterator]),
  1366. &cache_key);
  1367. if (GNUNET_YES ==
  1368. GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
  1369. ->url_param_map,
  1370. &cache_key))
  1371. {
  1372. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_ACCESS_DENIED);
  1373. GNUNET_asprintf (&handle->edesc,
  1374. "Server will not handle parameter: %s",
  1375. OIDC_ignored_parameter_array[iterator]);
  1376. GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
  1377. return;
  1378. }
  1379. }
  1380. // We only support authorization code flows.
  1381. if (0 != strcmp (handle->oidc->response_type,
  1382. OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE))
  1383. {
  1384. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE);
  1385. handle->edesc = GNUNET_strdup ("The authorization server does not support "
  1386. "obtaining this authorization code.");
  1387. GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
  1388. return;
  1389. }
  1390. // Checks if scope contains 'openid'
  1391. expected_scope = GNUNET_strdup (handle->oidc->scope);
  1392. char *test;
  1393. test = strtok (expected_scope, delimiter);
  1394. while (NULL != test)
  1395. {
  1396. if (0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope))
  1397. break;
  1398. test = strtok (NULL, delimiter);
  1399. }
  1400. if (NULL == test)
  1401. {
  1402. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE);
  1403. handle->edesc =
  1404. GNUNET_strdup ("The requested scope is invalid, unknown, or malformed.");
  1405. GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
  1406. GNUNET_free (expected_scope);
  1407. return;
  1408. }
  1409. GNUNET_free (expected_scope);
  1410. if ((NULL == handle->oidc->login_identity) &&
  1411. (GNUNET_NO == handle->oidc->user_cancelled))
  1412. GNUNET_SCHEDULER_add_now (&login_redirect, handle);
  1413. else
  1414. GNUNET_SCHEDULER_add_now (&client_redirect, handle);
  1415. }
  1416. /**
  1417. * Iterate over tlds in config
  1418. */
  1419. static void
  1420. tld_iter (void *cls, const char *section, const char *option, const char *value)
  1421. {
  1422. struct RequestHandle *handle = cls;
  1423. struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
  1424. if (GNUNET_OK !=
  1425. GNUNET_CRYPTO_ecdsa_public_key_from_string (value, strlen (value), &pkey))
  1426. {
  1427. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping non key %s\n", value);
  1428. return;
  1429. }
  1430. if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
  1431. handle->tld = GNUNET_strdup (option + 1);
  1432. }
  1433. /**
  1434. * Responds to authorization GET and url-encoded POST request
  1435. *
  1436. * @param con_handle the connection handle
  1437. * @param url the url
  1438. * @param cls the RequestHandle
  1439. */
  1440. static void
  1441. authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
  1442. const char *url,
  1443. void *cls)
  1444. {
  1445. struct RequestHandle *handle = cls;
  1446. struct EgoEntry *tmp_ego;
  1447. const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
  1448. struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
  1449. cookie_identity_interpretation (handle);
  1450. // RECOMMENDED value: state - REQUIRED for answers
  1451. handle->oidc->state = get_url_parameter_copy (handle, OIDC_STATE_KEY);
  1452. // REQUIRED value: client_id
  1453. handle->oidc->client_id = get_url_parameter_copy (handle, OIDC_CLIENT_ID_KEY);
  1454. if (NULL == handle->oidc->client_id)
  1455. {
  1456. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
  1457. handle->edesc = GNUNET_strdup ("missing parameter client_id");
  1458. handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
  1459. GNUNET_SCHEDULER_add_now (&do_error, handle);
  1460. return;
  1461. }
  1462. // OPTIONAL value: code_challenge
  1463. handle->oidc->code_challenge = get_url_parameter_copy (handle,
  1464. OIDC_CODE_CHALLENGE_KEY);
  1465. if (NULL == handle->oidc->code_challenge)
  1466. {
  1467. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1468. "OAuth authorization request does not contain PKCE parameters!\n");
  1469. }
  1470. if (GNUNET_OK !=
  1471. GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
  1472. strlen (
  1473. handle->oidc->client_id),
  1474. &handle->oidc->client_pkey))
  1475. {
  1476. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT);
  1477. handle->edesc = GNUNET_strdup ("The client is not authorized to request an "
  1478. "authorization code using this method.");
  1479. handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
  1480. GNUNET_SCHEDULER_add_now (&do_error, handle);
  1481. return;
  1482. }
  1483. // If we know this identity, translated the corresponding TLD
  1484. // TODO: We might want to have a reverse lookup functionality for TLDs?
  1485. for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
  1486. {
  1487. priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
  1488. GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, &pkey);
  1489. if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
  1490. {
  1491. handle->tld = GNUNET_strdup (tmp_ego->identifier);
  1492. handle->ego_entry = handle->ego_tail;
  1493. }
  1494. }
  1495. handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
  1496. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scope: %s\n", handle->oidc->scope);
  1497. if (NULL == handle->tld)
  1498. GNUNET_CONFIGURATION_iterate_section_values (cfg, "gns", tld_iter, handle);
  1499. if (NULL == handle->tld)
  1500. handle->tld = GNUNET_strdup (handle->oidc->client_id);
  1501. GNUNET_SCHEDULER_add_now (&build_authz_response, handle);
  1502. }
  1503. /**
  1504. * Combines an identity with a login time and responds OK to login request
  1505. *
  1506. * @param con_handle the connection handle
  1507. * @param url the url
  1508. * @param cls the RequestHandle
  1509. */
  1510. static void
  1511. login_cont (struct GNUNET_REST_RequestHandle *con_handle,
  1512. const char *url,
  1513. void *cls)
  1514. {
  1515. struct MHD_Response *resp = GNUNET_REST_create_response ("");
  1516. struct RequestHandle *handle = cls;
  1517. struct GNUNET_HashCode cache_key;
  1518. struct GNUNET_TIME_Absolute *current_time;
  1519. struct GNUNET_TIME_Absolute *last_time;
  1520. char *cookie;
  1521. char *header_val;
  1522. json_t *root;
  1523. json_error_t error;
  1524. json_t *identity;
  1525. char term_data[handle->rest_handle->data_size + 1];
  1526. term_data[handle->rest_handle->data_size] = '\0';
  1527. GNUNET_memcpy (term_data,
  1528. handle->rest_handle->data,
  1529. handle->rest_handle->data_size);
  1530. root = json_loads (term_data, JSON_DECODE_ANY, &error);
  1531. identity = json_object_get (root, "identity");
  1532. if (! json_is_string (identity))
  1533. {
  1534. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  1535. "Error parsing json string from %s\n",
  1536. term_data);
  1537. handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
  1538. json_decref (root);
  1539. GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
  1540. return;
  1541. }
  1542. GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
  1543. GNUNET_asprintf (&header_val,
  1544. "%s;Max-Age=%d",
  1545. cookie,
  1546. OIDC_COOKIE_EXPIRATION);
  1547. MHD_add_response_header (resp, "Set-Cookie", header_val);
  1548. MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST");
  1549. GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
  1550. if (0 != strcmp (json_string_value (identity), "Denied"))
  1551. {
  1552. current_time = GNUNET_new (struct GNUNET_TIME_Absolute);
  1553. *current_time = GNUNET_TIME_relative_to_absolute (
  1554. GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (),
  1555. OIDC_COOKIE_EXPIRATION));
  1556. last_time =
  1557. GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
  1558. GNUNET_free (last_time);
  1559. GNUNET_CONTAINER_multihashmap_put (OIDC_cookie_jar_map,
  1560. &cache_key,
  1561. current_time,
  1562. GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
  1563. }
  1564. handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
  1565. GNUNET_free (cookie);
  1566. GNUNET_free (header_val);
  1567. json_decref (root);
  1568. GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
  1569. }
  1570. static int
  1571. check_authorization (struct RequestHandle *handle,
  1572. struct GNUNET_CRYPTO_EcdsaPublicKey *cid)
  1573. {
  1574. struct GNUNET_HashCode cache_key;
  1575. char *authorization;
  1576. char *credentials;
  1577. char *basic_authorization;
  1578. char *client_id;
  1579. char *pass;
  1580. char *expected_pass;
  1581. GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
  1582. strlen (OIDC_AUTHORIZATION_HEADER_KEY),
  1583. &cache_key);
  1584. if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
  1585. ->header_param_map,
  1586. &cache_key))
  1587. {
  1588. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
  1589. handle->edesc = GNUNET_strdup ("missing authorization");
  1590. handle->response_code = MHD_HTTP_UNAUTHORIZED;
  1591. return GNUNET_SYSERR;
  1592. }
  1593. authorization =
  1594. GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
  1595. &cache_key);
  1596. // split header in "Basic" and [content]
  1597. credentials = strtok (authorization, " ");
  1598. if ((NULL == credentials) || (0 != strcmp ("Basic", credentials)))
  1599. {
  1600. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
  1601. handle->response_code = MHD_HTTP_UNAUTHORIZED;
  1602. return GNUNET_SYSERR;
  1603. }
  1604. credentials = strtok (NULL, " ");
  1605. if (NULL == credentials)
  1606. {
  1607. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
  1608. handle->response_code = MHD_HTTP_UNAUTHORIZED;
  1609. return GNUNET_SYSERR;
  1610. }
  1611. GNUNET_STRINGS_base64_decode (credentials,
  1612. strlen (credentials),
  1613. (void **) &basic_authorization);
  1614. if (NULL == basic_authorization)
  1615. {
  1616. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
  1617. handle->response_code = MHD_HTTP_UNAUTHORIZED;
  1618. return GNUNET_SYSERR;
  1619. }
  1620. client_id = strtok (basic_authorization, ":");
  1621. if (NULL == client_id)
  1622. {
  1623. GNUNET_free (basic_authorization);
  1624. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
  1625. handle->response_code = MHD_HTTP_UNAUTHORIZED;
  1626. return GNUNET_SYSERR;
  1627. }
  1628. pass = strtok (NULL, ":");
  1629. if (NULL == pass)
  1630. {
  1631. GNUNET_free (basic_authorization);
  1632. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
  1633. handle->response_code = MHD_HTTP_UNAUTHORIZED;
  1634. return GNUNET_SYSERR;
  1635. }
  1636. // check client password
  1637. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
  1638. "reclaim-rest-plugin",
  1639. "OIDC_CLIENT_SECRET",
  1640. &expected_pass))
  1641. {
  1642. if (0 != strcmp (expected_pass, pass))
  1643. {
  1644. GNUNET_free (basic_authorization);
  1645. GNUNET_free (expected_pass);
  1646. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
  1647. handle->response_code = MHD_HTTP_UNAUTHORIZED;
  1648. return GNUNET_SYSERR;
  1649. }
  1650. GNUNET_free (expected_pass);
  1651. }
  1652. else
  1653. {
  1654. GNUNET_free (basic_authorization);
  1655. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
  1656. handle->edesc = GNUNET_strdup ("gnunet configuration failed");
  1657. handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
  1658. return GNUNET_SYSERR;
  1659. }
  1660. // check client_id
  1661. for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
  1662. handle->ego_entry = handle->ego_entry->next)
  1663. {
  1664. if (0 == strcmp (handle->ego_entry->keystring, client_id))
  1665. break;
  1666. }
  1667. if (NULL == handle->ego_entry)
  1668. {
  1669. GNUNET_free (basic_authorization);
  1670. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
  1671. handle->response_code = MHD_HTTP_UNAUTHORIZED;
  1672. return GNUNET_SYSERR;
  1673. }
  1674. GNUNET_STRINGS_string_to_data (client_id,
  1675. strlen (client_id),
  1676. cid,
  1677. sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
  1678. GNUNET_free (basic_authorization);
  1679. return GNUNET_OK;
  1680. }
  1681. const struct EgoEntry *
  1682. find_ego (struct RequestHandle *handle,
  1683. struct GNUNET_CRYPTO_EcdsaPublicKey *test_key)
  1684. {
  1685. struct EgoEntry *ego_entry;
  1686. struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
  1687. for (ego_entry = handle->ego_head; NULL != ego_entry;
  1688. ego_entry = ego_entry->next)
  1689. {
  1690. GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
  1691. if (0 == GNUNET_memcmp (&pub_key, test_key))
  1692. return ego_entry;
  1693. }
  1694. return NULL;
  1695. }
  1696. static void
  1697. persist_access_token (const struct RequestHandle *handle,
  1698. const char *access_token,
  1699. const struct GNUNET_RECLAIM_Ticket *ticket)
  1700. {
  1701. struct GNUNET_HashCode hc;
  1702. struct GNUNET_RECLAIM_Ticket *ticketbuf;
  1703. GNUNET_CRYPTO_hash (access_token, strlen (access_token), &hc);
  1704. ticketbuf = GNUNET_new (struct GNUNET_RECLAIM_Ticket);
  1705. *ticketbuf = *ticket;
  1706. GNUNET_assert (GNUNET_SYSERR !=
  1707. GNUNET_CONTAINER_multihashmap_put (
  1708. OIDC_access_token_map,
  1709. &hc,
  1710. ticketbuf,
  1711. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  1712. }
  1713. /**
  1714. * Responds to token url-encoded POST request
  1715. *
  1716. * @param con_handle the connection handle
  1717. * @param url the url
  1718. * @param cls the RequestHandle
  1719. */
  1720. static void
  1721. token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
  1722. const char *url,
  1723. void *cls)
  1724. {
  1725. struct RequestHandle *handle = cls;
  1726. const struct EgoEntry *ego_entry;
  1727. struct GNUNET_TIME_Relative expiration_time;
  1728. struct GNUNET_RECLAIM_AttributeList *cl = NULL;
  1729. struct GNUNET_RECLAIM_AttestationList *al = NULL;
  1730. struct GNUNET_RECLAIM_Ticket ticket;
  1731. struct GNUNET_CRYPTO_EcdsaPublicKey cid;
  1732. const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
  1733. struct GNUNET_HashCode cache_key;
  1734. struct MHD_Response *resp;
  1735. char *grant_type;
  1736. char *code;
  1737. char *json_response;
  1738. char *id_token;
  1739. char *access_token;
  1740. char *jwt_secret;
  1741. char *nonce;
  1742. char *code_verifier;
  1743. /*
  1744. * Check Authorization
  1745. */
  1746. if (GNUNET_SYSERR == check_authorization (handle, &cid))
  1747. {
  1748. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  1749. "OIDC authorization for token endpoint failed\n");
  1750. GNUNET_SCHEDULER_add_now (&do_error, handle);
  1751. return;
  1752. }
  1753. /*
  1754. * Check parameter
  1755. */
  1756. // TODO Do not allow multiple equal parameter names
  1757. // REQUIRED grant_type
  1758. GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY,
  1759. strlen (OIDC_GRANT_TYPE_KEY),
  1760. &cache_key);
  1761. grant_type = get_url_parameter_copy (handle, OIDC_GRANT_TYPE_KEY);
  1762. if (NULL == grant_type)
  1763. {
  1764. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
  1765. handle->edesc = GNUNET_strdup ("missing parameter grant_type");
  1766. handle->response_code = MHD_HTTP_BAD_REQUEST;
  1767. GNUNET_SCHEDULER_add_now (&do_error, handle);
  1768. return;
  1769. }
  1770. // Check parameter grant_type == "authorization_code"
  1771. if (0 != strcmp (OIDC_GRANT_TYPE_VALUE, grant_type))
  1772. {
  1773. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE);
  1774. handle->response_code = MHD_HTTP_BAD_REQUEST;
  1775. GNUNET_free (grant_type);
  1776. GNUNET_SCHEDULER_add_now (&do_error, handle);
  1777. return;
  1778. }
  1779. GNUNET_free (grant_type);
  1780. // REQUIRED code
  1781. code = get_url_parameter_copy (handle, OIDC_CODE_KEY);
  1782. if (NULL == code)
  1783. {
  1784. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
  1785. handle->edesc = GNUNET_strdup ("missing parameter code");
  1786. handle->response_code = MHD_HTTP_BAD_REQUEST;
  1787. GNUNET_SCHEDULER_add_now (&do_error, handle);
  1788. return;
  1789. }
  1790. ego_entry = find_ego (handle, &cid);
  1791. if (NULL == ego_entry)
  1792. {
  1793. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
  1794. handle->edesc = GNUNET_strdup ("Unknown client");
  1795. handle->response_code = MHD_HTTP_BAD_REQUEST;
  1796. GNUNET_free (code);
  1797. GNUNET_SCHEDULER_add_now (&do_error, handle);
  1798. return;
  1799. }
  1800. privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
  1801. // REQUIRED code verifier
  1802. code_verifier = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY);
  1803. if (NULL == code_verifier)
  1804. {
  1805. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1806. "OAuth authorization request does not contain PKCE parameters!\n");
  1807. }
  1808. // decode code
  1809. if (GNUNET_OK != OIDC_parse_authz_code (privkey, code, code_verifier, &ticket,
  1810. &cl, &al, &nonce))
  1811. {
  1812. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
  1813. handle->edesc = GNUNET_strdup ("invalid code");
  1814. handle->response_code = MHD_HTTP_BAD_REQUEST;
  1815. GNUNET_free (code);
  1816. GNUNET_SCHEDULER_add_now (&do_error, handle);
  1817. return;
  1818. }
  1819. GNUNET_free (code);
  1820. // create jwt
  1821. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
  1822. "reclaim-rest-plugin",
  1823. "expiration_time",
  1824. &expiration_time))
  1825. {
  1826. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
  1827. handle->edesc = GNUNET_strdup ("gnunet configuration failed");
  1828. handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
  1829. GNUNET_SCHEDULER_add_now (&do_error, handle);
  1830. return;
  1831. }
  1832. // TODO OPTIONAL acr,amr,azp
  1833. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
  1834. "reclaim-rest-plugin",
  1835. "jwt_secret",
  1836. &jwt_secret))
  1837. {
  1838. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
  1839. handle->edesc = GNUNET_strdup ("No signing secret configured!");
  1840. handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
  1841. GNUNET_SCHEDULER_add_now (&do_error, handle);
  1842. return;
  1843. }
  1844. id_token = OIDC_id_token_new (&ticket.audience,
  1845. &ticket.identity,
  1846. cl,
  1847. al,
  1848. &expiration_time,
  1849. (NULL != nonce) ? nonce : NULL,
  1850. jwt_secret);
  1851. access_token = OIDC_access_token_new ();
  1852. OIDC_build_token_response (access_token,
  1853. id_token,
  1854. &expiration_time,
  1855. &json_response);
  1856. persist_access_token (handle, access_token, &ticket);
  1857. resp = GNUNET_REST_create_response (json_response);
  1858. MHD_add_response_header (resp, "Cache-Control", "no-store");
  1859. MHD_add_response_header (resp, "Pragma", "no-cache");
  1860. MHD_add_response_header (resp, "Content-Type", "application/json");
  1861. handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
  1862. GNUNET_RECLAIM_attribute_list_destroy (cl);
  1863. GNUNET_RECLAIM_attestation_list_destroy (al);
  1864. GNUNET_free (access_token);
  1865. GNUNET_free (json_response);
  1866. GNUNET_free (id_token);
  1867. GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
  1868. }
  1869. /**
  1870. * Collects claims and stores them in handle
  1871. */
  1872. static void
  1873. consume_ticket (void *cls,
  1874. const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
  1875. const struct GNUNET_RECLAIM_Attribute *attr,
  1876. const struct GNUNET_RECLAIM_Attestation *attest)
  1877. {
  1878. struct RequestHandle *handle = cls;
  1879. handle->idp_op = NULL;
  1880. if (NULL == identity)
  1881. {
  1882. GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle);
  1883. return;
  1884. }
  1885. if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attr->attestation))
  1886. {
  1887. char *tmp_value;
  1888. json_t *value;
  1889. tmp_value = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
  1890. attr->data,
  1891. attr->data_size);
  1892. value = json_string (tmp_value);
  1893. json_object_set_new (handle->oidc->response, attr->name, value);
  1894. GNUNET_free (tmp_value);
  1895. return;
  1896. }
  1897. json_t *claim_sources;
  1898. json_t *claim_sources_jwt;
  1899. json_t *claim_names;
  1900. char *attest_val_str;
  1901. claim_sources = json_object_get (handle->oidc->response,"_claim_sources");
  1902. claim_names = json_object_get (handle->oidc->response,"_claim_names");
  1903. attest_val_str =
  1904. GNUNET_RECLAIM_attestation_value_to_string (attest->type,
  1905. attest->data,
  1906. attest->data_size);
  1907. if ((NULL == claim_sources) && (NULL == claim_names) )
  1908. {
  1909. claim_sources = json_object ();
  1910. claim_names = json_object ();
  1911. }
  1912. char *source_name;
  1913. int i = 0;
  1914. GNUNET_asprintf (&source_name, "src%d", i);
  1915. while (NULL != (claim_sources_jwt = json_object_get (claim_sources,
  1916. source_name)))
  1917. {
  1918. if (0 == strcmp (json_string_value (json_object_get (claim_sources_jwt,
  1919. "JWT")),
  1920. attest_val_str))
  1921. {
  1922. // Adapt only the claim names
  1923. json_object_set_new (claim_names, attr->data,
  1924. json_string (source_name));
  1925. json_object_set (handle->oidc->response,
  1926. "_claim_names", claim_names);
  1927. break;
  1928. }
  1929. i++;
  1930. GNUNET_free (source_name);
  1931. GNUNET_asprintf (&source_name, "src%d", i);
  1932. }
  1933. // Create new one
  1934. if (NULL == claim_sources_jwt)
  1935. {
  1936. claim_sources_jwt = json_object ();
  1937. // Set the JWT for names
  1938. json_object_set_new (claim_names, attr->data,
  1939. json_string (source_name));
  1940. // Set the JWT for the inner source
  1941. json_object_set_new (claim_sources_jwt, "JWT",
  1942. json_string (attest_val_str));
  1943. // Set the JWT for the source
  1944. json_object_set_new (claim_sources, source_name, claim_sources_jwt);
  1945. // Set as claims
  1946. json_object_set (handle->oidc->response, "_claim_names", claim_names);
  1947. json_object_set (handle->oidc->response, "_claim_sources",claim_sources);
  1948. }
  1949. json_decref (claim_sources);
  1950. json_decref (claim_names);
  1951. json_decref (claim_sources_jwt);
  1952. GNUNET_free (attest_val_str);
  1953. }
  1954. /**
  1955. * Responds to userinfo GET and url-encoded POST request
  1956. *
  1957. * @param con_handle the connection handle
  1958. * @param url the url
  1959. * @param cls the RequestHandle
  1960. */
  1961. static void
  1962. userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
  1963. const char *url,
  1964. void *cls)
  1965. {
  1966. // TODO expiration time
  1967. struct RequestHandle *handle = cls;
  1968. char delimiter[] = " ";
  1969. struct GNUNET_HashCode cache_key;
  1970. char *authorization;
  1971. char *authorization_type;
  1972. char *authorization_access_token;
  1973. struct GNUNET_RECLAIM_Ticket *ticket;
  1974. const struct EgoEntry *ego_entry;
  1975. const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
  1976. GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
  1977. strlen (OIDC_AUTHORIZATION_HEADER_KEY),
  1978. &cache_key);
  1979. if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
  1980. ->header_param_map,
  1981. &cache_key))
  1982. {
  1983. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
  1984. handle->edesc = GNUNET_strdup ("No Access Token");
  1985. handle->response_code = MHD_HTTP_UNAUTHORIZED;
  1986. GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
  1987. return;
  1988. }
  1989. authorization =
  1990. GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
  1991. &cache_key);
  1992. // split header in "Bearer" and access_token
  1993. authorization = GNUNET_strdup (authorization);
  1994. authorization_type = strtok (authorization, delimiter);
  1995. if ((NULL == authorization_type) ||
  1996. (0 != strcmp ("Bearer", authorization_type)))
  1997. {
  1998. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
  1999. handle->edesc = GNUNET_strdup ("No Access Token");
  2000. handle->response_code = MHD_HTTP_UNAUTHORIZED;
  2001. GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
  2002. GNUNET_free (authorization);
  2003. return;
  2004. }
  2005. authorization_access_token = strtok (NULL, delimiter);
  2006. if (NULL == authorization_access_token)
  2007. {
  2008. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
  2009. handle->edesc = GNUNET_strdup ("Access token missing");
  2010. handle->response_code = MHD_HTTP_UNAUTHORIZED;
  2011. GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
  2012. GNUNET_free (authorization);
  2013. return;
  2014. }
  2015. GNUNET_CRYPTO_hash (authorization_access_token,
  2016. strlen (authorization_access_token),
  2017. &cache_key);
  2018. if (GNUNET_NO ==
  2019. GNUNET_CONTAINER_multihashmap_contains (OIDC_access_token_map,
  2020. &cache_key))
  2021. {
  2022. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
  2023. handle->edesc = GNUNET_strdup ("The access token expired");
  2024. handle->response_code = MHD_HTTP_UNAUTHORIZED;
  2025. GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
  2026. GNUNET_free (authorization);
  2027. return;
  2028. }
  2029. ticket =
  2030. GNUNET_CONTAINER_multihashmap_get (OIDC_access_token_map, &cache_key);
  2031. GNUNET_assert (NULL != ticket);
  2032. ego_entry = find_ego (handle, &ticket->audience);
  2033. if (NULL == ego_entry)
  2034. {
  2035. handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
  2036. handle->edesc = GNUNET_strdup ("The access token expired");
  2037. handle->response_code = MHD_HTTP_UNAUTHORIZED;
  2038. GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
  2039. GNUNET_free (authorization);
  2040. return;
  2041. }
  2042. handle->idp = GNUNET_RECLAIM_connect (cfg);
  2043. handle->oidc->response = json_object ();
  2044. json_object_set_new (handle->oidc->response,
  2045. "sub",
  2046. json_string (ego_entry->keystring));
  2047. privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
  2048. handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
  2049. privkey,
  2050. ticket,
  2051. consume_ticket,
  2052. handle);
  2053. GNUNET_free (authorization);
  2054. }
  2055. /**
  2056. * Handle rest request
  2057. *
  2058. * @param handle the request handle
  2059. */
  2060. static void
  2061. init_cont (struct RequestHandle *handle)
  2062. {
  2063. struct GNUNET_REST_RequestHandlerError err;
  2064. static const struct GNUNET_REST_RequestHandler handlers[] =
  2065. { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint },
  2066. { MHD_HTTP_METHOD_POST,
  2067. GNUNET_REST_API_NS_AUTHORIZE,
  2068. &authorize_endpoint }, // url-encoded
  2069. { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont },
  2070. { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
  2071. { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
  2072. { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
  2073. { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, &options_cont },
  2074. GNUNET_REST_HANDLER_END };
  2075. if (GNUNET_NO ==
  2076. GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
  2077. {
  2078. handle->response_code = err.error_code;
  2079. GNUNET_SCHEDULER_add_now (&do_error, handle);
  2080. }
  2081. }
  2082. /**
  2083. * If listing is enabled, prints information about the egos.
  2084. *
  2085. * This function is initially called for all egos and then again
  2086. * whenever a ego's identifier changes or if it is deleted. At the
  2087. * end of the initial pass over all egos, the function is once called
  2088. * with 'NULL' for 'ego'. That does NOT mean that the callback won't
  2089. * be invoked in the future or that there was an error.
  2090. *
  2091. * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
  2092. * this function is only called ONCE, and 'NULL' being passed in
  2093. * 'ego' does indicate an error (i.e. name is taken or no default
  2094. * value is known). If 'ego' is non-NULL and if '*ctx'
  2095. * is set in those callbacks, the value WILL be passed to a subsequent
  2096. * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
  2097. * that one was not NULL).
  2098. *
  2099. * When an identity is renamed, this function is called with the
  2100. * (known) ego but the NEW identifier.
  2101. *
  2102. * When an identity is deleted, this function is called with the
  2103. * (known) ego and "NULL" for the 'identifier'. In this case,
  2104. * the 'ego' is henceforth invalid (and the 'ctx' should also be
  2105. * cleaned up).
  2106. *
  2107. * @param cls closure
  2108. * @param ego ego handle
  2109. * @param ctx context for application to store data for this ego
  2110. * (during the lifetime of this process, initially NULL)
  2111. * @param identifier identifier assigned by the user for this ego,
  2112. * NULL if the user just deleted the ego and it
  2113. * must thus no longer be used
  2114. */
  2115. static void
  2116. list_ego (void *cls,
  2117. struct GNUNET_IDENTITY_Ego *ego,
  2118. void **ctx,
  2119. const char *identifier)
  2120. {
  2121. struct RequestHandle *handle = cls;
  2122. struct EgoEntry *ego_entry;
  2123. struct GNUNET_CRYPTO_EcdsaPublicKey pk;
  2124. if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
  2125. {
  2126. handle->state = ID_REST_STATE_POST_INIT;
  2127. init_cont (handle);
  2128. return;
  2129. }
  2130. GNUNET_assert (NULL != ego);
  2131. if (ID_REST_STATE_INIT == handle->state)
  2132. {
  2133. ego_entry = GNUNET_new (struct EgoEntry);
  2134. GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
  2135. ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
  2136. ego_entry->ego = ego;
  2137. ego_entry->identifier = GNUNET_strdup (identifier);
  2138. GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
  2139. handle->ego_tail,
  2140. ego_entry);
  2141. return;
  2142. }
  2143. /* Ego renamed or added */
  2144. if (identifier != NULL)
  2145. {
  2146. for (ego_entry = handle->ego_head; NULL != ego_entry;
  2147. ego_entry = ego_entry->next)
  2148. {
  2149. if (ego_entry->ego == ego)
  2150. {
  2151. /* Rename */
  2152. GNUNET_free (ego_entry->identifier);
  2153. ego_entry->identifier = GNUNET_strdup (identifier);
  2154. break;
  2155. }
  2156. }
  2157. if (NULL == ego_entry)
  2158. {
  2159. /* Add */
  2160. ego_entry = GNUNET_new (struct EgoEntry);
  2161. GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
  2162. ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
  2163. ego_entry->ego = ego;
  2164. ego_entry->identifier = GNUNET_strdup (identifier);
  2165. GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
  2166. handle->ego_tail,
  2167. ego_entry);
  2168. }
  2169. }
  2170. else
  2171. {
  2172. /* Delete */
  2173. for (ego_entry = handle->ego_head; NULL != ego_entry;
  2174. ego_entry = ego_entry->next)
  2175. {
  2176. if (ego_entry->ego == ego)
  2177. break;
  2178. }
  2179. if (NULL == ego_entry)
  2180. return; /* Not found */
  2181. GNUNET_CONTAINER_DLL_remove (handle->ego_head,
  2182. handle->ego_tail,
  2183. ego_entry);
  2184. GNUNET_free (ego_entry->identifier);
  2185. GNUNET_free (ego_entry->keystring);
  2186. GNUNET_free (ego_entry);
  2187. return;
  2188. }
  2189. }
  2190. static void
  2191. rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
  2192. GNUNET_REST_ResultProcessor proc,
  2193. void *proc_cls)
  2194. {
  2195. struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
  2196. handle->oidc = GNUNET_new (struct OIDC_Variables);
  2197. if (NULL == OIDC_cookie_jar_map)
  2198. OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10,
  2199. GNUNET_NO);
  2200. if (NULL == OIDC_access_token_map)
  2201. OIDC_access_token_map =
  2202. GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
  2203. handle->response_code = 0;
  2204. handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
  2205. handle->proc_cls = proc_cls;
  2206. handle->proc = proc;
  2207. handle->state = ID_REST_STATE_INIT;
  2208. handle->rest_handle = rest_handle;
  2209. handle->url = GNUNET_strdup (rest_handle->url);
  2210. if (handle->url[strlen (handle->url) - 1] == '/')
  2211. handle->url[strlen (handle->url) - 1] = '\0';
  2212. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
  2213. handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
  2214. handle->gns_handle = GNUNET_GNS_connect (cfg);
  2215. handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
  2216. handle->timeout_task =
  2217. GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
  2218. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
  2219. }
  2220. /**
  2221. * Entry point for the plugin.
  2222. *
  2223. * @param cls Config info
  2224. * @return NULL on error, otherwise the plugin context
  2225. */
  2226. void *
  2227. libgnunet_plugin_rest_openid_connect_init (void *cls)
  2228. {
  2229. static struct Plugin plugin;
  2230. struct GNUNET_REST_Plugin *api;
  2231. cfg = cls;
  2232. if (NULL != plugin.cfg)
  2233. return NULL; /* can only initialize once! */
  2234. memset (&plugin, 0, sizeof(struct Plugin));
  2235. plugin.cfg = cfg;
  2236. api = GNUNET_new (struct GNUNET_REST_Plugin);
  2237. api->cls = &plugin;
  2238. api->name = GNUNET_REST_API_NS_OIDC;
  2239. api->process_request = &rest_identity_process_request;
  2240. GNUNET_asprintf (&allow_methods,
  2241. "%s, %s, %s, %s, %s",
  2242. MHD_HTTP_METHOD_GET,
  2243. MHD_HTTP_METHOD_POST,
  2244. MHD_HTTP_METHOD_PUT,
  2245. MHD_HTTP_METHOD_DELETE,
  2246. MHD_HTTP_METHOD_OPTIONS);
  2247. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2248. _ ("OpenID Connect REST API initialized\n"));
  2249. return api;
  2250. }
  2251. /**
  2252. * Exit point from the plugin.
  2253. *
  2254. * @param cls the plugin context (as returned by "init")
  2255. * @return always NULL
  2256. */
  2257. void *
  2258. libgnunet_plugin_rest_openid_connect_done (void *cls)
  2259. {
  2260. struct GNUNET_REST_Plugin *api = cls;
  2261. struct Plugin *plugin = api->cls;
  2262. plugin->cfg = NULL;
  2263. struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
  2264. void *value = NULL;
  2265. hashmap_it =
  2266. GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_cookie_jar_map);
  2267. while (GNUNET_YES ==
  2268. GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL,
  2269. value))
  2270. GNUNET_free (value);
  2271. GNUNET_CONTAINER_multihashmap_iterator_destroy (hashmap_it);
  2272. GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map);
  2273. hashmap_it =
  2274. GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_access_token_map);
  2275. while (GNUNET_YES ==
  2276. GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL,
  2277. value))
  2278. GNUNET_free (value);
  2279. GNUNET_CONTAINER_multihashmap_destroy (OIDC_access_token_map);
  2280. GNUNET_CONTAINER_multihashmap_iterator_destroy (hashmap_it);
  2281. GNUNET_free (allow_methods);
  2282. GNUNET_free (api);
  2283. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2284. "OpenID Connect REST plugin is finished\n");
  2285. return NULL;
  2286. }
  2287. /* end of plugin_rest_openid_connect.c */