aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/documentation/chapters/developer.texi19
-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
10 files changed, 1654 insertions, 41 deletions
diff --git a/doc/documentation/chapters/developer.texi b/doc/documentation/chapters/developer.texi
index 0b8c7e488..41db89df8 100644
--- a/doc/documentation/chapters/developer.texi
+++ b/doc/documentation/chapters/developer.texi
@@ -815,8 +815,8 @@ Each variable type should be chosen with care.
815statements (free, close, etc.) can be acceptable. 815statements (free, close, etc.) can be acceptable.
816 816
817@item Conditions should be written with constants on the left (to avoid 817@item Conditions should be written with constants on the left (to avoid
818accidental assignment) and with the 'true' target being either the 818accidental assignment) and with the @code{true} target being either the
819'error' case or the significantly simpler continuation. For example: 819@code{error} case or the significantly simpler continuation. For example:
820 820
821@example 821@example
822if (0 != stat ("filename," &sbuf)) @{ 822if (0 != stat ("filename," &sbuf)) @{
@@ -839,8 +839,8 @@ if (stat ("filename," &sbuf) == 0) @{
839@end example 839@end example
840 840
841@noindent 841@noindent
842If possible, the error clause should be terminated with a 'return' (or 842If possible, the error clause should be terminated with a @code{return} (or
843'goto' to some cleanup routine) and in this case, the 'else' clause 843@code{goto} to some cleanup routine) and in this case, the @code{else} clause
844should be omitted: 844should be omitted:
845 845
846@example 846@example
@@ -2159,7 +2159,7 @@ any attempts to make the same call later will be allowed or disallowed
2159right away. Because of that runtime log level evaluation should not 2159right away. Because of that runtime log level evaluation should not
2160significantly affect the process performance. 2160significantly affect the process performance.
2161Log definition parsing is only done once, at the first call to 2161Log definition parsing is only done once, at the first call to
2162GNUNET_log_setup () made by the process (which is usually done soon after 2162@code{GNUNET_log_setup ()} made by the process (which is usually done soon after
2163it starts). 2163it starts).
2164 2164
2165At the moment of writing there is no way to specify logging definitions 2165At the moment of writing there is no way to specify logging definitions
@@ -2323,18 +2323,21 @@ topology\n")); #endif unblacklisted_connections = create_small_world_ring
2323Pretty hard to follow, huh? 2323Pretty hard to follow, huh?
2324 2324
2325From now on, it is not necessary to include the #if / #endif statements to 2325From now on, it is not necessary to include the #if / #endif statements to
2326achieve the same behavior. The GNUNET_log and GNUNET_log_from macros take 2326achieve the same behavior. The @code{GNUNET_log} and @code{GNUNET_log_from}
2327macros take
2327care of it for you, depending on the configure option: 2328care of it for you, depending on the configure option:
2328 2329
2329@itemize @bullet 2330@itemize @bullet
2330@item If @code{--enable-logging} is set to @code{no}, the binary will 2331@item If @code{--enable-logging} is set to @code{no}, the binary will
2331contain no log messages at all. 2332contain no log messages at all.
2332@item If @code{--enable-logging} is set to @code{yes}, the binary will 2333@item If @code{--enable-logging} is set to @code{yes}, the binary will
2333contain no DEBUG messages, and therefore running with -L DEBUG will have 2334contain no DEBUG messages, and therefore running with @command{-L DEBUG}
2335will have
2334no effect. Other messages (ERROR, WARNING, INFO, etc) will be included. 2336no effect. Other messages (ERROR, WARNING, INFO, etc) will be included.
2335@item If @code{--enable-logging} is set to @code{verbose}, or 2337@item If @code{--enable-logging} is set to @code{verbose}, or
2336@code{veryverbose} the binary will contain DEBUG messages (still, it will 2338@code{veryverbose} the binary will contain DEBUG messages (still, it will
2337be neccessary to run with -L DEBUG or set the DEBUG config option to show 2339be neccessary to run with @command{-L DEBUG} or set the DEBUG config option
2340to show
2338them). 2341them).
2339@end itemize 2342@end itemize
2340 2343
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