diff options
author | Schanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de> | 2018-02-25 16:23:42 +0100 |
---|---|---|
committer | Schanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de> | 2018-02-25 16:23:42 +0100 |
commit | 82e4a63b4ef0f5de0cfaedd6f8789c4a1ccfed91 (patch) | |
tree | 129f4d571ee4bff86fd169c9c46c94fb73979e7c /src | |
parent | d4ad64d79b26163f8bcd78d32fe463082b9ed8de (diff) | |
parent | bbe8e9a4e5bc9b60a5cc5f54385e6252a0487aea (diff) | |
download | gnunet-82e4a63b4ef0f5de0cfaedd6f8789c4a1ccfed91.tar.gz gnunet-82e4a63b4ef0f5de0cfaedd6f8789c4a1ccfed91.zip |
-fix
Diffstat (limited to 'src')
-rw-r--r-- | src/identity-attribute/identity_attribute.c | 28 | ||||
-rw-r--r-- | src/identity-provider/jwt.c | 33 | ||||
-rw-r--r-- | src/identity-provider/jwt.h | 9 | ||||
-rw-r--r-- | src/identity-provider/plugin_rest_identity_provider.c | 1551 | ||||
-rw-r--r-- | src/identity-provider/test_idp.conf | 7 | ||||
-rw-r--r-- | src/include/gnunet_identity_attribute_lib.h | 6 | ||||
-rw-r--r-- | src/include/gnunet_rest_lib.h | 23 | ||||
-rw-r--r-- | src/rest/gnunet-rest-server.c | 17 | ||||
-rw-r--r-- | src/rest/rest.conf | 2 |
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 | */ | ||
253 | void | ||
254 | GNUNET_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 | |||
243 | size_t | 271 | size_t |
244 | GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) | 272 | GNUNET_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 | |||
42 | static char* | 45 | static char* |
43 | create_jwt_header(void) | 46 | create_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 | */ |
65 | char* | 68 | char* |
66 | jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, | 69 | jwt_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 | |||
4 | char* | ||
5 | jwt_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 | */ | ||
188 | char* 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 | */ | ||
203 | struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time; | ||
204 | |||
205 | /** | ||
206 | * OIDC authorized identities and times hashmap | ||
207 | */ | ||
208 | struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants; | ||
209 | |||
210 | /** | ||
211 | * OIDC ticket/code use only once | ||
212 | */ | ||
213 | struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once; | ||
214 | |||
215 | /** | ||
216 | * OIDC access_token to ticket and ego | ||
217 | */ | ||
218 | struct 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 | */ | ||
240 | struct 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 | |||
256 | static void | 430 | static void |
257 | cleanup_handle (struct RequestHandle *handle) | 431 | cleanup_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 | */ | ||
553 | static void | ||
554 | do_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 | */ | ||
576 | static void | ||
577 | do_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 | */ | ||
661 | static void | ||
662 | return_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 | |||
676 | static char* | ||
677 | base_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 | ||
382 | static void | 690 | static void |
383 | collect_finished_cb (void *cls) | 691 | collect_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 | */ | ||
1333 | static void | ||
1334 | cookie_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 | */ | ||
1383 | static void | ||
1384 | login_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 | */ | ||
1429 | static void | ||
1430 | oidc_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 | |||
1438 | static void | ||
1439 | oidc_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 | |||
1478 | static void | ||
1479 | oidc_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 | */ | ||
1503 | static void | ||
1504 | oidc_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 | */ | ||
1549 | static void | ||
1550 | login_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 | */ | ||
1618 | static void | ||
1619 | namestore_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 | ¤t_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, ¤t_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 | */ | ||
1672 | static 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 | */ | ||
1834 | static void | ||
1835 | authorize_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 | */ | ||
1911 | static void | ||
1912 | login_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 | |||
1958 | static void | ||
1959 | token_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 | |||
2346 | static void | ||
2347 | consume_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 | |||
2364 | static void | ||
2365 | userinfo_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] |
10 | AUTOSTART = YES | 10 | AUTOSTART = YES |
11 | #PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/restlog | 11 | PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/restlog |
12 | 12 | ||
13 | [transport] | 13 | [transport] |
14 | PLUGINS = | 14 | PLUGINS = |
@@ -26,3 +26,8 @@ DEFAULT_LOOKUP_TIMEOUT = 15 s | |||
26 | RECORD_PUT_INTERVAL = 1 h | 26 | RECORD_PUT_INTERVAL = 1 h |
27 | ZONE_PUBLISH_TIME_WINDOW = 1 h | 27 | ZONE_PUBLISH_TIME_WINDOW = 1 h |
28 | DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0 | 28 | DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0 |
29 | |||
30 | [identity-rest-plugin] | ||
31 | address = http://localhost:8000/#/login | ||
32 | psw = mysupersecretpassword | ||
33 | expiration_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_ | |||
148 | void | 148 | void |
149 | GNUNET_IDENTITY_ATTRIBUTE_list_destroy (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs); | 149 | GNUNET_IDENTITY_ATTRIBUTE_list_destroy (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs); |
150 | 150 | ||
151 | void | ||
152 | GNUNET_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 | ||
39 | struct GNUNET_REST_RequestHandle | 39 | struct 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 | |||
3 | BINARY=gnunet-rest-server | 3 | BINARY=gnunet-rest-server |
4 | REST_PORT=7776 | 4 | REST_PORT=7776 |
5 | REST_ALLOW_HEADERS=Authorization,Accept,Content-Type | 5 | REST_ALLOW_HEADERS=Authorization,Accept,Content-Type |
6 | REST_ALLOW_ORIGIN=* | 6 | REST_ALLOW_ORIGIN=http://localhost:8000 |