2
0

plugin_rest_openid_connect.c 87 KB

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