1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857 |
- /*
- This file is part of GNUnet.
- Copyright (C) 2012-2018 GNUnet e.V.
- GNUnet is free software: you can redistribute it and/or modify it
- under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License,
- or (at your option) any later version.
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: AGPL3.0-or-later
- */
- /**
- * @author Martin Schanzenbach
- * @author Philippe Buschmann
- * @file identity/plugin_rest_openid_connect.c
- * @brief GNUnet Namestore REST plugin
- *
- */
- #include "platform.h"
- #include <inttypes.h>
- #include <jansson.h>
- #include "gnunet_buffer_lib.h"
- #include "gnunet_strings_lib.h"
- #include "gnunet_gns_service.h"
- #include "gnunet_gnsrecord_lib.h"
- #include "gnunet_identity_service.h"
- #include "gnunet_namestore_service.h"
- #include "gnunet_reclaim_lib.h"
- #include "gnunet_reclaim_service.h"
- #include "gnunet_rest_lib.h"
- #include "gnunet_rest_plugin.h"
- #include "gnunet_signatures.h"
- #include "microhttpd.h"
- #include "oidc_helper.h"
- /**
- * REST root namespace
- */
- #define GNUNET_REST_API_NS_OIDC "/openid"
- /**
- * OIDC config
- */
- #define GNUNET_REST_API_NS_OIDC_CONFIG "/.well-known/openid-configuration"
- /**
- * Authorize endpoint
- */
- #define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize"
- /**
- * Token endpoint
- */
- #define GNUNET_REST_API_NS_TOKEN "/openid/token"
- /**
- * UserInfo endpoint
- */
- #define GNUNET_REST_API_NS_USERINFO "/openid/userinfo"
- /**
- * Login namespace
- */
- #define GNUNET_REST_API_NS_LOGIN "/openid/login"
- /**
- * State while collecting all egos
- */
- #define ID_REST_STATE_INIT 0
- /**
- * Done collecting egos
- */
- #define ID_REST_STATE_POST_INIT 1
- /**
- * OIDC grant_type key
- */
- #define OIDC_GRANT_TYPE_KEY "grant_type"
- /**
- * OIDC grant_type key
- */
- #define OIDC_GRANT_TYPE_VALUE "authorization_code"
- /**
- * OIDC code key
- */
- #define OIDC_CODE_KEY "code"
- /**
- * OIDC response_type key
- */
- #define OIDC_RESPONSE_TYPE_KEY "response_type"
- /**
- * OIDC client_id key
- */
- #define OIDC_CLIENT_ID_KEY "client_id"
- /**
- * OIDC scope key
- */
- #define OIDC_SCOPE_KEY "scope"
- /**
- * OIDC redirect_uri key
- */
- #define OIDC_REDIRECT_URI_KEY "redirect_uri"
- /**
- * OIDC state key
- */
- #define OIDC_STATE_KEY "state"
- /**
- * OIDC nonce key
- */
- #define OIDC_NONCE_KEY "nonce"
- /**
- * OIDC claims key
- */
- #define OIDC_CLAIMS_KEY "claims"
- /**
- * OIDC PKCE code challenge
- */
- #define OIDC_CODE_CHALLENGE_KEY "code_challenge"
- /**
- * OIDC PKCE code verifier
- */
- #define OIDC_CODE_VERIFIER_KEY "code_verifier"
- /**
- * OIDC cookie expiration (in seconds)
- */
- #define OIDC_COOKIE_EXPIRATION 3
- /**
- * OIDC cookie header key
- */
- #define OIDC_COOKIE_HEADER_KEY "cookie"
- /**
- * OIDC cookie header information key
- */
- #define OIDC_AUTHORIZATION_HEADER_KEY "authorization"
- /**
- * OIDC cookie header information key
- */
- #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
- /**
- * OIDC cookie header if user cancelled
- */
- #define OIDC_COOKIE_HEADER_ACCESS_DENIED "Identity=Denied"
- /**
- * OIDC expected response_type while authorizing
- */
- #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
- /**
- * OIDC expected scope part while authorizing
- */
- #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
- /**
- * OIDC error key for invalid client
- */
- #define OIDC_ERROR_KEY_INVALID_CLIENT "invalid_client"
- /**
- * OIDC error key for invalid scopes
- */
- #define OIDC_ERROR_KEY_INVALID_SCOPE "invalid_scope"
- /**
- * OIDC error key for invalid requests
- */
- #define OIDC_ERROR_KEY_INVALID_REQUEST "invalid_request"
- /**
- * OIDC error key for invalid tokens
- */
- #define OIDC_ERROR_KEY_INVALID_TOKEN "invalid_token"
- /**
- * OIDC error key for invalid cookies
- */
- #define OIDC_ERROR_KEY_INVALID_COOKIE "invalid_cookie"
- /**
- * OIDC error key for generic server errors
- */
- #define OIDC_ERROR_KEY_SERVER_ERROR "server_error"
- /**
- * OIDC error key for unsupported grants
- */
- #define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE "unsupported_grant_type"
- /**
- * OIDC error key for unsupported response types
- */
- #define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE "unsupported_response_type"
- /**
- * OIDC error key for unauthorized clients
- */
- #define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT "unauthorized_client"
- /**
- * OIDC error key for denied access
- */
- #define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied"
- /**
- * How long to wait for a consume in userinfo endpoint
- */
- #define CONSUME_TIMEOUT GNUNET_TIME_relative_multiply ( \
- GNUNET_TIME_UNIT_SECONDS,2)
- /**
- * OIDC ignored parameter array
- */
- static char *OIDC_ignored_parameter_array[] = { "display",
- "prompt",
- "ui_locales",
- "response_mode",
- "id_token_hint",
- "login_hint",
- "acr_values" };
- /**
- * OIDC hashmap for cached access tokens and codes
- */
- struct GNUNET_CONTAINER_MultiHashMap *oidc_code_cache;
- /**
- * OIDC hashmap that keeps track of issued cookies
- */
- struct GNUNET_CONTAINER_MultiHashMap *OIDC_cookie_jar_map;
- /**
- * The configuration handle
- */
- const struct GNUNET_CONFIGURATION_Handle *cfg;
- /**
- * HTTP methods allows for this plugin
- */
- static char *allow_methods;
- /**
- * Ego list
- */
- static struct EgoEntry *ego_head;
- /**
- * Ego list
- */
- static struct EgoEntry *ego_tail;
- /**
- * The processing state
- */
- static int state;
- /**
- * Handle to Identity service.
- */
- static struct GNUNET_IDENTITY_Handle *identity_handle;
- /**
- * GNS handle
- */
- static struct GNUNET_GNS_Handle *gns_handle;
- /**
- * Identity Provider
- */
- static struct GNUNET_RECLAIM_Handle *idp;
- /**
- * @brief struct returned by the initialization function of the plugin
- */
- struct Plugin
- {
- const struct GNUNET_CONFIGURATION_Handle *cfg;
- };
- /**
- * OIDC needed variables
- */
- struct OIDC_Variables
- {
- /**
- * The RP client public key
- */
- struct GNUNET_IDENTITY_PublicKey client_pkey;
- /**
- * The OIDC client id of the RP
- */
- char *client_id;
- /**
- * The OIDC redirect uri
- */
- char *redirect_uri;
- /**
- * The list of oidc scopes
- */
- char *scope;
- /**
- * The OIDC state
- */
- char *state;
- /**
- * The OIDC nonce
- */
- char *nonce;
- /**
- * The OIDC claims
- */
- char *claims;
- /**
- * The OIDC response type
- */
- char *response_type;
- /**
- * The identity chosen by the user to login
- */
- char *login_identity;
- /**
- * User cancelled authorization/login
- */
- int user_cancelled;
- /**
- * The PKCE code_challenge
- */
- char *code_challenge;
- /**
- * The PKCE code_verifier
- */
- char *code_verifier;
- };
- /**
- * The ego list
- */
- struct EgoEntry
- {
- /**
- * DLL
- */
- struct EgoEntry *next;
- /**
- * DLL
- */
- struct EgoEntry *prev;
- /**
- * Ego Identifier
- */
- char *identifier;
- /**
- * Public key string
- */
- char *keystring;
- /**
- * The Ego
- */
- struct GNUNET_IDENTITY_Ego *ego;
- };
- struct RequestHandle
- {
- /**
- * DLL
- */
- struct RequestHandle *next;
- /**
- * DLL
- */
- struct RequestHandle *prev;
- /**
- * Selected ego
- */
- struct EgoEntry *ego_entry;
- /**
- * Pointer to ego private key
- */
- struct GNUNET_IDENTITY_PrivateKey priv_key;
- /**
- * OIDC variables
- */
- struct OIDC_Variables *oidc;
- /**
- * GNS lookup op
- */
- struct GNUNET_GNS_LookupRequest *gns_op;
- /**
- * Rest connection
- */
- struct GNUNET_REST_RequestHandle *rest_handle;
- /**
- * Attribute claim list for id_token
- */
- struct GNUNET_RECLAIM_AttributeList *attr_idtoken_list;
- /**
- * Attribute claim list for userinfo
- */
- struct GNUNET_RECLAIM_AttributeList *attr_userinfo_list;
- /**
- * Credentials
- */
- struct GNUNET_RECLAIM_CredentialList *credentials;
- /**
- * Presentations
- */
- struct GNUNET_RECLAIM_PresentationList *presentations;
- /**
- * IDENTITY Operation
- */
- struct GNUNET_IDENTITY_Operation *op;
- /**
- * Idp Operation
- */
- struct GNUNET_RECLAIM_Operation *idp_op;
- /**
- * Timeout task for consume
- */
- struct GNUNET_SCHEDULER_Task *consume_timeout_op;
- /**
- * Attribute iterator
- */
- struct GNUNET_RECLAIM_AttributeIterator *attr_it;
- /**
- * Credential iterator
- */
- struct GNUNET_RECLAIM_CredentialIterator *cred_it;
- /**
- * Ticket iterator
- */
- struct GNUNET_RECLAIM_TicketIterator *ticket_it;
- /**
- * A ticket
- */
- struct GNUNET_RECLAIM_Ticket ticket;
- /**
- * Desired timeout for the lookup (default is no timeout).
- */
- struct GNUNET_TIME_Relative timeout;
- /**
- * ID of a task associated with the resolution process.
- */
- struct GNUNET_SCHEDULER_Task *timeout_task;
- /**
- * The plugin result processor
- */
- GNUNET_REST_ResultProcessor proc;
- /**
- * The closure of the result processor
- */
- void *proc_cls;
- /**
- * The url
- */
- char *url;
- /**
- * The passed access token
- */
- char *access_token;
- /**
- * The tld for redirect
- */
- char *tld;
- /**
- * The redirect prefix
- */
- char *redirect_prefix;
- /**
- * The redirect suffix
- */
- char *redirect_suffix;
- /**
- * Error response message
- */
- char *emsg;
- /**
- * Error response description
- */
- char *edesc;
- /**
- * Response code
- */
- int response_code;
- /**
- * Public client
- */
- int public_client;
- };
- /**
- * DLL
- */
- static struct RequestHandle *requests_head;
- /**
- * DLL
- */
- static struct RequestHandle *requests_tail;
- /**
- * Cleanup lookup handle
- * @param handle Handle to clean up
- */
- static void
- cleanup_handle (struct RequestHandle *handle)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
- if (NULL != handle->timeout_task)
- GNUNET_SCHEDULER_cancel (handle->timeout_task);
- if (NULL != handle->attr_it)
- GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
- if (NULL != handle->cred_it)
- GNUNET_RECLAIM_get_credentials_stop (handle->cred_it);
- if (NULL != handle->ticket_it)
- GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
- if (NULL != handle->idp_op)
- GNUNET_RECLAIM_cancel (handle->idp_op);
- if (NULL != handle->consume_timeout_op)
- GNUNET_SCHEDULER_cancel (handle->consume_timeout_op);
- GNUNET_free (handle->url);
- GNUNET_free (handle->tld);
- GNUNET_free (handle->redirect_prefix);
- GNUNET_free (handle->redirect_suffix);
- GNUNET_free (handle->emsg);
- GNUNET_free (handle->edesc);
- if (NULL != handle->gns_op)
- GNUNET_GNS_lookup_cancel (handle->gns_op);
- if (NULL != handle->oidc)
- {
- GNUNET_free (handle->oidc->client_id);
- GNUNET_free (handle->oidc->login_identity);
- GNUNET_free (handle->oidc->nonce);
- GNUNET_free (handle->oidc->redirect_uri);
- GNUNET_free (handle->oidc->response_type);
- GNUNET_free (handle->oidc->scope);
- GNUNET_free (handle->oidc->state);
- if (NULL != handle->oidc->claims)
- GNUNET_free (handle->oidc->claims);
- if (NULL != handle->oidc->code_challenge)
- GNUNET_free (handle->oidc->code_challenge);
- GNUNET_free (handle->oidc);
- }
- if (NULL!=handle->attr_idtoken_list)
- GNUNET_RECLAIM_attribute_list_destroy (handle->attr_idtoken_list);
- if (NULL!=handle->attr_userinfo_list)
- GNUNET_RECLAIM_attribute_list_destroy (handle->attr_userinfo_list);
- if (NULL!=handle->credentials)
- GNUNET_RECLAIM_credential_list_destroy (handle->credentials);
- if (NULL!=handle->presentations)
- GNUNET_RECLAIM_presentation_list_destroy (handle->presentations);
- GNUNET_CONTAINER_DLL_remove (requests_head,
- requests_tail,
- handle);
- if (NULL != handle->access_token)
- GNUNET_free (handle->access_token);
- GNUNET_free (handle);
- }
- /**
- * Task run on error, sends error message. Cleans up everything.
- *
- * @param cls the `struct RequestHandle`
- */
- static void
- do_error (void *cls)
- {
- struct RequestHandle *handle = cls;
- struct MHD_Response *resp;
- char *json_error;
- GNUNET_asprintf (&json_error,
- "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
- handle->emsg,
- (NULL != handle->edesc) ? handle->edesc : "",
- (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
- (NULL != handle->oidc->state) ? handle->oidc->state : "",
- (NULL != handle->oidc->state) ? "\"" : "");
- if (0 == handle->response_code)
- handle->response_code = MHD_HTTP_BAD_REQUEST;
- resp = GNUNET_REST_create_response (json_error);
- if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
- MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Basic");
- MHD_add_response_header (resp,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- "application/json");
- handle->proc (handle->proc_cls, resp, handle->response_code);
- cleanup_handle (handle);
- GNUNET_free (json_error);
- }
- /**
- * Task run on error in userinfo endpoint, sends error header. Cleans up
- * everything
- *
- * @param cls the `struct RequestHandle`
- */
- static void
- do_userinfo_error (void *cls)
- {
- struct RequestHandle *handle = cls;
- struct MHD_Response *resp;
- char *error;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error: %s\n", handle->edesc);
- GNUNET_asprintf (&error,
- "error=\"%s\", error_description=\"%s\"",
- handle->emsg,
- (NULL != handle->edesc) ? handle->edesc : "");
- resp = GNUNET_REST_create_response ("");
- GNUNET_assert (MHD_NO !=
- MHD_add_response_header (resp,
- MHD_HTTP_HEADER_WWW_AUTHENTICATE,
- "Bearer"));
- handle->proc (handle->proc_cls, resp, handle->response_code);
- cleanup_handle (handle);
- GNUNET_free (error);
- }
- /**
- * Task run on error, sends error message and redirects. Cleans up everything.
- *
- * @param cls the `struct RequestHandle`
- */
- static void
- do_redirect_error (void *cls)
- {
- struct RequestHandle *handle = cls;
- struct MHD_Response *resp;
- char *redirect;
- GNUNET_asprintf (&redirect,
- "%s?error=%s&error_description=%s%s%s",
- handle->oidc->redirect_uri,
- handle->emsg,
- handle->edesc,
- (NULL != handle->oidc->state) ? "&state=" : "",
- (NULL != handle->oidc->state) ? handle->oidc->state : "");
- resp = GNUNET_REST_create_response ("");
- GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
- "Location", redirect));
- handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
- cleanup_handle (handle);
- GNUNET_free (redirect);
- }
- /**
- * Task run on timeout, sends error message. Cleans up everything.
- *
- * @param cls the `struct RequestHandle`
- */
- static void
- do_timeout (void *cls)
- {
- struct RequestHandle *handle = cls;
- handle->timeout_task = NULL;
- do_error (handle);
- }
- /**
- * Respond to OPTIONS request
- *
- * @param con_handle the connection handle
- * @param url the url
- * @param cls the RequestHandle
- */
- static void
- options_cont (struct GNUNET_REST_RequestHandle *con_handle,
- const char *url,
- void *cls)
- {
- struct MHD_Response *resp;
- struct RequestHandle *handle = cls;
- // For now, independent of path return all options
- resp = GNUNET_REST_create_response (NULL);
- MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- cleanup_handle (handle);
- return;
- }
- /**
- * Interprets cookie header and pass its identity keystring to handle
- */
- static void
- cookie_identity_interpretation (struct RequestHandle *handle)
- {
- struct GNUNET_HashCode cache_key;
- char *cookies;
- struct GNUNET_TIME_Absolute current_time, *relog_time;
- char delimiter[] = "; ";
- char *tmp_cookies;
- char *token;
- char *value;
- // gets identity of login try with cookie
- GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY,
- strlen (OIDC_COOKIE_HEADER_KEY),
- &cache_key);
- if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
- ->header_param_map,
- &cache_key))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cookie found\n");
- return;
- }
- // splits cookies and find 'Identity' cookie
- tmp_cookies =
- GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
- &cache_key);
- cookies = GNUNET_strdup (tmp_cookies);
- token = strtok (cookies, delimiter);
- handle->oidc->user_cancelled = GNUNET_NO;
- handle->oidc->login_identity = NULL;
- if (NULL == token)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unable to parse cookie: %s\n",
- cookies);
- GNUNET_free (cookies);
- return;
- }
- while (NULL != token)
- {
- if (0 == strcmp (token, OIDC_COOKIE_HEADER_ACCESS_DENIED))
- {
- handle->oidc->user_cancelled = GNUNET_YES;
- GNUNET_free (cookies);
- return;
- }
- if (NULL != strstr (token, OIDC_COOKIE_HEADER_INFORMATION_KEY))
- break;
- token = strtok (NULL, delimiter);
- }
- if (NULL == token)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "No cookie value to process: %s\n",
- cookies);
- GNUNET_free (cookies);
- return;
- }
- GNUNET_CRYPTO_hash (token, strlen (token), &cache_key);
- if (GNUNET_NO ==
- GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
- {
- GNUNET_log (
- GNUNET_ERROR_TYPE_WARNING,
- "Found cookie `%s', but no corresponding expiration entry present...\n",
- token);
- GNUNET_free (cookies);
- return;
- }
- relog_time =
- GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
- current_time = GNUNET_TIME_absolute_get ();
- // 30 min after old login -> redirect to login
- if (current_time.abs_value_us > relog_time->abs_value_us)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Found cookie `%s', but it is expired.\n",
- token);
- GNUNET_free (cookies);
- return;
- }
- value = strtok (token, OIDC_COOKIE_HEADER_INFORMATION_KEY);
- GNUNET_assert (NULL != value);
- handle->oidc->login_identity = GNUNET_strdup (value);
- GNUNET_free (cookies);
- }
- /**
- * Redirects to login page stored in configuration file
- */
- static void
- login_redirect (void *cls)
- {
- char *login_base_url;
- char *new_redirect;
- char *tmp;
- struct MHD_Response *resp;
- struct GNUNET_Buffer buf = { 0 };
- struct RequestHandle *handle = cls;
- if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
- "reclaim-rest-plugin",
- "address",
- &login_base_url))
- {
- GNUNET_buffer_write_str (&buf, login_base_url);
- GNUNET_buffer_write_fstr (&buf,
- "?%s=%s",
- OIDC_RESPONSE_TYPE_KEY,
- handle->oidc->response_type);
- GNUNET_buffer_write_fstr (&buf,
- "&%s=%s",
- OIDC_CLIENT_ID_KEY,
- handle->oidc->client_id);
- GNUNET_STRINGS_urlencode (handle->oidc->redirect_uri,
- strlen (handle->oidc->redirect_uri),
- &tmp);
- GNUNET_buffer_write_fstr (&buf,
- "&%s=%s",
- OIDC_REDIRECT_URI_KEY,
- tmp);
- GNUNET_free (tmp);
- GNUNET_STRINGS_urlencode (handle->oidc->scope,
- strlen (handle->oidc->scope),
- &tmp);
- GNUNET_buffer_write_fstr (&buf,
- "&%s=%s",
- OIDC_SCOPE_KEY,
- tmp);
- GNUNET_free (tmp);
- if (NULL != handle->oidc->state)
- {
- GNUNET_STRINGS_urlencode (handle->oidc->state,
- strlen (handle->oidc->state),
- &tmp);
- GNUNET_buffer_write_fstr (&buf,
- "&%s=%s",
- OIDC_STATE_KEY,
- handle->oidc->state);
- GNUNET_free (tmp);
- }
- if (NULL != handle->oidc->code_challenge)
- {
- GNUNET_buffer_write_fstr (&buf,
- "&%s=%s",
- OIDC_CODE_CHALLENGE_KEY,
- handle->oidc->code_challenge);
- }
- if (NULL != handle->oidc->nonce)
- {
- GNUNET_buffer_write_fstr (&buf,
- "&%s=%s",
- OIDC_NONCE_KEY,
- handle->oidc->nonce);
- }
- if (NULL != handle->oidc->claims)
- {
- GNUNET_STRINGS_urlencode (handle->oidc->claims,
- strlen (handle->oidc->claims),
- &tmp);
- GNUNET_buffer_write_fstr (&buf,
- "&%s=%s",
- OIDC_CLAIMS_KEY,
- tmp);
- GNUNET_free (tmp);
- }
- new_redirect = GNUNET_buffer_reap_str (&buf);
- resp = GNUNET_REST_create_response ("");
- MHD_add_response_header (resp, "Location", new_redirect);
- GNUNET_free (login_base_url);
- }
- else
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
- handle->edesc = GNUNET_strdup ("gnunet configuration failed");
- handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
- GNUNET_free (new_redirect);
- cleanup_handle (handle);
- }
- /**
- * Does internal server error when iteration failed.
- */
- static void
- oidc_iteration_error (void *cls)
- {
- struct RequestHandle *handle = cls;
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
- handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- }
- /**
- * Issues ticket and redirects to relying party with the authorization code as
- * parameter. Otherwise redirects with error
- */
- static void
- oidc_ticket_issue_cb (void *cls,
- const struct GNUNET_RECLAIM_Ticket *ticket,
- const struct
- GNUNET_RECLAIM_PresentationList *presentation)
- {
- struct RequestHandle *handle = cls;
- struct MHD_Response *resp;
- char *ticket_str;
- char *redirect_uri;
- char *code_string;
- handle->idp_op = NULL;
- if (NULL == ticket)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
- handle->edesc = GNUNET_strdup ("Server cannot generate ticket.");
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- return;
- }
- handle->ticket = *ticket;
- ticket_str =
- GNUNET_STRINGS_data_to_string_alloc (&handle->ticket,
- sizeof(struct GNUNET_RECLAIM_Ticket));
- code_string = OIDC_build_authz_code (&handle->priv_key,
- &handle->ticket,
- handle->attr_idtoken_list,
- presentation,
- handle->oidc->nonce,
- handle->oidc->code_challenge);
- if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
- (NULL != handle->tld))
- {
- GNUNET_asprintf (&redirect_uri,
- "%s.%s/%s%s%s=%s&state=%s",
- handle->redirect_prefix,
- handle->tld,
- handle->redirect_suffix,
- (NULL == strchr (handle->redirect_suffix, '?') ? "?" :
- "&"),
- handle->oidc->response_type,
- code_string,
- handle->oidc->state);
- }
- else
- {
- GNUNET_asprintf (&redirect_uri,
- "%s%s%s=%s&state=%s",
- handle->oidc->redirect_uri,
- (NULL == strchr (handle->oidc->redirect_uri, '?') ? "?" :
- "&"),
- handle->oidc->response_type,
- code_string,
- handle->oidc->state);
- }
- resp = GNUNET_REST_create_response ("");
- GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
- "Location", redirect_uri));
- handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
- cleanup_handle (handle);
- GNUNET_free (redirect_uri);
- GNUNET_free (ticket_str);
- GNUNET_free (code_string);
- }
- static struct GNUNET_RECLAIM_AttributeList*
- attribute_list_merge (struct GNUNET_RECLAIM_AttributeList *list_a,
- struct GNUNET_RECLAIM_AttributeList *list_b)
- {
- struct GNUNET_RECLAIM_AttributeList *merged_list;
- struct GNUNET_RECLAIM_AttributeListEntry *le_a;
- struct GNUNET_RECLAIM_AttributeListEntry *le_b;
- struct GNUNET_RECLAIM_AttributeListEntry *le_m;
- merged_list = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
- for (le_a = list_a->list_head; NULL != le_a; le_a = le_a->next)
- {
- le_m = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
- le_m->attribute = GNUNET_RECLAIM_attribute_new (le_a->attribute->name,
- &le_a->attribute->
- credential,
- le_a->attribute->type,
- le_a->attribute->data,
- le_a->attribute->data_size);
- le_m->attribute->id = le_a->attribute->id;
- le_m->attribute->flag = le_a->attribute->flag;
- le_m->attribute->credential = le_a->attribute->credential;
- GNUNET_CONTAINER_DLL_insert (merged_list->list_head,
- merged_list->list_tail,
- le_m);
- }
- le_m = NULL;
- for (le_b = list_b->list_head; NULL != le_b; le_b = le_b->next)
- {
- for (le_m = merged_list->list_head; NULL != le_m; le_m = le_m->next)
- {
- if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (&le_m->attribute->id,
- &le_b->attribute->id))
- break; /** Attribute already in list **/
- }
- if (NULL != le_m)
- continue; /** Attribute already in list **/
- le_m = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
- le_m->attribute = GNUNET_RECLAIM_attribute_new (le_b->attribute->name,
- &le_b->attribute->
- credential,
- le_b->attribute->type,
- le_b->attribute->data,
- le_b->attribute->data_size);
- le_m->attribute->id = le_b->attribute->id;
- le_m->attribute->flag = le_b->attribute->flag;
- le_m->attribute->credential = le_b->attribute->credential;
- GNUNET_CONTAINER_DLL_insert (merged_list->list_head,
- merged_list->list_tail,
- le_m);
- }
- return merged_list;
- }
- static void
- oidc_cred_collect_finished_cb (void *cls)
- {
- struct RequestHandle *handle = cls;
- struct GNUNET_RECLAIM_AttributeList *merged_list;
- struct GNUNET_RECLAIM_AttributeListEntry *le_m;
- handle->cred_it = NULL;
- merged_list = attribute_list_merge (handle->attr_idtoken_list,
- handle->attr_userinfo_list);
- for (le_m = merged_list->list_head; NULL != le_m; le_m = le_m->next)
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "List Attribute in ticket to issue: %s\n",
- le_m->attribute->name);
- handle->idp_op = GNUNET_RECLAIM_ticket_issue (idp,
- &handle->priv_key,
- &handle->oidc->client_pkey,
- merged_list,
- &oidc_ticket_issue_cb,
- handle);
- GNUNET_RECLAIM_attribute_list_destroy (merged_list);
- }
- /**
- * Collects all attributes for an ego if in scope parameter
- */
- static void
- oidc_cred_collect (void *cls,
- const struct GNUNET_IDENTITY_PublicKey *identity,
- const struct GNUNET_RECLAIM_Credential *cred)
- {
- struct RequestHandle *handle = cls;
- struct GNUNET_RECLAIM_AttributeListEntry *le;
- struct GNUNET_RECLAIM_CredentialListEntry *ale;
- for (ale = handle->credentials->list_head; NULL != ale; ale = ale->next)
- {
- if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (&ale->credential->id,
- &cred->id))
- continue;
- /** Credential already in list **/
- GNUNET_RECLAIM_get_credentials_next (handle->cred_it);
- return;
- }
- for (le = handle->attr_idtoken_list->list_head; NULL != le; le = le->next)
- {
- if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (&le->attribute->credential,
- &cred->id))
- continue;
- /** Credential matches for attribute, add **/
- ale = GNUNET_new (struct GNUNET_RECLAIM_CredentialListEntry);
- ale->credential = GNUNET_RECLAIM_credential_new (cred->name,
- cred->type,
- cred->data,
- cred->data_size);
- GNUNET_CONTAINER_DLL_insert (handle->credentials->list_head,
- handle->credentials->list_tail,
- ale);
- }
- GNUNET_RECLAIM_get_credentials_next (handle->cred_it);
- }
- static void
- oidc_attr_collect_finished_cb (void *cls)
- {
- struct RequestHandle *handle = cls;
- handle->attr_it = NULL;
- handle->ticket_it = NULL;
- if (NULL == handle->attr_idtoken_list->list_head)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE);
- handle->edesc = GNUNET_strdup ("The requested scope is not available.");
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- return;
- }
- handle->credentials = GNUNET_new (struct GNUNET_RECLAIM_CredentialList);
- handle->cred_it =
- GNUNET_RECLAIM_get_credentials_start (idp,
- &handle->priv_key,
- &oidc_iteration_error,
- handle,
- &oidc_cred_collect,
- handle,
- &oidc_cred_collect_finished_cb,
- handle);
- }
- static int
- attr_in_claims_request (struct RequestHandle *handle,
- const char *attr_name,
- const char *claims_parameter)
- {
- int ret = GNUNET_NO;
- json_t *root;
- json_error_t error;
- json_t *claims_j;
- const char *key;
- json_t *value;
- /** Check if attribute is requested through a scope **/
- if (GNUNET_YES == OIDC_check_scopes_for_claim_request (handle->oidc->scope,
- attr_name))
- return GNUNET_YES;
- /** Try claims parameter if not in scope */
- if (NULL != handle->oidc->claims)
- {
- root = json_loads (handle->oidc->claims, JSON_DECODE_ANY, &error);
- claims_j = json_object_get (root, claims_parameter);
- /* obj is a JSON object */
- if (NULL != claims_j)
- {
- json_object_foreach (claims_j, key, value) {
- if (0 != strcmp (attr_name, key))
- continue;
- ret = GNUNET_YES;
- break;
- }
- }
- json_decref (root);
- }
- return ret;
- }
- static int
- attr_in_idtoken_request (struct RequestHandle *handle,
- const char *attr_name)
- {
- return attr_in_claims_request (handle, attr_name, "id_token");
- }
- static int
- attr_in_userinfo_request (struct RequestHandle *handle,
- const char *attr_name)
- {
- return attr_in_claims_request (handle, attr_name, "userinfo");
- }
- /**
- * Collects all attributes for an ego if in scope parameter
- */
- static void
- oidc_attr_collect (void *cls,
- const struct GNUNET_IDENTITY_PublicKey *identity,
- const struct GNUNET_RECLAIM_Attribute *attr)
- {
- struct RequestHandle *handle = cls;
- struct GNUNET_RECLAIM_AttributeListEntry *le;
- if (GNUNET_YES == attr_in_idtoken_request (handle, attr->name))
- {
- le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
- le->attribute = GNUNET_RECLAIM_attribute_new (attr->name,
- &attr->credential,
- attr->type,
- attr->data,
- attr->data_size);
- le->attribute->id = attr->id;
- le->attribute->flag = attr->flag;
- le->attribute->credential = attr->credential;
- GNUNET_CONTAINER_DLL_insert (handle->attr_idtoken_list->list_head,
- handle->attr_idtoken_list->list_tail,
- le);
- }
- if (GNUNET_YES == attr_in_userinfo_request (handle, attr->name))
- {
- le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
- le->attribute = GNUNET_RECLAIM_attribute_new (attr->name,
- &attr->credential,
- attr->type,
- attr->data,
- attr->data_size);
- le->attribute->id = attr->id;
- le->attribute->flag = attr->flag;
- le->attribute->credential = attr->credential;
- GNUNET_CONTAINER_DLL_insert (handle->attr_userinfo_list->list_head,
- handle->attr_userinfo_list->list_tail,
- le);
- }
- GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
- }
- /**
- * Checks time and cookie and redirects accordingly
- */
- static void
- code_redirect (void *cls)
- {
- struct RequestHandle *handle = cls;
- struct GNUNET_TIME_Absolute current_time;
- struct GNUNET_TIME_Absolute *relog_time;
- struct GNUNET_IDENTITY_PublicKey pubkey;
- struct GNUNET_IDENTITY_PublicKey ego_pkey;
- struct GNUNET_HashCode cache_key;
- char *identity_cookie;
- GNUNET_asprintf (&identity_cookie,
- "Identity=%s",
- handle->oidc->login_identity);
- GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
- GNUNET_free (identity_cookie);
- // No login time for identity -> redirect to login
- if (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
- {
- relog_time =
- GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
- current_time = GNUNET_TIME_absolute_get ();
- // 30 min after old login -> redirect to login
- if (current_time.abs_value_us <= relog_time->abs_value_us)
- {
- if (GNUNET_OK !=
- GNUNET_IDENTITY_public_key_from_string (handle->oidc
- ->login_identity,
- &pubkey))
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_COOKIE);
- handle->edesc =
- GNUNET_strdup ("The cookie of a login identity is not valid");
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- return;
- }
- // iterate over egos and compare their public key
- for (handle->ego_entry = ego_head; NULL != handle->ego_entry;
- handle->ego_entry = handle->ego_entry->next)
- {
- GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
- if (0 == GNUNET_memcmp (&ego_pkey, &pubkey))
- {
- handle->priv_key =
- *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
- handle->attr_idtoken_list =
- GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
- handle->attr_userinfo_list =
- GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
- handle->attr_it =
- GNUNET_RECLAIM_get_attributes_start (idp,
- &handle->priv_key,
- &oidc_iteration_error,
- handle,
- &oidc_attr_collect,
- handle,
- &oidc_attr_collect_finished_cb,
- handle);
- return;
- }
- }
- GNUNET_SCHEDULER_add_now (&login_redirect, handle);
- return;
- }
- }
- }
- static void
- build_redirect (void *cls)
- {
- struct RequestHandle *handle = cls;
- struct MHD_Response *resp;
- char *redirect_uri;
- if (GNUNET_YES == handle->oidc->user_cancelled)
- {
- if ((NULL != handle->redirect_prefix) &&
- (NULL != handle->redirect_suffix) && (NULL != handle->tld))
- {
- GNUNET_asprintf (&redirect_uri,
- "%s.%s/%s?error=%s&error_description=%s&state=%s",
- handle->redirect_prefix,
- handle->tld,
- handle->redirect_suffix,
- "access_denied",
- "User denied access",
- handle->oidc->state);
- }
- else
- {
- GNUNET_asprintf (&redirect_uri,
- "%s?error=%s&error_description=%s&state=%s",
- handle->oidc->redirect_uri,
- "access_denied",
- "User denied access",
- handle->oidc->state);
- }
- resp = GNUNET_REST_create_response ("");
- GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
- "Location",
- redirect_uri));
- handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
- cleanup_handle (handle);
- GNUNET_free (redirect_uri);
- return;
- }
- GNUNET_SCHEDULER_add_now (&code_redirect, handle);
- }
- static void
- lookup_redirect_uri_result (void *cls,
- uint32_t rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
- {
- struct RequestHandle *handle = cls;
- char *tmp;
- char *tmp_key_str;
- char *pos;
- struct GNUNET_IDENTITY_PublicKey redirect_zone;
- handle->gns_op = NULL;
- if (0 == rd_count)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
- handle->edesc =
- GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- return;
- }
- for (int i = 0; i < rd_count; i++)
- {
- if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type)
- continue;
- if (0 != strncmp (rd[i].data, handle->oidc->redirect_uri, rd[i].data_size))
- continue;
- tmp = GNUNET_strndup (rd[i].data, rd[i].data_size);
- if (NULL == strstr (tmp, handle->oidc->client_id))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Redirect uri %s does not contain client_id %s\n",
- tmp,
- handle->oidc->client_id);
- }
- else
- {
- pos = strrchr (tmp, (unsigned char) '.');
- if (NULL == pos)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Redirect uri %s contains client_id but is malformed\n",
- tmp);
- GNUNET_free (tmp);
- continue;
- }
- *pos = '\0';
- handle->redirect_prefix = GNUNET_strdup (tmp);
- tmp_key_str = pos + 1;
- pos = strchr (tmp_key_str, (unsigned char) '/');
- if (NULL == pos)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Redirect uri %s contains client_id but is malformed\n",
- tmp);
- GNUNET_free (tmp);
- continue;
- }
- *pos = '\0';
- handle->redirect_suffix = GNUNET_strdup (pos + 1);
- GNUNET_STRINGS_string_to_data (tmp_key_str,
- strlen (tmp_key_str),
- &redirect_zone,
- sizeof(redirect_zone));
- }
- GNUNET_SCHEDULER_add_now (&build_redirect, handle);
- GNUNET_free (tmp);
- return;
- }
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
- handle->edesc =
- GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- }
- /**
- * Initiate redirect back to client.
- */
- static void
- client_redirect (void *cls)
- {
- struct RequestHandle *handle = cls;
- /* Lookup client redirect uri to verify request */
- handle->gns_op =
- GNUNET_GNS_lookup (gns_handle,
- GNUNET_GNS_EMPTY_LABEL_AT,
- &handle->oidc->client_pkey,
- GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT,
- GNUNET_GNS_LO_DEFAULT,
- &lookup_redirect_uri_result,
- handle);
- }
- static char *
- get_url_parameter_copy (const struct RequestHandle *handle, const char *key)
- {
- struct GNUNET_HashCode hc;
- char *value;
- char *res;
- GNUNET_CRYPTO_hash (key, strlen (key), &hc);
- if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
- ->url_param_map,
- &hc))
- return NULL;
- value =
- GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, &hc);
- if (NULL == value)
- return NULL;
- GNUNET_STRINGS_urldecode (value, strlen (value), &res);
- return res;
- }
- /**
- * Iteration over all results finished, build final
- * response.
- *
- * @param cls the `struct RequestHandle`
- */
- static void
- build_authz_response (void *cls)
- {
- struct RequestHandle *handle = cls;
- struct GNUNET_HashCode cache_key;
- char *expected_scope;
- char delimiter[] = " ";
- int number_of_ignored_parameter, iterator;
- // REQUIRED value: redirect_uri
- handle->oidc->redirect_uri =
- get_url_parameter_copy (handle, OIDC_REDIRECT_URI_KEY);
- if (NULL == handle->oidc->redirect_uri)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
- handle->edesc = GNUNET_strdup ("missing parameter redirect_uri");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- // REQUIRED value: response_type
- handle->oidc->response_type =
- get_url_parameter_copy (handle, OIDC_RESPONSE_TYPE_KEY);
- if (NULL == handle->oidc->response_type)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
- handle->edesc = GNUNET_strdup ("missing parameter response_type");
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- return;
- }
- // REQUIRED value: scope
- handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
- if (NULL == handle->oidc->scope)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE);
- handle->edesc = GNUNET_strdup ("missing parameter scope");
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- return;
- }
- // OPTIONAL value: nonce
- handle->oidc->nonce = get_url_parameter_copy (handle, OIDC_NONCE_KEY);
- // OPTIONAL value: claims
- handle->oidc->claims = get_url_parameter_copy (handle, OIDC_CLAIMS_KEY);
- // TODO check other values if needed
- number_of_ignored_parameter =
- sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
- for (iterator = 0; iterator < number_of_ignored_parameter; iterator++)
- {
- GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
- strlen (OIDC_ignored_parameter_array[iterator]),
- &cache_key);
- if (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
- ->url_param_map,
- &cache_key))
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_ACCESS_DENIED);
- GNUNET_asprintf (&handle->edesc,
- "Server will not handle parameter: %s",
- OIDC_ignored_parameter_array[iterator]);
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- return;
- }
- }
- // We only support authorization code flows.
- if (0 != strcmp (handle->oidc->response_type,
- OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE))
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE);
- handle->edesc = GNUNET_strdup ("The authorization server does not support "
- "obtaining this authorization code.");
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- return;
- }
- // Checks if scope contains 'openid'
- expected_scope = GNUNET_strdup (handle->oidc->scope);
- char *test;
- test = strtok (expected_scope, delimiter);
- while (NULL != test)
- {
- if (0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope))
- break;
- test = strtok (NULL, delimiter);
- }
- if (NULL == test)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE);
- handle->edesc =
- GNUNET_strdup ("The requested scope is invalid, unknown, or malformed.");
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- GNUNET_free (expected_scope);
- return;
- }
- GNUNET_free (expected_scope);
- if ((NULL == handle->oidc->login_identity) &&
- (GNUNET_NO == handle->oidc->user_cancelled))
- GNUNET_SCHEDULER_add_now (&login_redirect, handle);
- else
- GNUNET_SCHEDULER_add_now (&client_redirect, handle);
- }
- /**
- * Iterate over tlds in config
- */
- static void
- tld_iter (void *cls, const char *section, const char *option, const char *value)
- {
- struct RequestHandle *handle = cls;
- struct GNUNET_IDENTITY_PublicKey pkey;
- if (GNUNET_OK !=
- GNUNET_IDENTITY_public_key_from_string (value, &pkey))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping non key %s\n", value);
- return;
- }
- if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
- handle->tld = GNUNET_strdup (option + 1);
- }
- /**
- * Responds to authorization GET and url-encoded POST request
- *
- * @param con_handle the connection handle
- * @param url the url
- * @param cls the RequestHandle
- */
- static void
- authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
- const char *url,
- void *cls)
- {
- struct RequestHandle *handle = cls;
- struct EgoEntry *tmp_ego;
- const struct GNUNET_IDENTITY_PrivateKey *priv_key;
- struct GNUNET_IDENTITY_PublicKey pkey;
- cookie_identity_interpretation (handle);
- // RECOMMENDED value: state - REQUIRED for answers
- handle->oidc->state = get_url_parameter_copy (handle, OIDC_STATE_KEY);
- // REQUIRED value: client_id
- handle->oidc->client_id = get_url_parameter_copy (handle, OIDC_CLIENT_ID_KEY);
- if (NULL == handle->oidc->client_id)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
- handle->edesc = GNUNET_strdup ("missing parameter client_id");
- handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- // OPTIONAL value: code_challenge
- handle->oidc->code_challenge = get_url_parameter_copy (handle,
- OIDC_CODE_CHALLENGE_KEY);
- if (NULL == handle->oidc->code_challenge)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "OAuth authorization request does not contain PKCE parameters!\n");
- }
- if (GNUNET_OK !=
- GNUNET_IDENTITY_public_key_from_string (handle->oidc->client_id,
- &handle->oidc->client_pkey))
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT);
- handle->edesc = GNUNET_strdup ("The client is not authorized to request an "
- "authorization code using this method.");
- handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- // If we know this identity, translated the corresponding TLD
- // TODO: We might want to have a reverse lookup functionality for TLDs?
- for (tmp_ego = ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
- {
- priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
- GNUNET_IDENTITY_key_get_public (priv_key, &pkey);
- if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
- {
- handle->tld = GNUNET_strdup (tmp_ego->identifier);
- handle->ego_entry = ego_tail;
- }
- }
- if (NULL == handle->tld)
- GNUNET_CONFIGURATION_iterate_section_values (cfg, "gns", tld_iter, handle);
- if (NULL == handle->tld)
- handle->tld = GNUNET_strdup (handle->oidc->client_id);
- GNUNET_SCHEDULER_add_now (&build_authz_response, handle);
- }
- /**
- * Combines an identity with a login time and responds OK to login request
- *
- * @param con_handle the connection handle
- * @param url the url
- * @param cls the RequestHandle
- */
- static void
- login_cont (struct GNUNET_REST_RequestHandle *con_handle,
- const char *url,
- void *cls)
- {
- struct MHD_Response *resp = GNUNET_REST_create_response ("");
- struct RequestHandle *handle = cls;
- struct GNUNET_HashCode cache_key;
- struct GNUNET_TIME_Absolute *current_time;
- struct GNUNET_TIME_Absolute *last_time;
- char *cookie;
- char *header_val;
- json_t *root;
- json_error_t error;
- json_t *identity;
- char term_data[handle->rest_handle->data_size + 1];
- term_data[handle->rest_handle->data_size] = '\0';
- GNUNET_memcpy (term_data,
- handle->rest_handle->data,
- handle->rest_handle->data_size);
- root = json_loads (term_data, JSON_DECODE_ANY, &error);
- identity = json_object_get (root, "identity");
- if (! json_is_string (identity))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error parsing json string from %s\n",
- term_data);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
- json_decref (root);
- cleanup_handle (handle);
- return;
- }
- GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
- GNUNET_asprintf (&header_val,
- "%s;Max-Age=%d",
- cookie,
- OIDC_COOKIE_EXPIRATION);
- GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
- "Set-Cookie", header_val));
- GNUNET_assert (MHD_NO !=
- MHD_add_response_header (resp,
- "Access-Control-Allow-Methods",
- "POST"));
- GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
- if (0 != strcmp (json_string_value (identity), "Denied"))
- {
- current_time = GNUNET_new (struct GNUNET_TIME_Absolute);
- *current_time = GNUNET_TIME_relative_to_absolute (
- GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (),
- OIDC_COOKIE_EXPIRATION));
- last_time =
- GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
- GNUNET_free (last_time);
- GNUNET_CONTAINER_multihashmap_put (OIDC_cookie_jar_map,
- &cache_key,
- current_time,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
- }
- handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- GNUNET_free (cookie);
- GNUNET_free (header_val);
- json_decref (root);
- cleanup_handle (handle);
- }
- static int
- parse_credentials_basic_auth (struct RequestHandle *handle,
- char **client_id,
- char **client_secret)
- {
- struct GNUNET_HashCode cache_key;
- char *authorization;
- char *credentials;
- char *basic_authorization;
- char *client_id_tmp;
- char *pass;
- GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
- strlen (OIDC_AUTHORIZATION_HEADER_KEY),
- &cache_key);
- if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
- ->header_param_map,
- &cache_key))
- return GNUNET_SYSERR;
- authorization =
- GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
- &cache_key);
- // split header in "Basic" and [content]
- credentials = strtok (authorization, " ");
- if ((NULL == credentials) || (0 != strcmp ("Basic", credentials)))
- return GNUNET_SYSERR;
- credentials = strtok (NULL, " ");
- if (NULL == credentials)
- return GNUNET_SYSERR;
- GNUNET_STRINGS_base64_decode (credentials,
- strlen (credentials),
- (void **) &basic_authorization);
- if (NULL == basic_authorization)
- return GNUNET_SYSERR;
- client_id_tmp = strtok (basic_authorization, ":");
- if (NULL == client_id_tmp)
- {
- GNUNET_free (basic_authorization);
- return GNUNET_SYSERR;
- }
- pass = strtok (NULL, ":");
- if (NULL == pass)
- {
- GNUNET_free (basic_authorization);
- return GNUNET_SYSERR;
- }
- *client_id = strdup (client_id_tmp);
- *client_secret = strdup (pass);
- GNUNET_free (basic_authorization);
- return GNUNET_OK;
- }
- static int
- parse_credentials_post_body (struct RequestHandle *handle,
- char **client_id,
- char **client_secret)
- {
- struct GNUNET_HashCode cache_key;
- char *client_id_tmp;
- char *pass;
- GNUNET_CRYPTO_hash ("client_id",
- strlen ("client_id"),
- &cache_key);
- if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
- ->url_param_map,
- &cache_key))
- return GNUNET_SYSERR;
- client_id_tmp = GNUNET_CONTAINER_multihashmap_get (
- handle->rest_handle->url_param_map,
- &cache_key);
- if (NULL == client_id_tmp)
- return GNUNET_SYSERR;
- *client_id = strdup (client_id_tmp);
- GNUNET_CRYPTO_hash ("client_secret",
- strlen ("client_secret"),
- &cache_key);
- if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
- ->url_param_map,
- &cache_key))
- {
- GNUNET_free (*client_id);
- *client_id = NULL;
- return GNUNET_SYSERR;
- }
- pass = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
- &cache_key);
- if (NULL == pass)
- {
- GNUNET_free (*client_id);
- *client_id = NULL;
- return GNUNET_SYSERR;
- }
- *client_secret = strdup (pass);
- return GNUNET_OK;
- }
- static int
- check_authorization (struct RequestHandle *handle,
- struct GNUNET_IDENTITY_PublicKey *cid)
- {
- char *expected_pass;
- char *received_cid;
- char *received_cpw;
- char *pkce_cv;
- if (GNUNET_OK == parse_credentials_basic_auth (handle,
- &received_cid,
- &received_cpw))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received client credentials in HTTP AuthZ header\n");
- }
- else if (GNUNET_OK == parse_credentials_post_body (handle,
- &received_cid,
- &received_cpw))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received client credentials in POST body\n");
- }
- else
- {
- /** Allow public clients with PKCE **/
- pkce_cv = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY);
- if (NULL == pkce_cv)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
- handle->response_code = MHD_HTTP_UNAUTHORIZED;
- return GNUNET_SYSERR;
- }
- handle->public_client = GNUNET_YES;
- GNUNET_free (pkce_cv);
- received_cid = get_url_parameter_copy (handle, OIDC_CLIENT_ID_KEY);
- GNUNET_STRINGS_string_to_data (received_cid,
- strlen (received_cid),
- cid,
- sizeof(struct GNUNET_IDENTITY_PublicKey));
- GNUNET_free (received_cid);
- return GNUNET_OK;
- }
- // check client password
- if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
- "reclaim-rest-plugin",
- "OIDC_CLIENT_SECRET",
- &expected_pass))
- {
- if (0 != strcmp (expected_pass, received_cpw))
- {
- GNUNET_free (expected_pass);
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
- handle->response_code = MHD_HTTP_UNAUTHORIZED;
- GNUNET_free (received_cpw);
- GNUNET_free (received_cid);
- return GNUNET_SYSERR;
- }
- GNUNET_free (expected_pass);
- }
- else
- {
- GNUNET_free (received_cpw);
- GNUNET_free (received_cid);
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
- handle->edesc = GNUNET_strdup ("gnunet configuration failed");
- handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- return GNUNET_SYSERR;
- }
- // check client_id
- for (handle->ego_entry = ego_head; NULL != handle->ego_entry;
- handle->ego_entry = handle->ego_entry->next)
- {
- if (0 == strcmp (handle->ego_entry->keystring, received_cid))
- break;
- }
- if (NULL == handle->ego_entry)
- {
- GNUNET_free (received_cpw);
- GNUNET_free (received_cid);
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
- handle->response_code = MHD_HTTP_UNAUTHORIZED;
- return GNUNET_SYSERR;
- }
- GNUNET_STRINGS_string_to_data (received_cid,
- strlen (received_cid),
- cid,
- sizeof(struct GNUNET_IDENTITY_PublicKey));
- GNUNET_free (received_cpw);
- GNUNET_free (received_cid);
- return GNUNET_OK;
- }
- const struct EgoEntry *
- find_ego (struct RequestHandle *handle,
- struct GNUNET_IDENTITY_PublicKey *test_key)
- {
- struct EgoEntry *ego_entry;
- struct GNUNET_IDENTITY_PublicKey pub_key;
- for (ego_entry = ego_head; NULL != ego_entry;
- ego_entry = ego_entry->next)
- {
- GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
- if (0 == GNUNET_memcmp (&pub_key, test_key))
- return ego_entry;
- }
- return NULL;
- }
- /**
- * Responds to token url-encoded POST request
- *
- * @param con_handle the connection handle
- * @param url the url
- * @param cls the RequestHandle
- */
- static void
- token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
- const char *url,
- void *cls)
- {
- struct RequestHandle *handle = cls;
- const struct EgoEntry *ego_entry;
- struct GNUNET_TIME_Relative expiration_time;
- struct GNUNET_RECLAIM_AttributeList *cl = NULL;
- struct GNUNET_RECLAIM_PresentationList *pl = NULL;
- struct GNUNET_RECLAIM_Ticket ticket;
- struct GNUNET_IDENTITY_PublicKey cid;
- struct GNUNET_HashCode cache_key;
- struct MHD_Response *resp;
- char *grant_type;
- char *code;
- char *json_response;
- char *id_token;
- char *access_token;
- char *jwt_secret;
- char *nonce = NULL;
- char *code_verifier;
- /*
- * Check Authorization
- */
- if (GNUNET_SYSERR == check_authorization (handle, &cid))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "OIDC authorization for token endpoint failed\n");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- /*
- * Check parameter
- */
- // TODO Do not allow multiple equal parameter names
- // REQUIRED grant_type
- GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY,
- strlen (OIDC_GRANT_TYPE_KEY),
- &cache_key);
- grant_type = get_url_parameter_copy (handle, OIDC_GRANT_TYPE_KEY);
- if (NULL == grant_type)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
- handle->edesc = GNUNET_strdup ("missing parameter grant_type");
- handle->response_code = MHD_HTTP_BAD_REQUEST;
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- // Check parameter grant_type == "authorization_code"
- if (0 != strcmp (OIDC_GRANT_TYPE_VALUE, grant_type))
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE);
- handle->response_code = MHD_HTTP_BAD_REQUEST;
- GNUNET_free (grant_type);
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- GNUNET_free (grant_type);
- // REQUIRED code
- code = get_url_parameter_copy (handle, OIDC_CODE_KEY);
- if (NULL == code)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
- handle->edesc = GNUNET_strdup ("missing parameter code");
- handle->response_code = MHD_HTTP_BAD_REQUEST;
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- ego_entry = find_ego (handle, &cid);
- if (NULL == ego_entry)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
- handle->edesc = GNUNET_strdup ("Unknown client");
- handle->response_code = MHD_HTTP_BAD_REQUEST;
- GNUNET_free (code);
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- // REQUIRED code verifier
- code_verifier = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY);
- if (NULL == code_verifier)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "OAuth authorization request does not contain PKCE parameters!\n");
- }
- // decode code
- if (GNUNET_OK != OIDC_parse_authz_code (&cid, code, code_verifier, &ticket,
- &cl, &pl, &nonce,
- OIDC_VERIFICATION_DEFAULT))
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
- handle->edesc = GNUNET_strdup ("invalid code");
- handle->response_code = MHD_HTTP_BAD_REQUEST;
- GNUNET_free (code);
- if (NULL != code_verifier)
- GNUNET_free (code_verifier);
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- if (NULL != code_verifier)
- GNUNET_free (code_verifier);
- // create jwt
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
- "reclaim-rest-plugin",
- "expiration_time",
- &expiration_time))
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
- handle->edesc = GNUNET_strdup ("gnunet configuration failed");
- handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- GNUNET_free (code);
- if (NULL != nonce)
- GNUNET_free (nonce);
- GNUNET_RECLAIM_attribute_list_destroy (cl);
- GNUNET_RECLAIM_presentation_list_destroy (pl);
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- // TODO OPTIONAL acr,amr,azp
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
- "reclaim-rest-plugin",
- "jwt_secret",
- &jwt_secret))
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
- handle->edesc = GNUNET_strdup ("No signing secret configured!");
- handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- GNUNET_free (code);
- GNUNET_RECLAIM_attribute_list_destroy (cl);
- GNUNET_RECLAIM_presentation_list_destroy (pl);
- if (NULL != nonce)
- GNUNET_free (nonce);
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- id_token = OIDC_generate_id_token (&ticket.audience,
- &ticket.identity,
- cl,
- pl,
- &expiration_time,
- (NULL != nonce) ? nonce : NULL,
- jwt_secret);
- GNUNET_free (jwt_secret);
- if (NULL != nonce)
- GNUNET_free (nonce);
- access_token = OIDC_access_token_new (&ticket);
- /* Store mapping from access token to code so we can later
- * fall back on the provided attributes in userinfo
- */
- GNUNET_CRYPTO_hash (access_token,
- strlen (access_token),
- &cache_key);
- char *tmp_at = GNUNET_CONTAINER_multihashmap_get (oidc_code_cache,
- &cache_key);
- GNUNET_CONTAINER_multihashmap_put (oidc_code_cache,
- &cache_key,
- code,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
- /* If there was a previous code in there, free the old value */
- if (NULL != tmp_at)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "OIDC access token already issued. Cleanup.\n");
- GNUNET_free (tmp_at);
- }
- OIDC_build_token_response (access_token,
- id_token,
- &expiration_time,
- &json_response);
- resp = GNUNET_REST_create_response (json_response);
- GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
- "Cache-Control",
- "no-store"));
- GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
- "Pragma", "no-cache"));
- GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
- "Content-Type",
- "application/json"));
- handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- GNUNET_RECLAIM_attribute_list_destroy (cl);
- GNUNET_RECLAIM_presentation_list_destroy (pl);
- GNUNET_free (access_token);
- GNUNET_free (json_response);
- GNUNET_free (id_token);
- cleanup_handle (handle);
- }
- /**
- * Collects claims and stores them in handle
- */
- static void
- consume_ticket (void *cls,
- const struct GNUNET_IDENTITY_PublicKey *identity,
- const struct GNUNET_RECLAIM_Attribute *attr,
- const struct GNUNET_RECLAIM_Presentation *presentation)
- {
- struct RequestHandle *handle = cls;
- struct GNUNET_RECLAIM_AttributeListEntry *ale;
- struct GNUNET_RECLAIM_PresentationListEntry *atle;
- struct MHD_Response *resp;
- char *result_str;
- if (NULL != handle->consume_timeout_op)
- GNUNET_SCHEDULER_cancel (handle->consume_timeout_op);
- handle->consume_timeout_op = NULL;
- handle->idp_op = NULL;
- if (NULL == identity)
- {
- result_str = OIDC_generate_userinfo (&handle->ticket.identity,
- handle->attr_userinfo_list,
- handle->presentations);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Userinfo: %s\n", result_str);
- resp = GNUNET_REST_create_response (result_str);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- GNUNET_free (result_str);
- cleanup_handle (handle);
- return;
- }
- ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
- ale->attribute = GNUNET_RECLAIM_attribute_new (attr->name,
- &attr->credential,
- attr->type,
- attr->data,
- attr->data_size);
- ale->attribute->id = attr->id;
- ale->attribute->flag = attr->flag;
- ale->attribute->credential = attr->credential;
- GNUNET_CONTAINER_DLL_insert (handle->attr_userinfo_list->list_head,
- handle->attr_userinfo_list->list_tail,
- ale);
- if (NULL == presentation)
- return;
- for (atle = handle->presentations->list_head;
- NULL != atle; atle = atle->next)
- {
- if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (
- &atle->presentation->credential_id,
- &presentation->credential_id))
- continue;
- break; /** already in list **/
- }
- if (NULL == atle)
- {
- /** Credential matches for attribute, add **/
- atle = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry);
- atle->presentation = GNUNET_RECLAIM_presentation_new (presentation->type,
- presentation->data,
- presentation->
- data_size);
- atle->presentation->credential_id = presentation->credential_id;
- GNUNET_CONTAINER_DLL_insert (handle->presentations->list_head,
- handle->presentations->list_tail,
- atle);
- }
- }
- static void
- consume_timeout (void*cls)
- {
- struct RequestHandle *handle = cls;
- struct GNUNET_HashCode cache_key;
- struct GNUNET_RECLAIM_AttributeList *cl = NULL;
- struct GNUNET_RECLAIM_PresentationList *pl = NULL;
- struct GNUNET_RECLAIM_Ticket ticket;
- char *nonce;
- char *cached_code;
- handle->consume_timeout_op = NULL;
- if (NULL != handle->idp_op)
- GNUNET_RECLAIM_cancel (handle->idp_op);
- handle->idp_op = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Ticket consumptioned timed out. Using cache...\n");
- GNUNET_CRYPTO_hash (handle->access_token,
- strlen (handle->access_token),
- &cache_key);
- cached_code = GNUNET_CONTAINER_multihashmap_get (oidc_code_cache,
- &cache_key);
- if (NULL == cached_code)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
- handle->edesc = GNUNET_strdup ("No Access Token in cache!");
- handle->response_code = MHD_HTTP_UNAUTHORIZED;
- GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
- return;
- }
- // decode code
- if (GNUNET_OK != OIDC_parse_authz_code (&handle->ticket.audience,
- cached_code, NULL, &ticket,
- &cl, &pl, &nonce,
- OIDC_VERIFICATION_NO_CODE_VERIFIER))
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
- handle->edesc = GNUNET_strdup ("invalid code");
- handle->response_code = MHD_HTTP_BAD_REQUEST;
- GNUNET_free (cached_code);
- if (NULL != nonce)
- GNUNET_free (nonce);
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- struct MHD_Response *resp;
- char *result_str;
- result_str = OIDC_generate_userinfo (&handle->ticket.identity,
- cl,
- pl);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Userinfo: %s\n", result_str);
- resp = GNUNET_REST_create_response (result_str);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- GNUNET_free (result_str);
- GNUNET_free (nonce);
- GNUNET_RECLAIM_attribute_list_destroy (cl);
- GNUNET_RECLAIM_presentation_list_destroy (pl);
- cleanup_handle (handle);
- }
- /**
- * Responds to userinfo GET and url-encoded POST request
- *
- * @param con_handle the connection handle
- * @param url the url
- * @param cls the RequestHandle
- */
- static void
- userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
- const char *url,
- void *cls)
- {
- // TODO expiration time
- struct RequestHandle *handle = cls;
- struct GNUNET_RECLAIM_Ticket *ticket;
- char delimiter[] = " ";
- struct GNUNET_HashCode cache_key;
- char *authorization;
- char *authorization_type;
- char *authorization_access_token;
- const struct EgoEntry *aud_ego;
- const struct GNUNET_IDENTITY_PrivateKey *privkey;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting userinfo\n");
- GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
- strlen (OIDC_AUTHORIZATION_HEADER_KEY),
- &cache_key);
- if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
- ->header_param_map,
- &cache_key))
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
- handle->edesc = GNUNET_strdup ("No Access Token");
- handle->response_code = MHD_HTTP_UNAUTHORIZED;
- GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
- return;
- }
- authorization =
- GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
- &cache_key);
- // split header in "Bearer" and access_token
- authorization = GNUNET_strdup (authorization);
- authorization_type = strtok (authorization, delimiter);
- if ((NULL == authorization_type) ||
- (0 != strcmp ("Bearer", authorization_type)))
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
- handle->edesc = GNUNET_strdup ("No Access Token");
- handle->response_code = MHD_HTTP_UNAUTHORIZED;
- GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
- GNUNET_free (authorization);
- return;
- }
- authorization_access_token = strtok (NULL, delimiter);
- if (NULL == authorization_access_token)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
- handle->edesc = GNUNET_strdup ("Access token missing");
- handle->response_code = MHD_HTTP_UNAUTHORIZED;
- GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
- GNUNET_free (authorization);
- return;
- }
- if (GNUNET_OK != OIDC_access_token_parse (authorization_access_token,
- &ticket))
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
- handle->edesc = GNUNET_strdup ("The access token is invalid");
- handle->response_code = MHD_HTTP_UNAUTHORIZED;
- GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
- GNUNET_free (authorization);
- return;
- }
- GNUNET_assert (NULL != ticket);
- handle->ticket = *ticket;
- GNUNET_free (ticket);
- aud_ego = find_ego (handle, &handle->ticket.audience);
- if (NULL == aud_ego)
- {
- handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
- handle->edesc = GNUNET_strdup ("The access token expired");
- handle->response_code = MHD_HTTP_UNAUTHORIZED;
- GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
- GNUNET_free (authorization);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Consuming ticket\n");
- privkey = GNUNET_IDENTITY_ego_get_private_key (aud_ego->ego);
- handle->attr_userinfo_list =
- GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
- handle->presentations =
- GNUNET_new (struct GNUNET_RECLAIM_PresentationList);
- /* If the consume takes too long, we use values from the cache */
- handle->access_token = GNUNET_strdup (authorization_access_token);
- handle->consume_timeout_op = GNUNET_SCHEDULER_add_delayed (CONSUME_TIMEOUT,
- &consume_timeout,
- handle);
- handle->idp_op = GNUNET_RECLAIM_ticket_consume (idp,
- privkey,
- &handle->ticket,
- &consume_ticket,
- handle);
- GNUNET_free (authorization);
- }
- /**
- * If listing is enabled, prints information about the egos.
- *
- * This function is initially called for all egos and then again
- * whenever a ego's identifier changes or if it is deleted. At the
- * end of the initial pass over all egos, the function is once called
- * with 'NULL' for 'ego'. That does NOT mean that the callback won't
- * be invoked in the future or that there was an error.
- *
- * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', this
- * function is only called ONCE, and 'NULL' being passed in 'ego' does
- * indicate an error (for example because name is taken or no default value is
- * known). If 'ego' is non-NULL and if '*ctx' is set in those callbacks, the
- * value WILL be passed to a subsequent call to the identity callback of
- * 'GNUNET_IDENTITY_connect' (if that one was not NULL).
- *
- * When an identity is renamed, this function is called with the
- * (known) ego but the NEW identifier.
- *
- * When an identity is deleted, this function is called with the
- * (known) ego and "NULL" for the 'identifier'. In this case,
- * the 'ego' is henceforth invalid (and the 'ctx' should also be
- * cleaned up).
- *
- * @param cls closure
- * @param ego ego handle
- * @param ctx context for application to store data for this ego
- * (during the lifetime of this process, initially NULL)
- * @param identifier identifier assigned by the user for this ego,
- * NULL if the user just deleted the ego and it
- * must thus no longer be used
- */
- static void
- list_ego (void *cls,
- struct GNUNET_IDENTITY_Ego *ego,
- void **ctx,
- const char *identifier)
- {
- struct EgoEntry *ego_entry;
- struct GNUNET_IDENTITY_PublicKey pk;
- if (NULL == ego)
- {
- state = ID_REST_STATE_POST_INIT;
- return;
- }
- if (ID_REST_STATE_INIT == state)
- {
- ego_entry = GNUNET_new (struct EgoEntry);
- GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
- ego_entry->keystring = GNUNET_IDENTITY_public_key_to_string (&pk);
- ego_entry->ego = ego;
- ego_entry->identifier = GNUNET_strdup (identifier);
- GNUNET_CONTAINER_DLL_insert_tail (ego_head,
- ego_tail,
- ego_entry);
- return;
- }
- /* Ego renamed or added */
- if (identifier != NULL)
- {
- for (ego_entry = ego_head; NULL != ego_entry;
- ego_entry = ego_entry->next)
- {
- if (ego_entry->ego == ego)
- {
- /* Rename */
- GNUNET_free (ego_entry->identifier);
- ego_entry->identifier = GNUNET_strdup (identifier);
- break;
- }
- }
- if (NULL == ego_entry)
- {
- /* Add */
- ego_entry = GNUNET_new (struct EgoEntry);
- GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
- ego_entry->keystring = GNUNET_IDENTITY_public_key_to_string (&pk);
- ego_entry->ego = ego;
- ego_entry->identifier = GNUNET_strdup (identifier);
- GNUNET_CONTAINER_DLL_insert_tail (ego_head,
- ego_tail,
- ego_entry);
- }
- }
- else
- {
- /* Delete */
- for (ego_entry = ego_head; NULL != ego_entry;
- ego_entry = ego_entry->next)
- {
- if (ego_entry->ego == ego)
- break;
- }
- if (NULL == ego_entry)
- return; /* Not found */
- GNUNET_CONTAINER_DLL_remove (ego_head,
- ego_tail,
- ego_entry);
- GNUNET_free (ego_entry->identifier);
- GNUNET_free (ego_entry->keystring);
- GNUNET_free (ego_entry);
- return;
- }
- }
- static void
- oidc_config_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
- const char *url,
- void *cls)
- {
- json_t *oidc_config;
- json_t *auth_methods;
- json_t *sig_algs;
- json_t *scopes;
- json_t *response_types;
- json_t *sub_types;
- json_t *claim_types;
- char *oidc_config_str;
- struct MHD_Response *resp;
- struct RequestHandle *handle = cls;
- oidc_config = json_object ();
- // FIXME get from config?
- json_object_set_new (oidc_config,
- "issuer", json_string ("http://localhost:7776"));
- json_object_set_new (oidc_config,
- "authorization_endpoint",
- json_string ("https://api.reclaim/openid/authorize"));
- json_object_set_new (oidc_config,
- "token_endpoint",
- json_string ("http://localhost:7776/openid/token"));
- auth_methods = json_array ();
- json_array_append_new (auth_methods,
- json_string ("client_secret_basic"));
- json_array_append_new (auth_methods,
- json_string ("client_secret_post"));
- json_object_set_new (oidc_config,
- "token_endpoint_auth_methods_supported",
- auth_methods);
- sig_algs = json_array ();
- json_array_append_new (sig_algs,
- json_string ("HS512"));
- json_object_set_new (oidc_config,
- "id_token_signing_alg_values_supported",
- sig_algs);
- json_object_set_new (oidc_config,
- "userinfo_endpoint",
- json_string ("http://localhost:7776/openid/userinfo"));
- scopes = json_array ();
- json_array_append_new (scopes,
- json_string ("openid"));
- json_array_append_new (scopes,
- json_string ("profile"));
- json_array_append_new (scopes,
- json_string ("email"));
- json_array_append_new (scopes,
- json_string ("address"));
- json_array_append_new (scopes,
- json_string ("phone"));
- json_object_set_new (oidc_config,
- "scopes_supported",
- scopes);
- response_types = json_array ();
- json_array_append_new (response_types,
- json_string ("code"));
- json_object_set_new (oidc_config,
- "response_types_supported",
- response_types);
- sub_types = json_array ();
- json_array_append_new (sub_types,
- json_string ("public")); /* no pairwise support */
- json_object_set_new (oidc_config,
- "subject_types_supported",
- sub_types);
- claim_types = json_array ();
- json_array_append_new (claim_types,
- json_string ("normal"));
- json_array_append_new (claim_types,
- json_string ("aggregated"));
- json_object_set_new (oidc_config,
- "claim_types_supported",
- claim_types);
- json_object_set_new (oidc_config,
- "claims_parameter_supported",
- json_boolean (1));
- oidc_config_str = json_dumps (oidc_config, JSON_INDENT (1));
- resp = GNUNET_REST_create_response (oidc_config_str);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- json_decref (oidc_config);
- GNUNET_free (oidc_config_str);
- cleanup_handle (handle);
- }
- /**
- * Respond to OPTIONS request
- *
- * @param con_handle the connection handle
- * @param url the url
- * @param cls the RequestHandle
- */
- static void
- oidc_config_cors (struct GNUNET_REST_RequestHandle *con_handle,
- const char *url,
- void *cls)
- {
- struct MHD_Response *resp;
- struct RequestHandle *handle = cls;
- // For now, independent of path return all options
- resp = GNUNET_REST_create_response (NULL);
- GNUNET_assert (MHD_NO !=
- MHD_add_response_header (resp,
- "Access-Control-Allow-Methods",
- allow_methods));
- GNUNET_assert (MHD_NO !=
- MHD_add_response_header (resp,
- "Access-Control-Allow-Origin",
- "*"));
- handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- cleanup_handle (handle);
- return;
- }
- static enum GNUNET_GenericReturnValue
- rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
- GNUNET_REST_ResultProcessor proc,
- void *proc_cls)
- {
- struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
- struct GNUNET_REST_RequestHandlerError err;
- static const struct GNUNET_REST_RequestHandler handlers[] =
- { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint },
- { MHD_HTTP_METHOD_POST,
- GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint }, // url-encoded
- { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont },
- { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
- { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
- { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
- { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_OIDC_CONFIG,
- &oidc_config_endpoint },
- { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC_CONFIG,
- &oidc_config_cors },
- { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, &options_cont },
- GNUNET_REST_HANDLER_END };
- handle->oidc = GNUNET_new (struct OIDC_Variables);
- if (NULL == OIDC_cookie_jar_map)
- OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10,
- GNUNET_NO);
- if (NULL == oidc_code_cache)
- oidc_code_cache = GNUNET_CONTAINER_multihashmap_create (10,
- GNUNET_NO);
- handle->response_code = 0;
- handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
- handle->proc_cls = proc_cls;
- handle->proc = proc;
- handle->rest_handle = rest_handle;
- handle->url = GNUNET_strdup (rest_handle->url);
- handle->timeout_task =
- GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
- GNUNET_CONTAINER_DLL_insert (requests_head,
- requests_tail,
- handle);
- if (handle->url[strlen (handle->url) - 1] == '/')
- handle->url[strlen (handle->url) - 1] = '\0';
- if (GNUNET_NO ==
- GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
- return GNUNET_NO;
- return GNUNET_YES;
- }
- /**
- * Entry point for the plugin.
- *
- * @param cls Config info
- * @return NULL on error, otherwise the plugin context
- */
- void *
- libgnunet_plugin_rest_openid_connect_init (void *cls)
- {
- static struct Plugin plugin;
- struct GNUNET_REST_Plugin *api;
- cfg = cls;
- if (NULL != plugin.cfg)
- return NULL; /* can only initialize once! */
- memset (&plugin, 0, sizeof(struct Plugin));
- plugin.cfg = cfg;
- api = GNUNET_new (struct GNUNET_REST_Plugin);
- api->cls = &plugin;
- api->name = GNUNET_REST_API_NS_OIDC;
- api->process_request = &rest_identity_process_request;
- identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL);
- gns_handle = GNUNET_GNS_connect (cfg);
- idp = GNUNET_RECLAIM_connect (cfg);
- state = ID_REST_STATE_INIT;
- GNUNET_asprintf (&allow_methods,
- "%s, %s, %s, %s, %s",
- MHD_HTTP_METHOD_GET,
- MHD_HTTP_METHOD_POST,
- MHD_HTTP_METHOD_PUT,
- MHD_HTTP_METHOD_DELETE,
- MHD_HTTP_METHOD_OPTIONS);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _ ("OpenID Connect REST API initialized\n"));
- return api;
- }
- static int
- cleanup_hashmap (void *cls, const struct GNUNET_HashCode *key, void *value)
- {
- GNUNET_free (value);
- return GNUNET_YES;
- }
- /**
- * Exit point from the plugin.
- *
- * @param cls the plugin context (as returned by "init")
- * @return always NULL
- */
- void *
- libgnunet_plugin_rest_openid_connect_done (void *cls)
- {
- struct GNUNET_REST_Plugin *api = cls;
- struct Plugin *plugin = api->cls;
- struct EgoEntry *ego_entry;
- plugin->cfg = NULL;
- while (NULL != requests_head)
- cleanup_handle (requests_head);
- if (NULL != OIDC_cookie_jar_map)
- {
- GNUNET_CONTAINER_multihashmap_iterate (OIDC_cookie_jar_map,
- &cleanup_hashmap,
- NULL);
- GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map);
- }
- if (NULL != oidc_code_cache)
- {
- GNUNET_CONTAINER_multihashmap_iterate (oidc_code_cache,
- &cleanup_hashmap,
- NULL);
- GNUNET_CONTAINER_multihashmap_destroy (oidc_code_cache);
- }
- GNUNET_free (allow_methods);
- if (NULL != gns_handle)
- GNUNET_GNS_disconnect (gns_handle);
- if (NULL != identity_handle)
- GNUNET_IDENTITY_disconnect (identity_handle);
- if (NULL != idp)
- GNUNET_RECLAIM_disconnect (idp);
- while (NULL != (ego_entry = ego_head))
- {
- GNUNET_CONTAINER_DLL_remove (ego_head,
- ego_tail,
- ego_entry);
- GNUNET_free (ego_entry->identifier);
- GNUNET_free (ego_entry->keystring);
- GNUNET_free (ego_entry);
- }
- GNUNET_free (api);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "OpenID Connect REST plugin is finished\n");
- return NULL;
- }
- /* end of plugin_rest_openid_connect.c */
|