aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSchanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de>2018-02-25 16:23:42 +0100
committerSchanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de>2018-02-25 16:23:42 +0100
commit82e4a63b4ef0f5de0cfaedd6f8789c4a1ccfed91 (patch)
tree129f4d571ee4bff86fd169c9c46c94fb73979e7c /src
parentd4ad64d79b26163f8bcd78d32fe463082b9ed8de (diff)
parentbbe8e9a4e5bc9b60a5cc5f54385e6252a0487aea (diff)
downloadgnunet-82e4a63b4ef0f5de0cfaedd6f8789c4a1ccfed91.tar.gz
gnunet-82e4a63b4ef0f5de0cfaedd6f8789c4a1ccfed91.zip
-fix
Diffstat (limited to 'src')
-rw-r--r--src/identity-attribute/identity_attribute.c28
-rw-r--r--src/identity-provider/jwt.c33
-rw-r--r--src/identity-provider/jwt.h9
-rw-r--r--src/identity-provider/plugin_rest_identity_provider.c1551
-rw-r--r--src/identity-provider/test_idp.conf7
-rw-r--r--src/include/gnunet_identity_attribute_lib.h6
-rw-r--r--src/include/gnunet_rest_lib.h23
-rw-r--r--src/rest/gnunet-rest-server.c17
-rw-r--r--src/rest/rest.conf2
9 files changed, 1643 insertions, 33 deletions
diff --git a/src/identity-attribute/identity_attribute.c b/src/identity-attribute/identity_attribute.c
index cf50d058e..0111668fe 100644
--- a/src/identity-attribute/identity_attribute.c
+++ b/src/identity-attribute/identity_attribute.c
@@ -240,6 +240,34 @@ GNUNET_IDENTITY_ATTRIBUTE_claim_new (const char* attr_name,
240 return attr; 240 return attr;
241} 241}
242 242
243/**
244 * Add a new claim list entry.
245 *
246 * @param claim_list the attribute name
247 * @param attr_name the attribute name
248 * @param type the attribute type
249 * @param data the attribute value
250 * @param data_size the attribute value size
251 * @return
252 */
253void
254GNUNET_IDENTITY_ATTRIBUTE_list_add (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *claim_list,
255 const char* attr_name,
256 uint32_t type,
257 const void* data,
258 size_t data_size)
259{
260 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
261 le = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry);
262 le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr_name,
263 type,
264 data,
265 data_size);
266 GNUNET_CONTAINER_DLL_insert (claim_list->list_head,
267 claim_list->list_tail,
268 le);
269}
270
243size_t 271size_t
244GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) 272GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs)
245{ 273{
diff --git a/src/identity-provider/jwt.c b/src/identity-provider/jwt.c
index 2f1e3240b..ff3676cb6 100644
--- a/src/identity-provider/jwt.c
+++ b/src/identity-provider/jwt.c
@@ -33,12 +33,15 @@
33#define JWT_ALG "alg" 33#define JWT_ALG "alg"
34 34
35/*TODO is this the correct way to define new algs? */ 35/*TODO is this the correct way to define new algs? */
36#define JWT_ALG_VALUE "ED512" 36#define JWT_ALG_VALUE "urn:org:gnunet:jwt:alg:ecdsa:ed25519"
37 37
38#define JWT_TYP "typ" 38#define JWT_TYP "typ"
39 39
40#define JWT_TYP_VALUE "jwt" 40#define JWT_TYP_VALUE "jwt"
41 41
42//TODO change server address
43#define SERVER_ADDRESS "https://localhost"
44
42static char* 45static char*
43create_jwt_header(void) 46create_jwt_header(void)
44{ 47{
@@ -57,22 +60,22 @@ create_jwt_header(void)
57/** 60/**
58 * Create a JWT from attributes 61 * Create a JWT from attributes
59 * 62 *
60 * @param sub_key the public of the subject 63 * @param aud_key the public of the subject
61 * @param attrs the attribute list 64 * @param attrs the attribute list
62 * @param priv_key the key used to sign the JWT 65 * @param priv_key the key used to sign the JWT
63 * @return a new base64-encoded JWT string. 66 * @return a new base64-encoded JWT string.
64 */ 67 */
65char* 68char*
66jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, 69jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
67 const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs, 70 const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs,
68 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key) 71 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key)
69{ 72{
70 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; 73 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
71 struct GNUNET_CRYPTO_EcdsaPublicKey iss_key; 74 struct GNUNET_CRYPTO_EcdsaPublicKey sub_key;
72 struct GNUNET_CRYPTO_EcdsaSignature signature; 75 struct GNUNET_CRYPTO_EcdsaSignature signature;
73 struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; 76 struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
74 char* audience; 77 char* audience;
75 char* issuer; 78 char* subject;
76 char* header; 79 char* header;
77 char* padding; 80 char* padding;
78 char* body_str; 81 char* body_str;
@@ -84,20 +87,28 @@ jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key,
84 char* attr_val_str; 87 char* attr_val_str;
85 json_t* body; 88 json_t* body;
86 89
87 GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, &iss_key); 90 //exp REQUIRED time expired from config
91 //iat REQUIRED time now
92 //auth_time only if max_age
93 //nonce only if nonce
94 // OPTIONAL acr,amr,azp
95 GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, &sub_key);
88 /* TODO maybe we should use a local identity here */ 96 /* TODO maybe we should use a local identity here */
89 issuer = GNUNET_STRINGS_data_to_string_alloc (&iss_key, 97 subject = GNUNET_STRINGS_data_to_string_alloc (&sub_key,
90 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); 98 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
91 audience = GNUNET_STRINGS_data_to_string_alloc (sub_key, 99 audience = GNUNET_STRINGS_data_to_string_alloc (aud_key,
92 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); 100 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
93 header = create_jwt_header (); 101 header = create_jwt_header ();
94 body = json_object (); 102 body = json_object ();
95 /* TODO who is the issuer? local IdP or subject ? See self-issued tokens? */ 103 /* TODO who is the issuer? local IdP or subject ? See self-issued tokens? */
104 //iss REQUIRED case sensitive server uri with https
96 json_object_set_new (body, 105 json_object_set_new (body,
97 "iss", json_string (issuer)); 106 "iss", json_string (SERVER_ADDRESS));
107 //sub REQUIRED public key identity, not exceed 255 ASCII length
98 json_object_set_new (body, 108 json_object_set_new (body,
99 "sub", json_string (issuer)); 109 "sub", json_string (subject));
100 /* TODO what should be in here exactly? */ 110 /* TODO what should be in here exactly? */
111 //aud REQUIRED public key client_id must be there
101 json_object_set_new (body, 112 json_object_set_new (body,
102 "aud", json_string (audience)); 113 "aud", json_string (audience));
103 for (le = attrs->list_head; NULL != le; le = le->next) 114 for (le = attrs->list_head; NULL != le; le = le->next)
@@ -135,7 +146,7 @@ jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key,
135 while (NULL != padding) 146 while (NULL != padding)
136 padding = strtok(NULL, "="); 147 padding = strtok(NULL, "=");
137 148
138 GNUNET_free (issuer); 149 GNUNET_free (subject);
139 GNUNET_free (audience); 150 GNUNET_free (audience);
140 151
141 /** 152 /**
diff --git a/src/identity-provider/jwt.h b/src/identity-provider/jwt.h
new file mode 100644
index 000000000..072958973
--- /dev/null
+++ b/src/identity-provider/jwt.h
@@ -0,0 +1,9 @@
1#ifndef JWT_H
2#define JWT_H
3
4char*
5jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
6 const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs,
7 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key);
8
9#endif
diff --git a/src/identity-provider/plugin_rest_identity_provider.c b/src/identity-provider/plugin_rest_identity_provider.c
index 6eb856435..033c6e4ba 100644
--- a/src/identity-provider/plugin_rest_identity_provider.c
+++ b/src/identity-provider/plugin_rest_identity_provider.c
@@ -39,6 +39,7 @@
39#include "gnunet_signatures.h" 39#include "gnunet_signatures.h"
40#include "gnunet_identity_attribute_lib.h" 40#include "gnunet_identity_attribute_lib.h"
41#include "gnunet_identity_provider_service.h" 41#include "gnunet_identity_provider_service.h"
42#include "jwt.h"
42 43
43/** 44/**
44 * REST root namespace 45 * REST root namespace
@@ -66,6 +67,26 @@
66#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume" 67#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume"
67 68
68/** 69/**
70 * Authorize endpoint
71 */
72#define GNUNET_REST_API_NS_AUTHORIZE "/idp/authorize"
73
74/**
75 * Token endpoint
76 */
77#define GNUNET_REST_API_NS_TOKEN "/idp/token"
78
79/**
80 * UserInfo endpoint
81 */
82#define GNUNET_REST_API_NS_USERINFO "/idp/userinfo"
83
84/**
85 * Login namespace
86 */
87#define GNUNET_REST_API_NS_LOGIN "/idp/login"
88
89/**
69 * Attribute key 90 * Attribute key
70 */ 91 */
71#define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute" 92#define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute"
@@ -91,6 +112,110 @@
91 */ 112 */
92#define ID_REST_STATE_POST_INIT 1 113#define ID_REST_STATE_POST_INIT 1
93 114
115/**
116 * OIDC grant_type key
117 */
118#define OIDC_GRANT_TYPE_KEY "grant_type"
119
120/**
121 * OIDC grant_type key
122 */
123#define OIDC_GRANT_TYPE_VALUE "authorization_code"
124
125/**
126 * OIDC code key
127 */
128#define OIDC_CODE_KEY "code"
129
130/**
131 * OIDC response_type key
132 */
133#define OIDC_RESPONSE_TYPE_KEY "response_type"
134
135/**
136 * OIDC client_id key
137 */
138#define OIDC_CLIENT_ID_KEY "client_id"
139
140/**
141 * OIDC scope key
142 */
143#define OIDC_SCOPE_KEY "scope"
144
145/**
146 * OIDC redirect_uri key
147 */
148#define OIDC_REDIRECT_URI_KEY "redirect_uri"
149
150/**
151 * OIDC state key
152 */
153#define OIDC_STATE_KEY "state"
154
155/**
156 * OIDC nonce key
157 */
158#define OIDC_NONCE_KEY "nonce"
159
160/**
161 * OIDC cookie header key
162 */
163#define OIDC_COOKIE_HEADER_KEY "Cookie"
164
165/**
166 * OIDC cookie header information key
167 */
168#define OIDC_AUTHORIZATION_HEADER_KEY "Authorization"
169
170/**
171 * OIDC cookie header information key
172 */
173#define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
174
175/**
176 * OIDC expected response_type while authorizing
177 */
178#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
179
180/**
181 * OIDC expected scope part while authorizing
182 */
183#define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
184
185/**
186 * OIDC ignored parameter array
187 */
188char* OIDC_ignored_parameter_array [] =
189{
190 "display",
191 "prompt",
192 "max_age",
193 "ui_locales",
194 "response_mode",
195 "id_token_hint",
196 "login_hint",
197 "acr_values"
198};
199
200/**
201 * OIDC authorized identities and times hashmap
202 */
203struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time;
204
205/**
206 * OIDC authorized identities and times hashmap
207 */
208struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants;
209
210/**
211 * OIDC ticket/code use only once
212 */
213struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once;
214
215/**
216 * OIDC access_token to ticket and ego
217 */
218struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token;
94 219
95/** 220/**
96 * The configuration handle 221 * The configuration handle
@@ -109,6 +234,33 @@ struct Plugin
109{ 234{
110 const struct GNUNET_CONFIGURATION_Handle *cfg; 235 const struct GNUNET_CONFIGURATION_Handle *cfg;
111}; 236};
237/**
238 * OIDC needed variables
239 */
240struct OIDC_Variables
241{
242
243 struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
244
245 char *client_id;
246
247 int is_client_trusted;
248
249 char *redirect_uri;
250
251 char *scope;
252
253 char *state;
254
255 char *nonce;
256
257 char *response_type;
258
259 char *login_identity;
260
261 json_t *response;
262
263};
112 264
113/** 265/**
114 * The ego list 266 * The ego list
@@ -160,9 +312,14 @@ struct RequestHandle
160 struct EgoEntry *ego_entry; 312 struct EgoEntry *ego_entry;
161 313
162 /** 314 /**
163 * Ptr to current ego private key 315 * Pointer to ego private key
164 */ 316 */
165 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; 317 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
318
319 /**
320 * OIDC variables
321 */
322 struct OIDC_Variables *oidc;
166 323
167 /** 324 /**
168 * The processing state 325 * The processing state
@@ -179,6 +336,20 @@ struct RequestHandle
179 */ 336 */
180 struct GNUNET_REST_RequestHandle *rest_handle; 337 struct GNUNET_REST_RequestHandle *rest_handle;
181 338
339 /**
340 * Handle to NAMESTORE
341 */
342 struct GNUNET_NAMESTORE_Handle *namestore_handle;
343
344 /**
345 * Iterator for NAMESTORE
346 */
347 struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
348
349 /**
350 * Attribute claim list
351 */
352 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list;
182 353
183 /** 354 /**
184 * IDENTITY Operation 355 * IDENTITY Operation
@@ -236,6 +407,11 @@ struct RequestHandle
236 char *emsg; 407 char *emsg;
237 408
238 /** 409 /**
410 * Error response description
411 */
412 char *edesc;
413
414 /**
239 * Reponse code 415 * Reponse code
240 */ 416 */
241 int response_code; 417 int response_code;
@@ -247,8 +423,6 @@ struct RequestHandle
247 423
248}; 424};
249 425
250
251
252/** 426/**
253 * Cleanup lookup handle 427 * Cleanup lookup handle
254 * @param handle Handle to clean up 428 * @param handle Handle to clean up
@@ -256,6 +430,8 @@ struct RequestHandle
256static void 430static void
257cleanup_handle (struct RequestHandle *handle) 431cleanup_handle (struct RequestHandle *handle)
258{ 432{
433 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_entry;
434 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_tmp;
259 struct EgoEntry *ego_entry; 435 struct EgoEntry *ego_entry;
260 struct EgoEntry *ego_tmp; 436 struct EgoEntry *ego_tmp;
261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -276,6 +452,42 @@ cleanup_handle (struct RequestHandle *handle)
276 GNUNET_free (handle->url); 452 GNUNET_free (handle->url);
277 if (NULL != handle->emsg) 453 if (NULL != handle->emsg)
278 GNUNET_free (handle->emsg); 454 GNUNET_free (handle->emsg);
455 if (NULL != handle->edesc)
456 GNUNET_free (handle->edesc);
457 if (NULL != handle->namestore_handle)
458 GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
459 if (NULL != handle->oidc)
460 {
461 if (NULL != handle->oidc->client_id)
462 GNUNET_free(handle->oidc->client_id);
463 if (NULL != handle->oidc->login_identity)
464 GNUNET_free(handle->oidc->login_identity);
465 if (NULL != handle->oidc->nonce)
466 GNUNET_free(handle->oidc->nonce);
467 if (NULL != handle->oidc->redirect_uri)
468 GNUNET_free(handle->oidc->redirect_uri);
469 if (NULL != handle->oidc->response_type)
470 GNUNET_free(handle->oidc->response_type);
471 if (NULL != handle->oidc->scope)
472 GNUNET_free(handle->oidc->scope);
473 if (NULL != handle->oidc->state)
474 GNUNET_free(handle->oidc->state);
475 if (NULL != handle->oidc->response)
476 json_decref(handle->oidc->response);
477 GNUNET_free(handle->oidc);
478 }
479 if ( NULL != handle->attr_list )
480 {
481 for (claim_entry = handle->attr_list->list_head;
482 NULL != claim_entry;)
483 {
484 claim_tmp = claim_entry;
485 claim_entry = claim_entry->next;
486 GNUNET_free(claim_tmp->claim);
487 GNUNET_free(claim_tmp);
488 }
489 GNUNET_free (handle->attr_list);
490 }
279 for (ego_entry = handle->ego_head; 491 for (ego_entry = handle->ego_head;
280 NULL != ego_entry;) 492 NULL != ego_entry;)
281 { 493 {
@@ -285,6 +497,10 @@ cleanup_handle (struct RequestHandle *handle)
285 GNUNET_free (ego_tmp->keystring); 497 GNUNET_free (ego_tmp->keystring);
286 GNUNET_free (ego_tmp); 498 GNUNET_free (ego_tmp);
287 } 499 }
500 if (NULL != handle->attr_it)
501 {
502 GNUNET_free(handle->attr_it);
503 }
288 GNUNET_free (handle); 504 GNUNET_free (handle);
289} 505}
290 506
@@ -307,15 +523,74 @@ do_error (void *cls)
307 struct MHD_Response *resp; 523 struct MHD_Response *resp;
308 char *json_error; 524 char *json_error;
309 525
310 GNUNET_asprintf (&json_error, 526 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
311 "{Error while processing request: %s}", 527 handle->emsg,
312 handle->emsg); 528 (NULL != handle->edesc) ? handle->edesc : "",
529 (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
530 (NULL != handle->oidc->state) ? handle->oidc->state : "",
531 (NULL != handle->oidc->state) ? "\"" : "");
532 if ( 0 == handle->response_code )
533 {
534 handle->response_code = MHD_HTTP_BAD_REQUEST;
535 }
313 resp = GNUNET_REST_create_response (json_error); 536 resp = GNUNET_REST_create_response (json_error);
537 if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
538 {
539 MHD_add_response_header(resp, "WWW-Authenticate", "Basic");
540 }
541 MHD_add_response_header (resp, "Content-Type", "application/json");
314 handle->proc (handle->proc_cls, resp, handle->response_code); 542 handle->proc (handle->proc_cls, resp, handle->response_code);
315 cleanup_handle (handle); 543 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
316 GNUNET_free (json_error); 544 GNUNET_free (json_error);
317} 545}
318 546
547
548/**
549 * Task run on error, sends error message. Cleans up everything.
550 *
551 * @param cls the `struct RequestHandle`
552 */
553static void
554do_userinfo_error (void *cls)
555{
556 struct RequestHandle *handle = cls;
557 struct MHD_Response *resp;
558 char *error;
559
560 GNUNET_asprintf (&error, "error=\"%s\", error_description=\"%s\"",
561 handle->emsg,
562 (NULL != handle->edesc) ? handle->edesc : "");
563 resp = GNUNET_REST_create_response ("");
564 MHD_add_response_header(resp, "WWW-Authenticate", error);
565 handle->proc (handle->proc_cls, resp, handle->response_code);
566 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
567 GNUNET_free (error);
568}
569
570
571/**
572 * Task run on error, sends error message. Cleans up everything.
573 *
574 * @param cls the `struct RequestHandle`
575 */
576static void
577do_redirect_error (void *cls)
578{
579 struct RequestHandle *handle = cls;
580 struct MHD_Response *resp;
581 char* redirect;
582 GNUNET_asprintf (&redirect,
583 "%s?error=%s&error_description=%s%s%s",
584 handle->oidc->redirect_uri, handle->emsg, handle->edesc,
585 (NULL != handle->oidc->state) ? "&state=" : "",
586 (NULL != handle->oidc->state) ? handle->oidc->state : "");
587 resp = GNUNET_REST_create_response ("");
588 MHD_add_response_header (resp, "Location", redirect);
589 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
590 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
591 GNUNET_free (redirect);
592}
593
319/** 594/**
320 * Task run on timeout, sends error message. Cleans up everything. 595 * Task run on timeout, sends error message. Cleans up everything.
321 * 596 *
@@ -378,6 +653,39 @@ return_response (void *cls)
378 cleanup_handle (handle); 653 cleanup_handle (handle);
379} 654}
380 655
656/**
657 * Return attributes for claim
658 *
659 * @param cls the request handle
660 */
661static void
662return_userinfo_response (void *cls)
663{
664 char* result_str;
665 struct RequestHandle *handle = cls;
666 struct MHD_Response *resp;
667
668 result_str = json_dumps (handle->oidc->response, 0);
669
670 resp = GNUNET_REST_create_response (result_str);
671 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
672 GNUNET_free (result_str);
673 cleanup_handle (handle);
674}
675
676static char*
677base_64_encode(char *string)
678{
679 char *output;
680 GNUNET_STRINGS_base64_encode(string,strlen(string),&output);
681 int index = strlen(output)-1;
682 while ('=' == output[index])
683 {
684 output[index] = '\0';
685 index--;
686 }
687 return output;
688}
381 689
382static void 690static void
383collect_finished_cb (void *cls) 691collect_finished_cb (void *cls)
@@ -625,6 +933,7 @@ attr_collect (void *cls,
625 struct GNUNET_JSONAPI_Resource *json_resource; 933 struct GNUNET_JSONAPI_Resource *json_resource;
626 struct RequestHandle *handle = cls; 934 struct RequestHandle *handle = cls;
627 json_t *value; 935 json_t *value;
936 char* tmp_value;
628 937
629 if ((NULL == attr->name) || (NULL == attr->data)) 938 if ((NULL == attr->name) || (NULL == attr->data))
630 { 939 {
@@ -638,11 +947,17 @@ attr_collect (void *cls,
638 attr->name); 947 attr->name);
639 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); 948 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
640 949
641 value = json_string (attr->data); 950 tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type,
951 attr->data,
952 attr->data_size);
953
954 value = json_string (tmp_value);
955
642 GNUNET_JSONAPI_resource_add_attr (json_resource, 956 GNUNET_JSONAPI_resource_add_attr (json_resource,
643 "value", 957 "value",
644 value); 958 value);
645 json_decref (value); 959 json_decref (value);
960 GNUNET_free(tmp_value);
646 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it); 961 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
647} 962}
648 963
@@ -1013,6 +1328,1168 @@ options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1013} 1328}
1014 1329
1015/** 1330/**
1331 * Cookie interpretation
1332 */
1333static void
1334cookie_identity_interpretation (struct RequestHandle *handle)
1335{
1336 struct GNUNET_HashCode cache_key;
1337 char* cookies;
1338 struct GNUNET_TIME_Absolute current_time, *relog_time;
1339 char delimiter[] = "; ";
1340
1341 //gets identity of login try with cookie
1342 GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
1343 &cache_key);
1344 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
1345 &cache_key) )
1346 {
1347 //splits cookies and find 'Identity' cookie
1348 cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
1349 handle->oidc->login_identity = strtok(cookies, delimiter);
1350
1351 while ( NULL != handle->oidc->login_identity )
1352 {
1353 if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
1354 {
1355 break;
1356 }
1357 handle->oidc->login_identity = strtok (NULL, delimiter);
1358 }
1359 GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity),
1360 &cache_key);
1361 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) )
1362 {
1363 relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
1364 &cache_key);
1365 current_time = GNUNET_TIME_absolute_get ();
1366 // 30 min after old login -> redirect to login
1367 if ( current_time.abs_value_us <= relog_time->abs_value_us )
1368 {
1369 handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY);
1370 handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity);
1371 }
1372 }
1373 else
1374 {
1375 handle->oidc->login_identity = NULL;
1376 }
1377 }
1378}
1379
1380/**
1381 * Login redirection
1382 */
1383static void
1384login_redirection(void *cls)
1385{
1386 char *login_base_url;
1387 char *new_redirect;
1388 struct MHD_Response *resp;
1389 struct RequestHandle *handle = cls;
1390
1391 if ( GNUNET_OK
1392 == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
1393 "address", &login_base_url) )
1394 {
1395 GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
1396 login_base_url,
1397 OIDC_RESPONSE_TYPE_KEY,
1398 handle->oidc->response_type,
1399 OIDC_CLIENT_ID_KEY,
1400 handle->oidc->client_id,
1401 OIDC_REDIRECT_URI_KEY,
1402 handle->oidc->redirect_uri,
1403 OIDC_SCOPE_KEY,
1404 handle->oidc->scope,
1405 OIDC_STATE_KEY,
1406 (NULL != handle->oidc->state) ? handle->oidc->state : "",
1407 OIDC_NONCE_KEY,
1408 (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "");
1409 resp = GNUNET_REST_create_response ("");
1410 MHD_add_response_header (resp, "Location", new_redirect);
1411 GNUNET_free(login_base_url);
1412 }
1413 else
1414 {
1415 handle->emsg = GNUNET_strdup("server_error");
1416 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1417 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1418 GNUNET_SCHEDULER_add_now (&do_error, handle);
1419 return;
1420 }
1421 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1422 GNUNET_free(new_redirect);
1423 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1424}
1425
1426/**
1427 * Function called if we had an error in zone-to-name mapping.
1428 */
1429static void
1430oidc_iteration_error (void *cls)
1431{
1432 struct RequestHandle *handle = cls;
1433 handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR");
1434 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1435 GNUNET_SCHEDULER_add_now (&do_error, handle);
1436}
1437
1438static void
1439oidc_ticket_issue_cb (void* cls,
1440 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
1441{
1442 struct RequestHandle *handle = cls;
1443 struct MHD_Response *resp;
1444 char *ticket_str;
1445 char *redirect_uri;
1446 char *code_json_string;
1447 char *code_base64_final_string;
1448 handle->idp_op = NULL;
1449 resp = GNUNET_REST_create_response ("");
1450 if (NULL != ticket) {
1451 ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket,
1452 sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket));
1453 //TODO change if more attributes are needed (see max_age)
1454 GNUNET_asprintf (&code_json_string, "{\"ticket\":\"%s\"%s%s%s}",
1455 ticket_str,
1456 (NULL != handle->oidc->nonce) ? ", \"nonce\":\"" : "",
1457 (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "",
1458 (NULL != handle->oidc->nonce) ? "\"" : "");
1459 code_base64_final_string = base_64_encode(code_json_string);
1460 GNUNET_asprintf (&redirect_uri, "%s?%s=%s&state=%s",
1461 handle->oidc->redirect_uri,
1462 handle->oidc->response_type,
1463 code_base64_final_string, handle->oidc->state);
1464 MHD_add_response_header (resp, "Location", redirect_uri);
1465 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1466 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1467 GNUNET_free (redirect_uri);
1468 GNUNET_free (ticket_str);
1469 GNUNET_free (code_json_string);
1470 GNUNET_free (code_base64_final_string);
1471 return;
1472 }
1473 handle->emsg = GNUNET_strdup("server_error");
1474 handle->edesc = GNUNET_strdup("Server cannot generate ticket.");
1475 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1476}
1477
1478static void
1479oidc_collect_finished_cb (void *cls)
1480{
1481 struct RequestHandle *handle = cls;
1482 handle->attr_it = NULL;
1483 handle->ticket_it = NULL;
1484 if (NULL == handle->attr_list->list_head)
1485 {
1486 handle->emsg = GNUNET_strdup("invalid_scope");
1487 handle->edesc = GNUNET_strdup("The requested scope is not available.");
1488 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1489 return;
1490 }
1491 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_issue (handle->idp,
1492 &handle->priv_key,
1493 &handle->oidc->client_pkey,
1494 handle->attr_list,
1495 &oidc_ticket_issue_cb,
1496 handle);
1497}
1498
1499
1500/**
1501 * Collect all attributes for an ego
1502 */
1503static void
1504oidc_attr_collect (void *cls,
1505 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1506 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
1507{
1508 struct RequestHandle *handle = cls;
1509 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
1510 char* scope_variables;
1511 char* scope_variable;
1512 char delimiter[]=" ";
1513
1514 if ( (NULL == attr->name) || (NULL == attr->data) )
1515 {
1516 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1517 return;
1518 }
1519
1520 scope_variables = GNUNET_strdup(handle->oidc->scope);
1521 scope_variable = strtok (scope_variables, delimiter);
1522 while (NULL != scope_variable)
1523 {
1524 if ( 0 == strcmp (attr->name, scope_variable) )
1525 {
1526 break;
1527 }
1528 scope_variable = strtok (NULL, delimiter);
1529 }
1530 if ( NULL == scope_variable )
1531 {
1532 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1533 return;
1534 }
1535 GNUNET_free(scope_variables);
1536
1537 le = GNUNET_new(struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry);
1538 le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr->name, attr->type,
1539 attr->data, attr->data_size);
1540 GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head,
1541 handle->attr_list->list_tail, le);
1542 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1543}
1544
1545
1546/**
1547 * Cookie and Time check
1548 */
1549static void
1550login_check (void *cls)
1551{
1552 struct RequestHandle *handle = cls;
1553 struct GNUNET_TIME_Absolute current_time, *relog_time;
1554 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey;
1555 struct GNUNET_HashCode cache_key;
1556 char *identity_cookie;
1557
1558 GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity);
1559 GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1560 GNUNET_free(identity_cookie);
1561 //No login time for identity -> redirect to login
1562 if ( GNUNET_YES
1563 == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time,
1564 &cache_key) )
1565 {
1566 relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
1567 &cache_key);
1568 current_time = GNUNET_TIME_absolute_get ();
1569 // 30 min after old login -> redirect to login
1570 if ( current_time.abs_value_us <= relog_time->abs_value_us )
1571 {
1572 if ( GNUNET_OK
1573 != GNUNET_CRYPTO_ecdsa_public_key_from_string (
1574 handle->oidc->login_identity,
1575 strlen (handle->oidc->login_identity), &pubkey) )
1576 {
1577 handle->emsg = GNUNET_strdup("invalid_cookie");
1578 handle->edesc = GNUNET_strdup(
1579 "The cookie of a login identity is not valid");
1580 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1581 return;
1582 }
1583 // iterate over egos and compare their public key
1584 for (handle->ego_entry = handle->ego_head;
1585 NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
1586 {
1587 GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1588 if ( 0
1589 == memcmp (&ego_pkey, &pubkey,
1590 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1591 {
1592 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (
1593 handle->ego_entry->ego);
1594 handle->resp_object = GNUNET_JSONAPI_document_new ();
1595 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1596 handle->attr_list = GNUNET_new(
1597 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList);
1598 handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (
1599 handle->idp, &handle->priv_key, &oidc_iteration_error, handle,
1600 &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle);
1601 return;
1602 }
1603 }
1604 handle->emsg = GNUNET_strdup("invalid_cookie");
1605 handle->edesc = GNUNET_strdup(
1606 "The cookie of the login identity is not valid");
1607 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1608 return;
1609 }
1610 }
1611}
1612
1613/**
1614 * Create a response with requested records
1615 *
1616 * @param handle the RequestHandle
1617 */
1618static void
1619namestore_iteration_callback (
1620 void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1621 const char *rname, unsigned int rd_len,
1622 const struct GNUNET_GNSRECORD_Data *rd)
1623{
1624 struct RequestHandle *handle = cls;
1625 struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey;
1626 struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey;
1627 int i;
1628
1629 for (i = 0; i < rd_len; i++)
1630 {
1631 if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type )
1632 continue;
1633
1634 if ( NULL != handle->oidc->login_identity )
1635 {
1636 GNUNET_CRYPTO_ecdsa_public_key_from_string (
1637 handle->oidc->login_identity,
1638 strlen (handle->oidc->login_identity),
1639 &login_identity_pkey);
1640 GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego,
1641 &current_zone_pkey);
1642
1643 if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1644 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1645 {
1646 if ( 0 == memcmp (&login_identity_pkey, &current_zone_pkey,
1647 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1648 {
1649 handle->oidc->is_client_trusted = GNUNET_YES;
1650 }
1651 }
1652 }
1653 else
1654 {
1655 if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1656 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1657 {
1658 handle->oidc->is_client_trusted = GNUNET_YES;
1659 }
1660 }
1661 }
1662
1663 GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it);
1664}
1665
1666/**
1667 * Iteration over all results finished, build final
1668 * response.
1669 *
1670 * @param cls the `struct RequestHandle`
1671 */
1672static void namestore_iteration_finished (void *cls)
1673{
1674 struct RequestHandle *handle = cls;
1675 struct GNUNET_HashCode cache_key;
1676
1677 char *expected_redirect_uri;
1678 char *expected_scope;
1679 char delimiter[]=" ";
1680 int number_of_ignored_parameter, iterator;
1681
1682
1683 handle->ego_entry = handle->ego_entry->next;
1684
1685 if(NULL != handle->ego_entry)
1686 {
1687 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1688 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
1689 &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
1690 &namestore_iteration_finished, handle);
1691 return;
1692 }
1693 if (GNUNET_NO == handle->oidc->is_client_trusted)
1694 {
1695 handle->emsg = GNUNET_strdup("unauthorized_client");
1696 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1697 "authorization code using this method.");
1698 GNUNET_SCHEDULER_add_now (&do_error, handle);
1699 return;
1700 }
1701
1702 // REQUIRED value: redirect_uri
1703 GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1704 &cache_key);
1705 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1706 &cache_key))
1707 {
1708 handle->emsg=GNUNET_strdup("invalid_request");
1709 handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
1710 GNUNET_SCHEDULER_add_now (&do_error, handle);
1711 return;
1712 }
1713 handle->oidc->redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1714 &cache_key);
1715
1716 GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", handle->oidc->client_id);
1717 // verify the redirect uri matches https://<client_id>.zkey[/xyz]
1718 if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, strlen(expected_redirect_uri)) )
1719 {
1720 handle->emsg=GNUNET_strdup("invalid_request");
1721 handle->edesc=GNUNET_strdup("Invalid redirect_uri");
1722 GNUNET_SCHEDULER_add_now (&do_error, handle);
1723 GNUNET_free(expected_redirect_uri);
1724 return;
1725 }
1726 handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
1727
1728 GNUNET_free(expected_redirect_uri);
1729 // REQUIRED value: response_type
1730 GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
1731 &cache_key);
1732 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1733 &cache_key))
1734 {
1735 handle->emsg=GNUNET_strdup("invalid_request");
1736 handle->edesc=GNUNET_strdup("missing parameter response_type");
1737 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1738 return;
1739 }
1740 handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1741 &cache_key);
1742 handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
1743
1744 // REQUIRED value: scope
1745 GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
1746 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1747 &cache_key))
1748 {
1749 handle->emsg=GNUNET_strdup("invalid_request");
1750 handle->edesc=GNUNET_strdup("missing parameter scope");
1751 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1752 return;
1753 }
1754 handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1755 &cache_key);
1756 handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
1757
1758 //OPTIONAL value: nonce
1759 GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
1760 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1761 &cache_key))
1762 {
1763 handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1764 &cache_key);
1765 handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
1766 }
1767
1768 //TODO check other values if needed
1769 number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1770 for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1771 {
1772 GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1773 strlen(OIDC_ignored_parameter_array[iterator]),
1774 &cache_key);
1775 if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
1776 &cache_key))
1777 {
1778 handle->emsg=GNUNET_strdup("access_denied");
1779 GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1780 OIDC_ignored_parameter_array[iterator]);
1781 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1782 return;
1783 }
1784 }
1785
1786 // Checks if response_type is 'code'
1787 if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1788 {
1789 handle->emsg=GNUNET_strdup("unsupported_response_type");
1790 handle->edesc=GNUNET_strdup("The authorization server does not support "
1791 "obtaining this authorization code.");
1792 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1793 return;
1794 }
1795
1796 // Checks if scope contains 'openid'
1797 expected_scope = GNUNET_strdup(handle->oidc->scope);
1798 expected_scope = strtok (expected_scope, delimiter);
1799 while (NULL != expected_scope)
1800 {
1801 if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1802 {
1803 break;
1804 }
1805 expected_scope = strtok (NULL, delimiter);
1806 }
1807 if (NULL == expected_scope)
1808 {
1809 handle->emsg = GNUNET_strdup("invalid_scope");
1810 handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1811 "malformed.");
1812 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1813 return;
1814 }
1815
1816 GNUNET_free(expected_scope);
1817
1818 if( NULL != handle->oidc->login_identity )
1819 {
1820 GNUNET_SCHEDULER_add_now(&login_check,handle);
1821 return;
1822 }
1823
1824 GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1825}
1826
1827/**
1828 * Responds to authorization GET and url-encoded POST request
1829 *
1830 * @param con_handle the connection handle
1831 * @param url the url
1832 * @param cls the RequestHandle
1833 */
1834static void
1835authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1836 const char* url,
1837 void *cls)
1838{
1839 struct RequestHandle *handle = cls;
1840 struct GNUNET_HashCode cache_key;
1841
1842 cookie_identity_interpretation(handle);
1843
1844 //RECOMMENDED value: state - REQUIRED for answers
1845 GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
1846 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1847 &cache_key))
1848 {
1849 handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1850 &cache_key);
1851 handle->oidc->state = GNUNET_strdup (handle->oidc->state);
1852 }
1853
1854 // REQUIRED value: client_id
1855 GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
1856 &cache_key);
1857 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1858 &cache_key))
1859 {
1860 handle->emsg=GNUNET_strdup("invalid_request");
1861 handle->edesc=GNUNET_strdup("missing parameter client_id");
1862 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1863 GNUNET_SCHEDULER_add_now (&do_error, handle);
1864 return;
1865 }
1866 handle->oidc->client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1867 &cache_key);
1868 handle->oidc->client_id = GNUNET_strdup (handle->oidc->client_id);
1869
1870 if ( GNUNET_OK
1871 != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
1872 strlen (handle->oidc->client_id),
1873 &handle->oidc->client_pkey) )
1874 {
1875 handle->emsg = GNUNET_strdup("unauthorized_client");
1876 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1877 "authorization code using this method.");
1878 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1879 GNUNET_SCHEDULER_add_now (&do_error, handle);
1880 return;
1881 }
1882
1883
1884 if ( NULL == handle->ego_head )
1885 {
1886 handle->emsg = GNUNET_strdup("server_error");
1887 handle->edesc = GNUNET_strdup ("Egos are missing");
1888 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1889 GNUNET_SCHEDULER_add_now (&do_error, handle);
1890 return;
1891 }
1892
1893 handle->ego_entry = handle->ego_head;
1894 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
1895 handle->oidc->is_client_trusted = GNUNET_NO;
1896
1897 // Checks if client_id is valid:
1898 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
1899 handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
1900 handle, &namestore_iteration_callback, handle,
1901 &namestore_iteration_finished, handle);
1902}
1903
1904/**
1905 * Combines an identity with a login time and responds OK to login request
1906 *
1907 * @param con_handle the connection handle
1908 * @param url the url
1909 * @param cls the RequestHandle
1910 */
1911static void
1912login_cont (struct GNUNET_REST_RequestHandle *con_handle,
1913 const char* url,
1914 void *cls)
1915{
1916 struct MHD_Response *resp = GNUNET_REST_create_response ("");
1917 struct RequestHandle *handle = cls;
1918 struct GNUNET_HashCode cache_key;
1919 struct GNUNET_TIME_Absolute *current_time;
1920 struct GNUNET_TIME_Absolute *last_time;
1921 char* cookie;
1922 json_t *root;
1923 json_error_t error;
1924 json_t *identity;
1925 root = json_loads (handle->rest_handle->data, 0, &error);
1926 identity = json_object_get (root, "identity");
1927 if ( json_is_string(identity) )
1928 {
1929 GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1930
1931 GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1932
1933 current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
1934 *current_time = GNUNET_TIME_relative_to_absolute (
1935 GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_minute_ (),
1936 30));
1937 last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key);
1938 if (NULL != last_time)
1939 {
1940 GNUNET_free(last_time);
1941 }
1942 GNUNET_CONTAINER_multihashmap_put (
1943 OIDC_identity_login_time, &cache_key, current_time,
1944 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1945
1946 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1947 }
1948 else
1949 {
1950 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1951 }
1952 GNUNET_free(cookie);
1953 json_decref (root);
1954 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1955 return;
1956}
1957
1958static void
1959token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1960 const char* url,
1961 void *cls)
1962{
1963 //TODO static strings
1964
1965 struct RequestHandle *handle = cls;
1966 struct GNUNET_HashCode cache_key;
1967 char *authorization, *credentials;
1968 char delimiter[]=" ";
1969 char delimiter_user_psw[]=":";
1970 char *grant_type, *code, *redirect_uri, *expected_redirect_uri;
1971 char *user_psw = NULL, *client_id, *psw;
1972 char *expected_psw;
1973 int client_exists = GNUNET_NO;
1974 struct MHD_Response *resp;
1975 char* code_output;
1976 json_t *root, *ticket_string, *nonce, *max_age;
1977 json_error_t error;
1978 char *json_response;
1979
1980 /*
1981 * Check Authorization
1982 */
1983 GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
1984 strlen (OIDC_AUTHORIZATION_HEADER_KEY),
1985 &cache_key);
1986 if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
1987 &cache_key) )
1988 {
1989 handle->emsg=GNUNET_strdup("invalid_client");
1990 handle->edesc=GNUNET_strdup("missing authorization");
1991 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1992 GNUNET_SCHEDULER_add_now (&do_error, handle);
1993 return;
1994 }
1995 authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
1996
1997 //TODO authorization pointer will be moved as well
1998 //split header in "Basic" and [content]
1999 credentials = strtok (authorization, delimiter);
2000 if (0 != strcmp ("Basic",credentials))
2001 {
2002 handle->emsg=GNUNET_strdup("invalid_client");
2003 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2004 GNUNET_SCHEDULER_add_now (&do_error, handle);
2005 return;
2006 }
2007 credentials = strtok(NULL, delimiter);
2008 if (NULL == credentials)
2009 {
2010 handle->emsg=GNUNET_strdup("invalid_client");
2011 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2012 GNUNET_SCHEDULER_add_now (&do_error, handle);
2013 return;
2014 }
2015 GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), &user_psw);
2016
2017 if ( NULL == user_psw )
2018 {
2019 handle->emsg=GNUNET_strdup("invalid_client");
2020 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2021 GNUNET_SCHEDULER_add_now (&do_error, handle);
2022 return;
2023 }
2024 client_id = strtok (user_psw, delimiter_user_psw);
2025 if ( NULL == client_id )
2026 {
2027 GNUNET_free_non_null(user_psw);
2028 handle->emsg=GNUNET_strdup("invalid_client");
2029 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2030 GNUNET_SCHEDULER_add_now (&do_error, handle);
2031 return;
2032 }
2033 psw = strtok (NULL, delimiter_user_psw);
2034 if (NULL == psw)
2035 {
2036 GNUNET_free_non_null(user_psw);
2037 handle->emsg=GNUNET_strdup("invalid_client");
2038 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2039 GNUNET_SCHEDULER_add_now (&do_error, handle);
2040 return;
2041 }
2042 //check client password
2043 if ( GNUNET_OK
2044 == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
2045 "psw", &expected_psw) )
2046 {
2047 if (0 != strcmp (expected_psw, psw))
2048 {
2049 handle->emsg=GNUNET_strdup("invalid_client");
2050 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2051 GNUNET_SCHEDULER_add_now (&do_error, handle);
2052 return;
2053 }
2054 GNUNET_free(expected_psw);
2055 }
2056 else
2057 {
2058 handle->emsg = GNUNET_strdup("server_error");
2059 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2060 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2061 GNUNET_SCHEDULER_add_now (&do_error, handle);
2062 return;
2063 }
2064 //check client_id
2065 for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; )
2066 {
2067 if ( 0 == strcmp(handle->ego_entry->keystring, client_id))
2068 {
2069 client_exists = GNUNET_YES;
2070 break;
2071 }
2072 handle->ego_entry = handle->ego_entry->next;
2073 }
2074 if (GNUNET_NO == client_exists)
2075 {
2076 handle->emsg=GNUNET_strdup("invalid_client");
2077 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2078 GNUNET_SCHEDULER_add_now (&do_error, handle);
2079 return;
2080 }
2081
2082 /*
2083 * Check parameter
2084 */
2085
2086 //TODO Do not allow multiple equal parameter names
2087 //REQUIRED grant_type
2088 GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key);
2089 if ( GNUNET_NO
2090 == GNUNET_CONTAINER_multihashmap_contains (
2091 handle->rest_handle->url_param_map, &cache_key) )
2092 {
2093 handle->emsg = GNUNET_strdup("invalid_request");
2094 handle->edesc = GNUNET_strdup("missing parameter grant_type");
2095 handle->response_code = MHD_HTTP_BAD_REQUEST;
2096 GNUNET_SCHEDULER_add_now (&do_error, handle);
2097 return;
2098 }
2099 grant_type = GNUNET_CONTAINER_multihashmap_get (
2100 handle->rest_handle->url_param_map, &cache_key);
2101
2102 //REQUIRED code
2103 GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key);
2104 if ( GNUNET_NO
2105 == GNUNET_CONTAINER_multihashmap_contains (
2106 handle->rest_handle->url_param_map, &cache_key) )
2107 {
2108 handle->emsg = GNUNET_strdup("invalid_request");
2109 handle->edesc = GNUNET_strdup("missing parameter code");
2110 handle->response_code = MHD_HTTP_BAD_REQUEST;
2111 GNUNET_SCHEDULER_add_now (&do_error, handle);
2112 return;
2113 }
2114 code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
2115 &cache_key);
2116
2117 //REQUIRED redirect_uri
2118 GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
2119 &cache_key);
2120 if ( GNUNET_NO
2121 == GNUNET_CONTAINER_multihashmap_contains (
2122 handle->rest_handle->url_param_map, &cache_key) )
2123 {
2124 handle->emsg = GNUNET_strdup("invalid_request");
2125 handle->edesc = GNUNET_strdup("missing parameter redirect_uri");
2126 handle->response_code = MHD_HTTP_BAD_REQUEST;
2127 GNUNET_SCHEDULER_add_now (&do_error, handle);
2128 return;
2129 }
2130 redirect_uri = GNUNET_CONTAINER_multihashmap_get (
2131 handle->rest_handle->url_param_map, &cache_key);
2132
2133
2134 //Check parameter grant_type == "authorization_code"
2135 if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type))
2136 {
2137 handle->emsg=GNUNET_strdup("unsupported_grant_type");
2138 handle->response_code = MHD_HTTP_BAD_REQUEST;
2139 GNUNET_SCHEDULER_add_now (&do_error, handle);
2140 return;
2141 }
2142 // check redirect_uri
2143 GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", client_id);
2144 // verify the redirect uri matches https://<client_id>.zkey[/xyz]
2145 if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
2146 {
2147 handle->emsg=GNUNET_strdup("invalid_request");
2148 handle->edesc=GNUNET_strdup("Invalid redirect_uri");
2149 handle->response_code = MHD_HTTP_BAD_REQUEST;
2150 GNUNET_SCHEDULER_add_now (&do_error, handle);
2151 GNUNET_free(expected_redirect_uri);
2152 return;
2153 }
2154 GNUNET_free(expected_redirect_uri);
2155 GNUNET_CRYPTO_hash(code, strlen(code), &cache_key);
2156 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(OIDC_ticket_once,&cache_key))
2157 {
2158 handle->emsg = GNUNET_strdup("invalid_request");
2159 handle->edesc = GNUNET_strdup("Cannot use the same code more than once");
2160 handle->response_code = MHD_HTTP_BAD_REQUEST;
2161 GNUNET_SCHEDULER_add_now (&do_error, handle);
2162 return;
2163 }
2164 int i=1;
2165 GNUNET_CONTAINER_multihashmap_put(OIDC_ticket_once,&cache_key,&i,GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
2166
2167 //decode code
2168 GNUNET_STRINGS_base64_decode(code,strlen(code),&code_output);
2169 root = json_loads (code_output, 0, &error);
2170 GNUNET_free(code_output);
2171 ticket_string = json_object_get (root, "ticket");
2172 nonce = json_object_get (root, "nonce");
2173 max_age = json_object_get (root, "max_age");
2174
2175 if(ticket_string == NULL && !json_is_string(ticket_string))
2176 {
2177 handle->emsg = GNUNET_strdup("invalid_request");
2178 handle->edesc = GNUNET_strdup("invalid code");
2179 handle->response_code = MHD_HTTP_BAD_REQUEST;
2180 GNUNET_SCHEDULER_add_now (&do_error, handle);
2181 return;
2182 }
2183
2184 struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket = GNUNET_new(struct GNUNET_IDENTITY_PROVIDER_Ticket);
2185 if ( GNUNET_OK
2186 != GNUNET_STRINGS_string_to_data (json_string_value(ticket_string),
2187 strlen (json_string_value(ticket_string)),
2188 ticket,
2189 sizeof(struct GNUNET_IDENTITY_PROVIDER_Ticket)))
2190 {
2191 handle->emsg = GNUNET_strdup("invalid_request");
2192 handle->edesc = GNUNET_strdup("invalid code");
2193 handle->response_code = MHD_HTTP_BAD_REQUEST;
2194 GNUNET_SCHEDULER_add_now (&do_error, handle);
2195 GNUNET_free(ticket);
2196 return;
2197 }
2198 // this is the current client (relying party)
2199 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
2200 GNUNET_IDENTITY_ego_get_public_key(handle->ego_entry->ego,&pub_key);
2201 if (0 != memcmp(&pub_key,&ticket->audience,sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
2202 {
2203 handle->emsg = GNUNET_strdup("invalid_request");
2204 handle->edesc = GNUNET_strdup("invalid code");
2205 handle->response_code = MHD_HTTP_BAD_REQUEST;
2206 GNUNET_SCHEDULER_add_now (&do_error, handle);
2207 GNUNET_free(ticket);
2208 return;
2209 }
2210
2211 //create jwt
2212 unsigned long long int expiration_time;
2213 if ( GNUNET_OK
2214 != GNUNET_CONFIGURATION_get_value_number(cfg, "identity-rest-plugin",
2215 "expiration_time", &expiration_time) )
2216 {
2217 handle->emsg = GNUNET_strdup("server_error");
2218 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2219 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2220 GNUNET_SCHEDULER_add_now (&do_error, handle);
2221 GNUNET_free(ticket);
2222 return;
2223 }
2224
2225 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *cl = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList);
2226 //aud REQUIRED public key client_id must be there
2227 GNUNET_IDENTITY_ATTRIBUTE_list_add(cl,
2228 "aud",
2229 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2230 client_id,
2231 strlen(client_id));
2232 //exp REQUIRED time expired from config
2233 //TODO time as seconds
2234 struct GNUNET_TIME_Absolute exp_time = GNUNET_TIME_relative_to_absolute (
2235 GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (),
2236 expiration_time));
2237 const char* exp_time_string = GNUNET_STRINGS_absolute_time_to_string(exp_time);
2238 GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
2239 "exp",
2240 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2241 exp_time_string,
2242 strlen(exp_time_string));
2243 //iat REQUIRED time now
2244 //TODO time as seconds
2245 struct GNUNET_TIME_Absolute time_now = GNUNET_TIME_absolute_get();
2246 const char* time_now_string = GNUNET_STRINGS_absolute_time_to_string(time_now);
2247 GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
2248 "iat",
2249 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2250 time_now_string,
2251 strlen(time_now_string));
2252 //nonce only if nonce is provided
2253 if ( NULL != nonce && json_is_string(nonce) )
2254 {
2255 GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
2256 "nonce",
2257 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2258 json_string_value(nonce),
2259 strlen(json_string_value(nonce)));
2260 }
2261 //auth_time only if max_age is provided
2262 if ( NULL != max_age && json_is_string(max_age) )
2263 {
2264 GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
2265 "auth_time",
2266 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2267 json_string_value(max_age),
2268 strlen(json_string_value(max_age)));
2269 }
2270 //TODO OPTIONAL acr,amr,azp
2271
2272 //TODO lookup client for client == audience of ticket
2273 struct EgoEntry *ego_entry;
2274 for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
2275 {
2276 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
2277 if (0 == memcmp (&pub_key, &ticket->audience, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
2278 {
2279 break;
2280 }
2281 }
2282 if ( NULL == ego_entry )
2283 {
2284 handle->emsg = GNUNET_strdup("invalid_request");
2285 handle->edesc = GNUNET_strdup("invalid code....");
2286 handle->response_code = MHD_HTTP_BAD_REQUEST;
2287 GNUNET_SCHEDULER_add_now (&do_error, handle);
2288 GNUNET_free(ticket);
2289 return;
2290 }
2291 char *id_token = jwt_create_from_list(&ticket->audience,
2292 cl,
2293 GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego));
2294
2295 //Create random access_token
2296 char* access_token_number;
2297 char* access_token;
2298 uint64_t random_number;
2299 random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
2300 GNUNET_asprintf(&access_token_number, "%" PRIu64, random_number);
2301 GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token);
2302
2303
2304
2305 //TODO OPTIONAL add refresh_token and scope
2306 GNUNET_asprintf (&json_response,
2307 "{ \"access_token\" : \"%s\", "
2308 "\"token_type\" : \"Bearer\", "
2309 "\"expires_in\" : %d, "
2310 "\"id_token\" : \"%s\"}",
2311 access_token,
2312 expiration_time,
2313 id_token);
2314 GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key);
2315 char *id_ticket_combination;
2316 GNUNET_asprintf(&id_ticket_combination,
2317 "%s;%s",
2318 client_id,
2319 json_string_value(ticket_string));
2320 GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token,
2321 &cache_key,
2322 id_ticket_combination,
2323 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
2324
2325 resp = GNUNET_REST_create_response (json_response);
2326 MHD_add_response_header (resp, "Cache-Control", "no-store");
2327 MHD_add_response_header (resp, "Pragma", "no-cache");
2328 MHD_add_response_header (resp, "Content-Type", "application/json");
2329 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2330
2331 //TODO one time ticket/code
2332
2333 //TODO free
2334 GNUNET_IDENTITY_ATTRIBUTE_list_destroy(cl);
2335 GNUNET_free(access_token_number);
2336 GNUNET_free(access_token);
2337 GNUNET_free(user_psw);
2338 GNUNET_free(json_response);
2339 GNUNET_free(ticket);
2340 GNUNET_free(id_token);
2341 json_decref (root);
2342 GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle);
2343}
2344
2345
2346static void
2347consume_ticket (void *cls,
2348 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
2349 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
2350{
2351 struct RequestHandle *handle = cls;
2352
2353 if (NULL == identity)
2354 {
2355 GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle);
2356 return;
2357 }
2358
2359 json_object_set_new (handle->oidc->response,
2360 attr->name,
2361 json_string(attr->data));
2362}
2363
2364static void
2365userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
2366 const char* url, void *cls)
2367{
2368 struct RequestHandle *handle = cls;
2369 char delimiter[] = " ";
2370 char delimiter_db[] = ";";
2371 struct GNUNET_HashCode cache_key;
2372 char *authorization, *authorization_type, *authorization_access_token;
2373 char *client_ticket;
2374 struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket;
2375
2376 GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
2377 strlen (OIDC_AUTHORIZATION_HEADER_KEY),
2378 &cache_key);
2379 if ( GNUNET_NO
2380 == GNUNET_CONTAINER_multihashmap_contains (
2381 handle->rest_handle->header_param_map, &cache_key) )
2382 {
2383 handle->emsg = GNUNET_strdup("invalid_token");
2384 handle->edesc = GNUNET_strdup("No Access Token");
2385 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2386 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2387 return;
2388 }
2389 authorization = GNUNET_CONTAINER_multihashmap_get (
2390 handle->rest_handle->header_param_map, &cache_key);
2391
2392 //TODO authorization pointer will be moved as well
2393 //split header in "Bearer" and access_token
2394 authorization_type = strtok (authorization, delimiter);
2395 if ( 0 != strcmp ("Bearer", authorization_type) )
2396 {
2397 handle->emsg = GNUNET_strdup("invalid_token");
2398 handle->edesc = GNUNET_strdup("No Access Token");
2399 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2400 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2401 return;
2402 }
2403 authorization_access_token = strtok (NULL, delimiter);
2404 if ( NULL == authorization_access_token )
2405 {
2406 handle->emsg = GNUNET_strdup("invalid_token");
2407 handle->edesc = GNUNET_strdup("No Access Token");
2408 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2409 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2410 return;
2411 }
2412
2413 GNUNET_CRYPTO_hash (authorization_access_token,
2414 strlen (authorization_access_token),
2415 &cache_key);
2416 if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_interpret_access_token,
2417 &cache_key) )
2418 {
2419 handle->emsg = GNUNET_strdup("invalid_token");
2420 handle->edesc = GNUNET_strdup("The Access Token expired");
2421 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2422 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2423 return;
2424 }
2425
2426 client_ticket = GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token,
2427 &cache_key);
2428
2429 client_ticket = strtok(client_ticket,delimiter_db);
2430 if (NULL == client_ticket)
2431 {
2432 handle->emsg = GNUNET_strdup("invalid_token");
2433 handle->edesc = GNUNET_strdup("The Access Token expired");
2434 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2435 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2436 return;
2437 }
2438 handle->ego_entry = handle->ego_head;
2439 for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
2440 {
2441 if (0 == strcmp(handle->ego_entry->keystring,client_ticket))
2442 {
2443 break;
2444 }
2445 }
2446 if (NULL == handle->ego_entry)
2447 {
2448 handle->emsg = GNUNET_strdup("invalid_token");
2449 handle->edesc = GNUNET_strdup("The Access Token expired");
2450 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2451 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2452 return;
2453 }
2454 client_ticket = strtok(NULL, delimiter_db);
2455 if (NULL == client_ticket)
2456 {
2457 handle->emsg = GNUNET_strdup("invalid_token");
2458 handle->edesc = GNUNET_strdup("The Access Token expired");
2459 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2460 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2461 return;
2462 }
2463 ticket = GNUNET_new(struct GNUNET_IDENTITY_PROVIDER_Ticket);
2464 if ( GNUNET_OK
2465 != GNUNET_STRINGS_string_to_data (client_ticket,
2466 strlen (client_ticket),
2467 ticket,
2468 sizeof(struct GNUNET_IDENTITY_PROVIDER_Ticket)))
2469 {
2470 handle->emsg = GNUNET_strdup("invalid_token");
2471 handle->edesc = GNUNET_strdup("The Access Token expired");
2472 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2473 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2474 GNUNET_free(ticket);
2475 return;
2476 }
2477
2478 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
2479 handle->oidc->response = json_object();
2480 json_object_set_new( handle->oidc->response, "sub", json_string( handle->ego_entry->keystring));
2481 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (
2482 handle->idp,
2483 GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego),
2484 ticket,
2485 consume_ticket,
2486 handle);
2487 GNUNET_free(ticket);
2488
2489}
2490
2491
2492/**
1016 * Handle rest request 2493 * Handle rest request
1017 * 2494 *
1018 * @param handle the request handle 2495 * @param handle the request handle
@@ -1025,6 +2502,12 @@ init_cont (struct RequestHandle *handle)
1025 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont}, 2502 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
1026 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont}, 2503 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
1027 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont}, 2504 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
2505 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint},
2506 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, //url-encoded
2507 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
2508 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
2509 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2510 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
1028 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont}, 2511 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1029 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont}, 2512 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1030 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER, 2513 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
@@ -1109,7 +2592,16 @@ rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1109 void *proc_cls) 2592 void *proc_cls)
1110{ 2593{
1111 struct RequestHandle *handle = GNUNET_new (struct RequestHandle); 2594 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1112 2595 handle->oidc = GNUNET_new (struct OIDC_Variables);
2596 if ( NULL == OIDC_identity_login_time )
2597 OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2598 if ( NULL == OIDC_identity_grants )
2599 OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2600 if ( NULL == OIDC_ticket_once )
2601 OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2602 if ( NULL == OIDC_interpret_access_token )
2603 OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2604 handle->response_code = 0;
1113 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; 2605 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1114 handle->proc_cls = proc_cls; 2606 handle->proc_cls = proc_cls;
1115 handle->proc = proc; 2607 handle->proc = proc;
@@ -1124,6 +2616,7 @@ rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1124 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, 2616 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1125 &list_ego, 2617 &list_ego,
1126 handle); 2618 handle);
2619 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
1127 handle->timeout_task = 2620 handle->timeout_task =
1128 GNUNET_SCHEDULER_add_delayed (handle->timeout, 2621 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1129 &do_timeout, 2622 &do_timeout,
@@ -1178,8 +2671,44 @@ libgnunet_plugin_rest_identity_provider_done (void *cls)
1178{ 2671{
1179 struct GNUNET_REST_Plugin *api = cls; 2672 struct GNUNET_REST_Plugin *api = cls;
1180 struct Plugin *plugin = api->cls; 2673 struct Plugin *plugin = api->cls;
1181
1182 plugin->cfg = NULL; 2674 plugin->cfg = NULL;
2675
2676 struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2677 void *value = NULL;
2678 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (
2679 OIDC_identity_login_time);
2680 while (GNUNET_YES ==
2681 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2682 {
2683 if (NULL != value)
2684 GNUNET_free(value);
2685 }
2686 GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time);
2687 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants);
2688 while (GNUNET_YES ==
2689 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2690 {
2691 if (NULL != value)
2692 GNUNET_free(value);
2693 }
2694 GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants);
2695 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_ticket_once);
2696 while (GNUNET_YES ==
2697 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2698 {
2699 if (NULL != value)
2700 GNUNET_free(value);
2701 }
2702 GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once);
2703 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_interpret_access_token);
2704 while (GNUNET_YES ==
2705 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2706 {
2707 if (NULL != value)
2708 GNUNET_free(value);
2709 }
2710 GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token);
2711 GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it);
1183 GNUNET_free_non_null (allow_methods); 2712 GNUNET_free_non_null (allow_methods);
1184 GNUNET_free (api); 2713 GNUNET_free (api);
1185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
diff --git a/src/identity-provider/test_idp.conf b/src/identity-provider/test_idp.conf
index 2b76c7bf2..b11b43ae2 100644
--- a/src/identity-provider/test_idp.conf
+++ b/src/identity-provider/test_idp.conf
@@ -8,7 +8,7 @@ AUTOSTART = YES
8 8
9[rest] 9[rest]
10AUTOSTART = YES 10AUTOSTART = YES
11#PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/restlog 11PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/restlog
12 12
13[transport] 13[transport]
14PLUGINS = 14PLUGINS =
@@ -26,3 +26,8 @@ DEFAULT_LOOKUP_TIMEOUT = 15 s
26RECORD_PUT_INTERVAL = 1 h 26RECORD_PUT_INTERVAL = 1 h
27ZONE_PUBLISH_TIME_WINDOW = 1 h 27ZONE_PUBLISH_TIME_WINDOW = 1 h
28DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0 28DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
29
30[identity-rest-plugin]
31address = http://localhost:8000/#/login
32psw = mysupersecretpassword
33expiration_time = 3600 \ No newline at end of file
diff --git a/src/include/gnunet_identity_attribute_lib.h b/src/include/gnunet_identity_attribute_lib.h
index 316b0bf95..8879ba925 100644
--- a/src/include/gnunet_identity_attribute_lib.h
+++ b/src/include/gnunet_identity_attribute_lib.h
@@ -148,6 +148,12 @@ GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (const struct GNUNET_IDENTITY_
148void 148void
149GNUNET_IDENTITY_ATTRIBUTE_list_destroy (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs); 149GNUNET_IDENTITY_ATTRIBUTE_list_destroy (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs);
150 150
151void
152GNUNET_IDENTITY_ATTRIBUTE_list_add (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs,
153 const char* attr_name,
154 uint32_t type,
155 const void* data,
156 size_t data_size);
151 157
152/** 158/**
153 * Serialize an attribute list 159 * Serialize an attribute list
diff --git a/src/include/gnunet_rest_lib.h b/src/include/gnunet_rest_lib.h
index 9821e23d5..41b85401d 100644
--- a/src/include/gnunet_rest_lib.h
+++ b/src/include/gnunet_rest_lib.h
@@ -38,11 +38,34 @@
38 38
39struct GNUNET_REST_RequestHandle 39struct GNUNET_REST_RequestHandle
40{ 40{
41 /**
42 * Map of url parameters
43 */
41 struct GNUNET_CONTAINER_MultiHashMap *url_param_map; 44 struct GNUNET_CONTAINER_MultiHashMap *url_param_map;
45
46 /**
47 * Map of headers
48 */
42 struct GNUNET_CONTAINER_MultiHashMap *header_param_map; 49 struct GNUNET_CONTAINER_MultiHashMap *header_param_map;
50
51 /**
52 * The HTTP method as MHD value (see microhttpd.h)
53 */
43 const char *method; 54 const char *method;
55
56 /**
57 * The url as string
58 */
44 const char *url; 59 const char *url;
60
61 /**
62 * The POST data
63 */
45 const char *data; 64 const char *data;
65
66 /**
67 * The POST data size
68 */
46 size_t data_size; 69 size_t data_size;
47}; 70};
48 71
diff --git a/src/rest/gnunet-rest-server.c b/src/rest/gnunet-rest-server.c
index c79c807a6..fdcd4f9c5 100644
--- a/src/rest/gnunet-rest-server.c
+++ b/src/rest/gnunet-rest-server.c
@@ -303,6 +303,7 @@ post_data_iter (void *cls,
303 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 303 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
304 "Could not load add url param `%s'=%s\n", 304 "Could not load add url param `%s'=%s\n",
305 key, data); 305 key, data);
306 GNUNET_free(val);
306 } 307 }
307 return MHD_YES; 308 return MHD_YES;
308 309
@@ -398,6 +399,10 @@ create_response (void *cls,
398 MHD_GET_ARGUMENT_KIND, 399 MHD_GET_ARGUMENT_KIND,
399 &url_iterator, 400 &url_iterator,
400 rest_conndata_handle); 401 rest_conndata_handle);
402 MHD_get_connection_values (con,
403 MHD_HEADER_KIND,
404 &header_iterator,
405 rest_conndata_handle);
401 con_handle->pp = MHD_create_post_processor(con, 406 con_handle->pp = MHD_create_post_processor(con,
402 4000, 407 4000,
403 post_data_iter, 408 post_data_iter,
@@ -406,14 +411,8 @@ create_response (void *cls,
406 { 411 {
407 MHD_post_process(con_handle->pp, upload_data, *upload_data_size); 412 MHD_post_process(con_handle->pp, upload_data, *upload_data_size);
408 } 413 }
409 else 414 MHD_destroy_post_processor(con_handle->pp);
410 { 415
411 MHD_destroy_post_processor(con_handle->pp);
412 }
413 MHD_get_connection_values (con,
414 MHD_HEADER_KIND,
415 &header_iterator,
416 rest_conndata_handle);
417 con_handle->state = GN_REST_STATE_PROCESSING; 416 con_handle->state = GN_REST_STATE_PROCESSING;
418 con_handle->plugin->process_request (rest_conndata_handle, 417 con_handle->plugin->process_request (rest_conndata_handle,
419 &plugin_callback, 418 &plugin_callback,
@@ -644,7 +643,7 @@ do_accept (void *cls)
644 _("Failed to pass client to MHD\n")); 643 _("Failed to pass client to MHD\n"));
645 return; 644 return;
646 } 645 }
647 646 GNUNET_free(s);
648 schedule_httpd (); 647 schedule_httpd ();
649} 648}
650 649
diff --git a/src/rest/rest.conf b/src/rest/rest.conf
index b86e6c1a0..f74d772e8 100644
--- a/src/rest/rest.conf
+++ b/src/rest/rest.conf
@@ -3,4 +3,4 @@ UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-rest.sock
3BINARY=gnunet-rest-server 3BINARY=gnunet-rest-server
4REST_PORT=7776 4REST_PORT=7776
5REST_ALLOW_HEADERS=Authorization,Accept,Content-Type 5REST_ALLOW_HEADERS=Authorization,Accept,Content-Type
6REST_ALLOW_ORIGIN=* 6REST_ALLOW_ORIGIN=http://localhost:8000