diff options
author | Martin Schanzenbach <mschanzenbach@posteo.de> | 2020-08-06 08:45:40 +0200 |
---|---|---|
committer | Martin Schanzenbach <mschanzenbach@posteo.de> | 2020-08-06 08:45:40 +0200 |
commit | 1d4f5263ae72c12a42ec166ec8b1769620baaeda (patch) | |
tree | 4c5c6051b4ae968c4b3a5c82f1d51da452e9f1d3 /src | |
parent | 6e764f4abd8a3f14f03a5a167af7d5cb703fd1d5 (diff) | |
download | gnunet-1d4f5263ae72c12a42ec166ec8b1769620baaeda.tar.gz gnunet-1d4f5263ae72c12a42ec166ec8b1769620baaeda.zip |
reclaim: Refactoring and more standards compliance with respect to scopes
Diffstat (limited to 'src')
-rw-r--r-- | src/reclaim/oidc_helper.c | 313 | ||||
-rw-r--r-- | src/reclaim/oidc_helper.h | 30 | ||||
-rw-r--r-- | src/reclaim/plugin_rest_openid_connect.c | 198 |
3 files changed, 341 insertions, 200 deletions
diff --git a/src/reclaim/oidc_helper.c b/src/reclaim/oidc_helper.c index 4da387564..cb99a749d 100644 --- a/src/reclaim/oidc_helper.c +++ b/src/reclaim/oidc_helper.c | |||
@@ -69,6 +69,51 @@ struct OIDC_Parameters | |||
69 | 69 | ||
70 | GNUNET_NETWORK_STRUCT_END | 70 | GNUNET_NETWORK_STRUCT_END |
71 | 71 | ||
72 | /** | ||
73 | * Standard claims represented by the "profile" scope in OIDC | ||
74 | */ | ||
75 | static char OIDC_profile_claims[14][32] = { | ||
76 | "name", "family_name", "given_name", "middle_name", "nickname", | ||
77 | "preferred_username", "profile", "picture", "website", "gender", "birthdate", | ||
78 | "zoneinfo", "locale", "updated_at" | ||
79 | }; | ||
80 | |||
81 | /** | ||
82 | * Standard claims represented by the "email" scope in OIDC | ||
83 | */ | ||
84 | static char OIDC_email_claims[2][16] = { | ||
85 | "email", "email_verified" | ||
86 | }; | ||
87 | |||
88 | /** | ||
89 | * Standard claims represented by the "phone" scope in OIDC | ||
90 | */ | ||
91 | static char OIDC_phone_claims[2][32] = { | ||
92 | "phone_number", "phone_number_verified" | ||
93 | }; | ||
94 | |||
95 | /** | ||
96 | * Standard claims represented by the "address" scope in OIDC | ||
97 | */ | ||
98 | static char OIDC_address_claims[5][32] = { | ||
99 | "street_address", "locality", "region", "postal_code", "country" | ||
100 | }; | ||
101 | |||
102 | static enum GNUNET_GenericReturnValue | ||
103 | is_claim_in_address_scope (const char *claim) | ||
104 | { | ||
105 | int i; | ||
106 | for (i = 0; i < 5; i++) | ||
107 | { | ||
108 | if (0 == strcmp (claim, OIDC_address_claims[i])) | ||
109 | { | ||
110 | return GNUNET_YES; | ||
111 | } | ||
112 | } | ||
113 | return GNUNET_NO; | ||
114 | } | ||
115 | |||
116 | |||
72 | static char * | 117 | static char * |
73 | create_jwt_header (void) | 118 | create_jwt_header (void) |
74 | { | 119 | { |
@@ -109,49 +154,24 @@ fix_base64 (char *str) | |||
109 | replace_char (str, '/', '_'); | 154 | replace_char (str, '/', '_'); |
110 | } | 155 | } |
111 | 156 | ||
112 | 157 | static json_t* | |
113 | /** | 158 | generate_userinfo_json(const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, |
114 | * Create a JWT from attributes | 159 | struct GNUNET_RECLAIM_AttributeList *attrs, |
115 | * | 160 | struct GNUNET_RECLAIM_AttestationList *attests) |
116 | * @param aud_key the public of the audience | ||
117 | * @param sub_key the public key of the subject | ||
118 | * @param attrs the attribute list | ||
119 | * @param expiration_time the validity of the token | ||
120 | * @param secret_key the key used to sign the JWT | ||
121 | * @return a new base64-encoded JWT string. | ||
122 | */ | ||
123 | char * | ||
124 | OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | ||
125 | const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, | ||
126 | struct GNUNET_RECLAIM_AttributeList *attrs, | ||
127 | struct GNUNET_RECLAIM_AttestationList *attests, | ||
128 | const struct GNUNET_TIME_Relative *expiration_time, | ||
129 | const char *nonce, | ||
130 | const char *secret_key) | ||
131 | { | 161 | { |
132 | struct GNUNET_RECLAIM_AttributeListEntry *le; | 162 | struct GNUNET_RECLAIM_AttributeListEntry *le; |
133 | struct GNUNET_RECLAIM_AttestationListEntry *ale; | 163 | struct GNUNET_RECLAIM_AttestationListEntry *ale; |
134 | struct GNUNET_HashCode signature; | ||
135 | struct GNUNET_TIME_Absolute exp_time; | ||
136 | struct GNUNET_TIME_Absolute time_now; | ||
137 | char *audience; | ||
138 | char *subject; | 164 | char *subject; |
139 | char *header; | ||
140 | char *body_str; | ||
141 | char *aggr_names_str; | 165 | char *aggr_names_str; |
142 | char *aggr_sources_str; | 166 | char *aggr_sources_str; |
143 | char *source_name; | 167 | char *source_name; |
144 | char *result; | ||
145 | char *header_base64; | ||
146 | char *body_base64; | ||
147 | char *signature_target; | ||
148 | char *signature_base64; | ||
149 | char *attr_val_str; | 168 | char *attr_val_str; |
150 | char *attest_val_str; | 169 | char *attest_val_str; |
151 | json_t *body; | 170 | json_t *body; |
152 | json_t *aggr_names; | 171 | json_t *aggr_names; |
153 | json_t *aggr_sources; | 172 | json_t *aggr_sources; |
154 | json_t *aggr_sources_jwt; | 173 | json_t *aggr_sources_jwt; |
174 | json_t *addr_claim; | ||
155 | int num_attestations = 0; | 175 | int num_attestations = 0; |
156 | for (le = attrs->list_head; NULL != le; le = le->next) | 176 | for (le = attrs->list_head; NULL != le; le = le->next) |
157 | { | 177 | { |
@@ -159,22 +179,10 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | |||
159 | num_attestations++; | 179 | num_attestations++; |
160 | } | 180 | } |
161 | 181 | ||
162 | // iat REQUIRED time now | ||
163 | time_now = GNUNET_TIME_absolute_get (); | ||
164 | // exp REQUIRED time expired from config | ||
165 | exp_time = GNUNET_TIME_absolute_add (time_now, *expiration_time); | ||
166 | // auth_time only if max_age | ||
167 | // nonce only if nonce | ||
168 | // OPTIONAL acr,amr,azp | ||
169 | subject = | 182 | subject = |
170 | GNUNET_STRINGS_data_to_string_alloc (sub_key, | 183 | GNUNET_STRINGS_data_to_string_alloc (sub_key, |
171 | sizeof(struct | 184 | sizeof(struct |
172 | GNUNET_CRYPTO_EcdsaPublicKey)); | 185 | GNUNET_CRYPTO_EcdsaPublicKey)); |
173 | audience = | ||
174 | GNUNET_STRINGS_data_to_string_alloc (aud_key, | ||
175 | sizeof(struct | ||
176 | GNUNET_CRYPTO_EcdsaPublicKey)); | ||
177 | header = create_jwt_header (); | ||
178 | body = json_object (); | 186 | body = json_object (); |
179 | aggr_names = json_object (); | 187 | aggr_names = json_object (); |
180 | aggr_sources = json_object (); | 188 | aggr_sources = json_object (); |
@@ -185,23 +193,6 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | |||
185 | json_object_set_new (body, "iss", json_string (SERVER_ADDRESS)); | 193 | json_object_set_new (body, "iss", json_string (SERVER_ADDRESS)); |
186 | // sub REQUIRED public key identity, not exceed 255 ASCII length | 194 | // sub REQUIRED public key identity, not exceed 255 ASCII length |
187 | json_object_set_new (body, "sub", json_string (subject)); | 195 | json_object_set_new (body, "sub", json_string (subject)); |
188 | // aud REQUIRED public key client_id must be there | ||
189 | json_object_set_new (body, "aud", json_string (audience)); | ||
190 | // iat | ||
191 | json_object_set_new (body, | ||
192 | "iat", | ||
193 | json_integer (time_now.abs_value_us / (1000 * 1000))); | ||
194 | // exp | ||
195 | json_object_set_new (body, | ||
196 | "exp", | ||
197 | json_integer (exp_time.abs_value_us / (1000 * 1000))); | ||
198 | // nbf | ||
199 | json_object_set_new (body, | ||
200 | "nbf", | ||
201 | json_integer (time_now.abs_value_us / (1000 * 1000))); | ||
202 | // nonce | ||
203 | if (NULL != nonce) | ||
204 | json_object_set_new (body, "nonce", json_string (nonce)); | ||
205 | attest_val_str = NULL; | 196 | attest_val_str = NULL; |
206 | aggr_names_str = NULL; | 197 | aggr_names_str = NULL; |
207 | aggr_sources_str = NULL; | 198 | aggr_sources_str = NULL; |
@@ -236,8 +227,28 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | |||
236 | GNUNET_RECLAIM_attribute_value_to_string (le->attribute->type, | 227 | GNUNET_RECLAIM_attribute_value_to_string (le->attribute->type, |
237 | le->attribute->data, | 228 | le->attribute->data, |
238 | le->attribute->data_size); | 229 | le->attribute->data_size); |
239 | json_object_set_new (body, le->attribute->name, | 230 | /** |
240 | json_string (attr_val_str)); | 231 | * There is this wierd quirk that the individual address claim(s) must be |
232 | * inside a JSON object of the "address" claim. | ||
233 | * FIXME: Possibly include formatted claim here | ||
234 | */ | ||
235 | if (GNUNET_YES == is_claim_in_address_scope (le->attribute->name)) | ||
236 | { | ||
237 | if (NULL == addr_claim) | ||
238 | { | ||
239 | addr_claim = json_object (); | ||
240 | json_object_set_new (body, "address", | ||
241 | addr_claim); | ||
242 | } | ||
243 | json_object_set_new (addr_claim, le->attribute->name, | ||
244 | json_string (attr_val_str)); | ||
245 | |||
246 | } | ||
247 | else | ||
248 | { | ||
249 | json_object_set_new (body, le->attribute->name, | ||
250 | json_string (attr_val_str)); | ||
251 | } | ||
241 | GNUNET_free (attr_val_str); | 252 | GNUNET_free (attr_val_str); |
242 | } | 253 | } |
243 | else | 254 | else |
@@ -277,6 +288,102 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | |||
277 | 288 | ||
278 | json_decref (aggr_names); | 289 | json_decref (aggr_names); |
279 | json_decref (aggr_sources); | 290 | json_decref (aggr_sources); |
291 | return body; | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * Generate userinfo JSON as string | ||
296 | * | ||
297 | * @param sub_key the subject (user) | ||
298 | * @param attrs user attribute list | ||
299 | * @param attests user attribute attestation list (may be empty) | ||
300 | * @return Userinfo JSON | ||
301 | */ | ||
302 | char * | ||
303 | OIDC_generate_userinfo (const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, | ||
304 | struct GNUNET_RECLAIM_AttributeList *attrs, | ||
305 | struct GNUNET_RECLAIM_AttestationList *attests) | ||
306 | { | ||
307 | char *body_str; | ||
308 | json_t* body = generate_userinfo_json (sub_key, | ||
309 | attrs, | ||
310 | attests); | ||
311 | body_str = json_dumps (body, JSON_INDENT (0) | JSON_COMPACT); | ||
312 | json_decref (body); | ||
313 | return body_str; | ||
314 | } | ||
315 | |||
316 | |||
317 | /** | ||
318 | * Create a JWT from attributes | ||
319 | * | ||
320 | * @param aud_key the public of the audience | ||
321 | * @param sub_key the public key of the subject | ||
322 | * @param attrs the attribute list | ||
323 | * @param expiration_time the validity of the token | ||
324 | * @param secret_key the key used to sign the JWT | ||
325 | * @return a new base64-encoded JWT string. | ||
326 | */ | ||
327 | char * | ||
328 | OIDC_generate_id_token (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | ||
329 | const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, | ||
330 | struct GNUNET_RECLAIM_AttributeList *attrs, | ||
331 | struct GNUNET_RECLAIM_AttestationList *attests, | ||
332 | const struct GNUNET_TIME_Relative *expiration_time, | ||
333 | const char *nonce, | ||
334 | const char *secret_key) | ||
335 | { | ||
336 | struct GNUNET_HashCode signature; | ||
337 | struct GNUNET_TIME_Absolute exp_time; | ||
338 | struct GNUNET_TIME_Absolute time_now; | ||
339 | char *audience; | ||
340 | char *subject; | ||
341 | char *header; | ||
342 | char *body_str; | ||
343 | char *result; | ||
344 | char *header_base64; | ||
345 | char *body_base64; | ||
346 | char *signature_target; | ||
347 | char *signature_base64; | ||
348 | json_t *body; | ||
349 | |||
350 | body = generate_userinfo_json (sub_key, | ||
351 | attrs, | ||
352 | attests); | ||
353 | // iat REQUIRED time now | ||
354 | time_now = GNUNET_TIME_absolute_get (); | ||
355 | // exp REQUIRED time expired from config | ||
356 | exp_time = GNUNET_TIME_absolute_add (time_now, *expiration_time); | ||
357 | // auth_time only if max_age | ||
358 | // nonce only if nonce | ||
359 | // OPTIONAL acr,amr,azp | ||
360 | subject = | ||
361 | GNUNET_STRINGS_data_to_string_alloc (sub_key, | ||
362 | sizeof(struct | ||
363 | GNUNET_CRYPTO_EcdsaPublicKey)); | ||
364 | audience = | ||
365 | GNUNET_STRINGS_data_to_string_alloc (aud_key, | ||
366 | sizeof(struct | ||
367 | GNUNET_CRYPTO_EcdsaPublicKey)); | ||
368 | header = create_jwt_header (); | ||
369 | |||
370 | // aud REQUIRED public key client_id must be there | ||
371 | json_object_set_new (body, "aud", json_string (audience)); | ||
372 | // iat | ||
373 | json_object_set_new (body, | ||
374 | "iat", | ||
375 | json_integer (time_now.abs_value_us / (1000 * 1000))); | ||
376 | // exp | ||
377 | json_object_set_new (body, | ||
378 | "exp", | ||
379 | json_integer (exp_time.abs_value_us / (1000 * 1000))); | ||
380 | // nbf | ||
381 | json_object_set_new (body, | ||
382 | "nbf", | ||
383 | json_integer (time_now.abs_value_us / (1000 * 1000))); | ||
384 | // nonce | ||
385 | if (NULL != nonce) | ||
386 | json_object_set_new (body, "nonce", json_string (nonce)); | ||
280 | 387 | ||
281 | body_str = json_dumps (body, JSON_INDENT (0) | JSON_COMPACT); | 388 | body_str = json_dumps (body, JSON_INDENT (0) | JSON_COMPACT); |
282 | json_decref (body); | 389 | json_decref (body); |
@@ -315,10 +422,6 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | |||
315 | GNUNET_free (signature_target); | 422 | GNUNET_free (signature_target); |
316 | GNUNET_free (header); | 423 | GNUNET_free (header); |
317 | GNUNET_free (body_str); | 424 | GNUNET_free (body_str); |
318 | if (NULL != aggr_sources_str) | ||
319 | GNUNET_free (aggr_sources_str); | ||
320 | if (NULL != aggr_names_str) | ||
321 | GNUNET_free (aggr_names_str); | ||
322 | GNUNET_free (signature_base64); | 425 | GNUNET_free (signature_base64); |
323 | GNUNET_free (body_base64); | 426 | GNUNET_free (body_base64); |
324 | GNUNET_free (header_base64); | 427 | GNUNET_free (header_base64); |
@@ -552,7 +655,7 @@ OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, | |||
552 | code_challenge = ((char *) ¶ms[1]); | 655 | code_challenge = ((char *) ¶ms[1]); |
553 | GNUNET_free (code_verifier_hash); | 656 | GNUNET_free (code_verifier_hash); |
554 | if (0 != | 657 | if (0 != |
555 | strncmp (expected_code_challenge, code_challenge, code_challenge_len)) | 658 | strncmp (expected_code_challenge, code_challenge, code_challenge_len)) |
556 | { | 659 | { |
557 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 660 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
558 | "Invalid code verifier! Expected: %s, Got: %.*s\n", | 661 | "Invalid code verifier! Expected: %s, Got: %.*s\n", |
@@ -575,8 +678,8 @@ OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, | |||
575 | 678 | ||
576 | // Ticket | 679 | // Ticket |
577 | memcpy (ticket, ¶ms->ticket, sizeof(params->ticket)); | 680 | memcpy (ticket, ¶ms->ticket, sizeof(params->ticket)); |
578 | // Signature | 681 | // Signature |
579 | //GNUNET_CRYPTO_ecdsa_key_get_public (ecdsa_priv, &ecdsa_pub); | 682 | // GNUNET_CRYPTO_ecdsa_key_get_public (ecdsa_priv, &ecdsa_pub); |
580 | if (0 != GNUNET_memcmp (audience, &ticket->audience)) | 683 | if (0 != GNUNET_memcmp (audience, &ticket->audience)) |
581 | { | 684 | { |
582 | GNUNET_free (code_payload); | 685 | GNUNET_free (code_payload); |
@@ -675,3 +778,77 @@ OIDC_access_token_parse (const char*token, | |||
675 | return GNUNET_SYSERR; | 778 | return GNUNET_SYSERR; |
676 | return GNUNET_OK; | 779 | return GNUNET_OK; |
677 | } | 780 | } |
781 | |||
782 | |||
783 | /** | ||
784 | * Checks if a claim is implicitly requested through standard | ||
785 | * scope(s) | ||
786 | * | ||
787 | * @param scopes the scopes which have been requested | ||
788 | * @param attr the attribute name to check | ||
789 | * @return GNUNET_YES if attribute is implcitly requested | ||
790 | */ | ||
791 | enum GNUNET_GenericReturnValue | ||
792 | OIDC_check_scopes_for_claim_request (const char*scopes, | ||
793 | const char*attr) | ||
794 | { | ||
795 | char *scope_variables; | ||
796 | char *scope_variable; | ||
797 | char delimiter[] = " "; | ||
798 | int i; | ||
799 | |||
800 | scope_variables = GNUNET_strdup (scopes); | ||
801 | scope_variable = strtok (scope_variables, delimiter); | ||
802 | while (NULL != scope_variable) | ||
803 | { | ||
804 | if (0 == strcmp ("profile", scope_variable)) | ||
805 | { | ||
806 | for (i = 0; i < 14; i++) | ||
807 | { | ||
808 | if (0 == strcmp (attr, OIDC_profile_claims[i])) | ||
809 | { | ||
810 | GNUNET_free (scope_variables); | ||
811 | return GNUNET_YES; | ||
812 | } | ||
813 | } | ||
814 | } | ||
815 | else if (0 == strcmp ("address", scope_variable)) | ||
816 | { | ||
817 | for (i = 0; i < 5; i++) | ||
818 | { | ||
819 | if (0 == strcmp (attr, OIDC_address_claims[i])) | ||
820 | { | ||
821 | GNUNET_free (scope_variables); | ||
822 | return GNUNET_YES; | ||
823 | } | ||
824 | } | ||
825 | } | ||
826 | else if (0 == strcmp ("email", scope_variable)) | ||
827 | { | ||
828 | for (i = 0; i < 2; i++) | ||
829 | { | ||
830 | if (0 == strcmp (attr, OIDC_email_claims[i])) | ||
831 | { | ||
832 | GNUNET_free (scope_variables); | ||
833 | return GNUNET_YES; | ||
834 | } | ||
835 | } | ||
836 | } | ||
837 | else if (0 == strcmp ("phone", scope_variable)) | ||
838 | { | ||
839 | for (i = 0; i < 2; i++) | ||
840 | { | ||
841 | if (0 == strcmp (attr, OIDC_phone_claims[i])) | ||
842 | { | ||
843 | GNUNET_free (scope_variables); | ||
844 | return GNUNET_YES; | ||
845 | } | ||
846 | } | ||
847 | |||
848 | } | ||
849 | scope_variable = strtok (NULL, delimiter); | ||
850 | } | ||
851 | GNUNET_free (scope_variables); | ||
852 | return GNUNET_NO; | ||
853 | |||
854 | } | ||
diff --git a/src/reclaim/oidc_helper.h b/src/reclaim/oidc_helper.h index e71a7ad1c..e713dab62 100644 --- a/src/reclaim/oidc_helper.h +++ b/src/reclaim/oidc_helper.h | |||
@@ -49,7 +49,7 @@ | |||
49 | * @return a new base64-encoded JWT string. | 49 | * @return a new base64-encoded JWT string. |
50 | */ | 50 | */ |
51 | char* | 51 | char* |
52 | OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, | 52 | OIDC_generate_id_token (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, |
53 | const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, | 53 | const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, |
54 | struct GNUNET_RECLAIM_AttributeList *attrs, | 54 | struct GNUNET_RECLAIM_AttributeList *attrs, |
55 | struct GNUNET_RECLAIM_AttestationList *attests, | 55 | struct GNUNET_RECLAIM_AttestationList *attests, |
@@ -125,4 +125,32 @@ OIDC_access_token_new (const struct GNUNET_RECLAIM_Ticket *ticket); | |||
125 | int | 125 | int |
126 | OIDC_access_token_parse (const char* token, | 126 | OIDC_access_token_parse (const char* token, |
127 | struct GNUNET_RECLAIM_Ticket **ticket); | 127 | struct GNUNET_RECLAIM_Ticket **ticket); |
128 | |||
129 | |||
130 | /** | ||
131 | * Checks if a claim is implicitly requested through standard | ||
132 | * scope(s) | ||
133 | * | ||
134 | * @param scopes the scopes which have been requested | ||
135 | * @param attr the attribute name to check | ||
136 | * @return GNUNET_YES if attribute is implcitly requested | ||
137 | */ | ||
138 | enum GNUNET_GenericReturnValue | ||
139 | OIDC_check_scopes_for_claim_request (const char*scopes, | ||
140 | const char*attr); | ||
141 | |||
142 | |||
143 | /** | ||
144 | * Generate userinfo JSON as string | ||
145 | * | ||
146 | * @param sub_key the subject (user) | ||
147 | * @param attrs user attribute list | ||
148 | * @param attests user attribute attestation list (may be empty) | ||
149 | * @return Userinfo JSON | ||
150 | */ | ||
151 | char * | ||
152 | OIDC_generate_userinfo (const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, | ||
153 | struct GNUNET_RECLAIM_AttributeList *attrs, | ||
154 | struct GNUNET_RECLAIM_AttestationList *attests); | ||
155 | |||
128 | #endif | 156 | #endif |
diff --git a/src/reclaim/plugin_rest_openid_connect.c b/src/reclaim/plugin_rest_openid_connect.c index 238cffb85..b294ba166 100644 --- a/src/reclaim/plugin_rest_openid_connect.c +++ b/src/reclaim/plugin_rest_openid_connect.c | |||
@@ -357,10 +357,6 @@ struct OIDC_Variables | |||
357 | */ | 357 | */ |
358 | char *code_verifier; | 358 | char *code_verifier; |
359 | 359 | ||
360 | /** | ||
361 | * The response JSON | ||
362 | */ | ||
363 | json_t *response; | ||
364 | }; | 360 | }; |
365 | 361 | ||
366 | /** | 362 | /** |
@@ -569,7 +565,6 @@ cleanup_handle (struct RequestHandle *handle) | |||
569 | GNUNET_free (handle->oidc->response_type); | 565 | GNUNET_free (handle->oidc->response_type); |
570 | GNUNET_free (handle->oidc->scope); | 566 | GNUNET_free (handle->oidc->scope); |
571 | GNUNET_free (handle->oidc->state); | 567 | GNUNET_free (handle->oidc->state); |
572 | json_decref (handle->oidc->response); | ||
573 | GNUNET_free (handle->oidc); | 568 | GNUNET_free (handle->oidc); |
574 | } | 569 | } |
575 | if (NULL!=handle->attr_idtoken_list) | 570 | if (NULL!=handle->attr_idtoken_list) |
@@ -691,27 +686,6 @@ do_timeout (void *cls) | |||
691 | 686 | ||
692 | 687 | ||
693 | /** | 688 | /** |
694 | * Return attributes for claim | ||
695 | * | ||
696 | * @param cls the request handle | ||
697 | */ | ||
698 | static void | ||
699 | return_userinfo_response (void *cls) | ||
700 | { | ||
701 | char *result_str; | ||
702 | struct RequestHandle *handle = cls; | ||
703 | struct MHD_Response *resp; | ||
704 | |||
705 | result_str = json_dumps (handle->oidc->response, 0); | ||
706 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"ID-Token: %s\n",result_str); | ||
707 | resp = GNUNET_REST_create_response (result_str); | ||
708 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | ||
709 | GNUNET_free (result_str); | ||
710 | cleanup_handle (handle); | ||
711 | } | ||
712 | |||
713 | |||
714 | /** | ||
715 | * Respond to OPTIONS request | 689 | * Respond to OPTIONS request |
716 | * | 690 | * |
717 | * @param con_handle the connection handle | 691 | * @param con_handle the connection handle |
@@ -1153,9 +1127,6 @@ attr_in_claims_request (struct RequestHandle *handle, | |||
1153 | const char *attr_name, | 1127 | const char *attr_name, |
1154 | const char *claims_parameter) | 1128 | const char *claims_parameter) |
1155 | { | 1129 | { |
1156 | char *scope_variables; | ||
1157 | char *scope_variable; | ||
1158 | char delimiter[] = " "; | ||
1159 | int ret = GNUNET_NO; | 1130 | int ret = GNUNET_NO; |
1160 | json_t *root; | 1131 | json_t *root; |
1161 | json_error_t error; | 1132 | json_error_t error; |
@@ -1163,19 +1134,12 @@ attr_in_claims_request (struct RequestHandle *handle, | |||
1163 | const char *key; | 1134 | const char *key; |
1164 | json_t *value; | 1135 | json_t *value; |
1165 | 1136 | ||
1166 | scope_variables = GNUNET_strdup (handle->oidc->scope); | 1137 | /** Check if attribute is requested through standard scope **/ |
1167 | scope_variable = strtok (scope_variables, delimiter); | 1138 | if (GNUNET_YES == OIDC_check_scopes_for_claim_request (handle->oidc->scope, |
1168 | while (NULL != scope_variable) | 1139 | attr_name)) |
1169 | { | 1140 | return GNUNET_YES; |
1170 | if (0 == strcmp (attr_name, scope_variable)) | ||
1171 | break; | ||
1172 | scope_variable = strtok (NULL, delimiter); | ||
1173 | } | ||
1174 | if (NULL != scope_variable) | ||
1175 | ret = GNUNET_YES; | ||
1176 | GNUNET_free (scope_variables); | ||
1177 | 1141 | ||
1178 | /** Try claims parameter if no in scope */ | 1142 | /** Try claims parameter if not in scope */ |
1179 | if ((NULL != handle->oidc->claims) && | 1143 | if ((NULL != handle->oidc->claims) && |
1180 | (GNUNET_YES != ret)) | 1144 | (GNUNET_YES != ret)) |
1181 | { | 1145 | { |
@@ -2122,13 +2086,13 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
2122 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 2086 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
2123 | return; | 2087 | return; |
2124 | } | 2088 | } |
2125 | id_token = OIDC_id_token_new (&ticket.audience, | 2089 | id_token = OIDC_generate_id_token (&ticket.audience, |
2126 | &ticket.identity, | 2090 | &ticket.identity, |
2127 | cl, | 2091 | cl, |
2128 | al, | 2092 | al, |
2129 | &expiration_time, | 2093 | &expiration_time, |
2130 | (NULL != nonce) ? nonce : NULL, | 2094 | (NULL != nonce) ? nonce : NULL, |
2131 | jwt_secret); | 2095 | jwt_secret); |
2132 | access_token = OIDC_access_token_new (&ticket); | 2096 | access_token = OIDC_access_token_new (&ticket); |
2133 | OIDC_build_token_response (access_token, | 2097 | OIDC_build_token_response (access_token, |
2134 | id_token, | 2098 | id_token, |
@@ -2159,83 +2123,55 @@ consume_ticket (void *cls, | |||
2159 | const struct GNUNET_RECLAIM_Attestation *attest) | 2123 | const struct GNUNET_RECLAIM_Attestation *attest) |
2160 | { | 2124 | { |
2161 | struct RequestHandle *handle = cls; | 2125 | struct RequestHandle *handle = cls; |
2126 | struct GNUNET_RECLAIM_AttributeListEntry *ale; | ||
2127 | struct GNUNET_RECLAIM_AttestationListEntry *atle; | ||
2128 | struct MHD_Response *resp; | ||
2129 | char *result_str; | ||
2162 | handle->idp_op = NULL; | 2130 | handle->idp_op = NULL; |
2163 | 2131 | ||
2164 | if (NULL == identity) | 2132 | if (NULL == identity) |
2165 | { | 2133 | { |
2166 | GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle); | 2134 | result_str = OIDC_generate_userinfo (&handle->ticket.identity, |
2135 | handle->attr_userinfo_list, | ||
2136 | handle->attests_list); | ||
2137 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Userinfo: %s\n", result_str); | ||
2138 | resp = GNUNET_REST_create_response (result_str); | ||
2139 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | ||
2140 | GNUNET_free (result_str); | ||
2141 | cleanup_handle (handle); | ||
2167 | return; | 2142 | return; |
2168 | } | 2143 | } |
2169 | if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attr->attestation)) | 2144 | ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry); |
2145 | ale->attribute = GNUNET_RECLAIM_attribute_new (attr->name, | ||
2146 | &attr->attestation, | ||
2147 | attr->type, | ||
2148 | attr->data, | ||
2149 | attr->data_size); | ||
2150 | ale->attribute->id = attr->id; | ||
2151 | ale->attribute->flag = attr->flag; | ||
2152 | ale->attribute->attestation = attr->attestation; | ||
2153 | GNUNET_CONTAINER_DLL_insert (handle->attr_userinfo_list->list_head, | ||
2154 | handle->attr_userinfo_list->list_tail, | ||
2155 | ale); | ||
2156 | for (atle = handle->attests_list->list_head; NULL != atle; atle = atle->next) | ||
2157 | { | ||
2158 | if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (&atle->attestation->id, | ||
2159 | &attest->id)) | ||
2160 | continue; | ||
2161 | break; /** already in list **/ | ||
2162 | } | ||
2163 | if (NULL == atle) | ||
2170 | { | 2164 | { |
2171 | char *tmp_value; | 2165 | /** Attestation matches for attribute, add **/ |
2172 | json_t *value; | 2166 | atle = GNUNET_new (struct GNUNET_RECLAIM_AttestationListEntry); |
2173 | tmp_value = GNUNET_RECLAIM_attribute_value_to_string (attr->type, | 2167 | atle->attestation = GNUNET_RECLAIM_attestation_new (attest->name, |
2174 | attr->data, | 2168 | attest->type, |
2175 | attr->data_size); | 2169 | attest->data, |
2176 | value = json_string (tmp_value); | 2170 | attest->data_size); |
2177 | json_object_set_new (handle->oidc->response, attr->name, value); | 2171 | GNUNET_CONTAINER_DLL_insert (handle->attests_list->list_head, |
2178 | GNUNET_free (tmp_value); | 2172 | handle->attests_list->list_tail, |
2179 | return; | 2173 | atle); |
2180 | } | 2174 | } |
2181 | json_t *claim_sources; | ||
2182 | json_t *claim_sources_jwt; | ||
2183 | json_t *claim_names; | ||
2184 | char *attest_val_str; | ||
2185 | claim_sources = json_object_get (handle->oidc->response,"_claim_sources"); | ||
2186 | claim_names = json_object_get (handle->oidc->response,"_claim_names"); | ||
2187 | attest_val_str = | ||
2188 | GNUNET_RECLAIM_attestation_value_to_string (attest->type, | ||
2189 | attest->data, | ||
2190 | attest->data_size); | ||
2191 | if ((NULL == claim_sources) && (NULL == claim_names) ) | ||
2192 | { | ||
2193 | claim_sources = json_object (); | ||
2194 | claim_names = json_object (); | ||
2195 | } | ||
2196 | char *source_name; | ||
2197 | int i = 0; | ||
2198 | GNUNET_asprintf (&source_name, "src%d", i); | ||
2199 | while (NULL != (claim_sources_jwt = json_object_get (claim_sources, | ||
2200 | source_name))) | ||
2201 | { | ||
2202 | if (0 == strcmp (json_string_value (json_object_get (claim_sources_jwt, | ||
2203 | "JWT")), | ||
2204 | attest_val_str)) | ||
2205 | { | ||
2206 | // Adapt only the claim names | ||
2207 | json_object_set_new (claim_names, attr->data, | ||
2208 | json_string (source_name)); | ||
2209 | json_object_set (handle->oidc->response, | ||
2210 | "_claim_names", claim_names); | ||
2211 | break; | ||
2212 | } | ||
2213 | i++; | ||
2214 | GNUNET_free (source_name); | ||
2215 | GNUNET_asprintf (&source_name, "src%d", i); | ||
2216 | } | ||
2217 | |||
2218 | // Create new one | ||
2219 | if (NULL == claim_sources_jwt) | ||
2220 | { | ||
2221 | claim_sources_jwt = json_object (); | ||
2222 | // Set the JWT for names | ||
2223 | json_object_set_new (claim_names, attr->data, | ||
2224 | json_string (source_name)); | ||
2225 | // Set the JWT for the inner source | ||
2226 | json_object_set_new (claim_sources_jwt, "JWT", | ||
2227 | json_string (attest_val_str)); | ||
2228 | // Set the JWT for the source | ||
2229 | json_object_set_new (claim_sources, source_name, claim_sources_jwt); | ||
2230 | // Set as claims | ||
2231 | json_object_set (handle->oidc->response, "_claim_names", claim_names); | ||
2232 | json_object_set (handle->oidc->response, "_claim_sources",claim_sources); | ||
2233 | } | ||
2234 | |||
2235 | json_decref (claim_sources); | ||
2236 | json_decref (claim_names); | ||
2237 | json_decref (claim_sources_jwt); | ||
2238 | GNUNET_free (attest_val_str); | ||
2239 | } | 2175 | } |
2240 | 2176 | ||
2241 | 2177 | ||
@@ -2253,14 +2189,13 @@ userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
2253 | { | 2189 | { |
2254 | // TODO expiration time | 2190 | // TODO expiration time |
2255 | struct RequestHandle *handle = cls; | 2191 | struct RequestHandle *handle = cls; |
2192 | struct GNUNET_RECLAIM_Ticket *ticket; | ||
2256 | char delimiter[] = " "; | 2193 | char delimiter[] = " "; |
2257 | struct GNUNET_HashCode cache_key; | 2194 | struct GNUNET_HashCode cache_key; |
2258 | char *authorization; | 2195 | char *authorization; |
2259 | char *authorization_type; | 2196 | char *authorization_type; |
2260 | char *authorization_access_token; | 2197 | char *authorization_access_token; |
2261 | struct GNUNET_RECLAIM_Ticket *ticket; | ||
2262 | const struct EgoEntry *aud_ego; | 2198 | const struct EgoEntry *aud_ego; |
2263 | const struct EgoEntry *iss_ego; | ||
2264 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey; | 2199 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey; |
2265 | 2200 | ||
2266 | GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, | 2201 | GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, |
@@ -2316,9 +2251,10 @@ userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
2316 | 2251 | ||
2317 | } | 2252 | } |
2318 | GNUNET_assert (NULL != ticket); | 2253 | GNUNET_assert (NULL != ticket); |
2319 | aud_ego = find_ego (handle, &ticket->audience); | 2254 | handle->ticket = *ticket; |
2320 | iss_ego = find_ego (handle, &ticket->identity); | 2255 | GNUNET_free (ticket); |
2321 | if ((NULL == aud_ego) || (NULL == iss_ego)) | 2256 | aud_ego = find_ego (handle, &handle->ticket.audience); |
2257 | if (NULL == aud_ego) | ||
2322 | { | 2258 | { |
2323 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); | 2259 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); |
2324 | handle->edesc = GNUNET_strdup ("The access token expired"); | 2260 | handle->edesc = GNUNET_strdup ("The access token expired"); |
@@ -2328,16 +2264,16 @@ userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
2328 | return; | 2264 | return; |
2329 | } | 2265 | } |
2330 | 2266 | ||
2331 | handle->oidc->response = json_object (); | ||
2332 | json_object_set_new (handle->oidc->response, | ||
2333 | "sub", | ||
2334 | json_string (iss_ego->keystring)); | ||
2335 | privkey = GNUNET_IDENTITY_ego_get_private_key (aud_ego->ego); | 2267 | privkey = GNUNET_IDENTITY_ego_get_private_key (aud_ego->ego); |
2268 | handle->attr_userinfo_list = | ||
2269 | GNUNET_new (struct GNUNET_RECLAIM_AttributeList); | ||
2270 | handle->attests_list = | ||
2271 | GNUNET_new (struct GNUNET_RECLAIM_AttestationList); | ||
2336 | 2272 | ||
2337 | handle->idp_op = GNUNET_RECLAIM_ticket_consume (idp, | 2273 | handle->idp_op = GNUNET_RECLAIM_ticket_consume (idp, |
2338 | privkey, | 2274 | privkey, |
2339 | ticket, | 2275 | &handle->ticket, |
2340 | consume_ticket, | 2276 | &consume_ticket, |
2341 | handle); | 2277 | handle); |
2342 | GNUNET_free (authorization); | 2278 | GNUNET_free (authorization); |
2343 | } | 2279 | } |
@@ -2535,6 +2471,7 @@ oidc_config_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
2535 | cleanup_handle (handle); | 2471 | cleanup_handle (handle); |
2536 | } | 2472 | } |
2537 | 2473 | ||
2474 | |||
2538 | /** | 2475 | /** |
2539 | * Respond to OPTIONS request | 2476 | * Respond to OPTIONS request |
2540 | * | 2477 | * |
@@ -2544,8 +2481,8 @@ oidc_config_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
2544 | */ | 2481 | */ |
2545 | static void | 2482 | static void |
2546 | oidc_config_cors (struct GNUNET_REST_RequestHandle *con_handle, | 2483 | oidc_config_cors (struct GNUNET_REST_RequestHandle *con_handle, |
2547 | const char *url, | 2484 | const char *url, |
2548 | void *cls) | 2485 | void *cls) |
2549 | { | 2486 | { |
2550 | struct MHD_Response *resp; | 2487 | struct MHD_Response *resp; |
2551 | struct RequestHandle *handle = cls; | 2488 | struct RequestHandle *handle = cls; |
@@ -2560,7 +2497,6 @@ oidc_config_cors (struct GNUNET_REST_RequestHandle *con_handle, | |||
2560 | } | 2497 | } |
2561 | 2498 | ||
2562 | 2499 | ||
2563 | |||
2564 | static enum GNUNET_GenericReturnValue | 2500 | static enum GNUNET_GenericReturnValue |
2565 | rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle, | 2501 | rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle, |
2566 | GNUNET_REST_ResultProcessor proc, | 2502 | GNUNET_REST_ResultProcessor proc, |