aboutsummaryrefslogtreecommitdiff
path: root/src/reclaim
diff options
context:
space:
mode:
Diffstat (limited to 'src/reclaim')
-rw-r--r--src/reclaim/oidc_helper.c313
-rw-r--r--src/reclaim/oidc_helper.h30
-rw-r--r--src/reclaim/plugin_rest_openid_connect.c198
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
70GNUNET_NETWORK_STRUCT_END 70GNUNET_NETWORK_STRUCT_END
71 71
72/**
73 * Standard claims represented by the "profile" scope in OIDC
74 */
75static 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 */
84static char OIDC_email_claims[2][16] = {
85 "email", "email_verified"
86};
87
88/**
89 * Standard claims represented by the "phone" scope in OIDC
90 */
91static 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 */
98static char OIDC_address_claims[5][32] = {
99 "street_address", "locality", "region", "postal_code", "country"
100};
101
102static enum GNUNET_GenericReturnValue
103is_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
72static char * 117static char *
73create_jwt_header (void) 118create_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 157static json_t*
113/** 158generate_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 */
123char *
124OIDC_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 */
302char *
303OIDC_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 */
327char *
328OIDC_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 *) &params[1]); 655 code_challenge = ((char *) &params[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, &params->ticket, sizeof(params->ticket)); 680 memcpy (ticket, &params->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 */
791enum GNUNET_GenericReturnValue
792OIDC_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 */
51char* 51char*
52OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, 52OIDC_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);
125int 125int
126OIDC_access_token_parse (const char* token, 126OIDC_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 */
138enum GNUNET_GenericReturnValue
139OIDC_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 */
151char *
152OIDC_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 */
698static void
699return_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 */
2545static void 2482static void
2546oidc_config_cors (struct GNUNET_REST_RequestHandle *con_handle, 2483oidc_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
2564static enum GNUNET_GenericReturnValue 2500static enum GNUNET_GenericReturnValue
2565rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle, 2501rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
2566 GNUNET_REST_ResultProcessor proc, 2502 GNUNET_REST_ResultProcessor proc,