2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public Liceidentity as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public Liceidentity for more details.
15 You should have received a copy of the GNU General Public Liceidentity
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file identity-provider/identity_provider_api.c
23 * @brief api to interact with the identity provider service
24 * @author Martin Schanzenbach
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_mq_lib.h"
31 #include "gnunet_identity_provider_service.h"
32 #include "identity_provider.h"
34 #define LOG(kind,...) GNUNET_log_from (kind, "identity-api",__VA_ARGS__)
39 * Handle for an operation with the service.
41 struct GNUNET_IDENTITY_PROVIDER_Operation
47 struct GNUNET_IDENTITY_PROVIDER_Handle *h;
50 * We keep operations in a DLL.
52 struct GNUNET_IDENTITY_PROVIDER_Operation *next;
55 * We keep operations in a DLL.
57 struct GNUNET_IDENTITY_PROVIDER_Operation *prev;
60 * Message to send to the service.
61 * Allocated at the end of this struct.
63 const struct GNUNET_MessageHeader *msg;
66 * Continuation to invoke with the result of the transmission; @e cb
67 * will be NULL in this case.
69 GNUNET_IDENTITY_PROVIDER_ExchangeCallback ex_cb;
72 * Continuation to invoke with the result of the transmission for
73 * 'issue' operations (@e cont will be NULL in this case).
75 GNUNET_IDENTITY_PROVIDER_IssueCallback iss_cb;
78 * Envelope with the message for this queue entry.
80 struct GNUNET_MQ_Envelope *env;
88 * Closure for @e cont or @e cb.
96 * Handle for the service.
98 struct GNUNET_IDENTITY_PROVIDER_Handle
101 * Configuration to use.
103 const struct GNUNET_CONFIGURATION_Handle *cfg;
106 * Socket (if available).
108 struct GNUNET_CLIENT_Connection *client;
116 * Head of active operations.
118 struct GNUNET_IDENTITY_PROVIDER_Operation *op_head;
121 * Tail of active operations.
123 struct GNUNET_IDENTITY_PROVIDER_Operation *op_tail;
126 * Currently pending transmission request, or NULL for none.
128 struct GNUNET_CLIENT_TransmitHandle *th;
131 * Task doing exponential back-off trying to reconnect.
133 struct GNUNET_SCHEDULER_Task * reconnect_task;
136 * Time for next connect retry.
138 struct GNUNET_TIME_Relative reconnect_backoff;
141 * Connection to service (if available).
143 struct GNUNET_MQ_Handle *mq;
146 * Request Id generator. Incremented by one for each request.
151 * Are we polling for incoming messages right now?
159 * Try again to connect to the service.
161 * @param cls handle to the service.
164 reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *handle);
169 * @param cls the handle
172 reconnect_task (void *cls)
174 struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls;
176 handle->reconnect_task = NULL;
182 * Disconnect from service and then reconnect.
184 * @param handle our handle
187 force_reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *handle)
189 GNUNET_MQ_destroy (handle->mq);
191 handle->reconnect_backoff
192 = GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff);
193 handle->reconnect_task
194 = GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff,
200 * Generic error handler, called with the appropriate error code and
201 * the same closure specified at the creation of the message queue.
202 * Not every message queue implementation supports an error handler.
204 * @param cls closure with the `struct GNUNET_GNS_Handle *`
205 * @param error error code
208 mq_error_handler (void *cls,
209 enum GNUNET_MQ_Error error)
211 struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls;
212 force_reconnect (handle);
216 * Check validity of message received from the service
218 * @param cls the `struct GNUNET_IDENTITY_PROVIDER_Handle *`
219 * @param result_msg the incoming message
222 check_exchange_result (void *cls,
223 const struct ExchangeResultMessage *erm)
226 size_t size = ntohs (erm->header.size) - sizeof (*erm);
229 str = (char *) &erm[1];
230 if ( (size > sizeof (struct ExchangeResultMessage)) &&
231 ('\0' != str[size - sizeof (struct ExchangeResultMessage) - 1]) )
234 return GNUNET_SYSERR;
241 * Check validity of message received from the service
243 * @param cls the `struct GNUNET_IDENTITY_PROVIDER_Handle *`
244 * @param result_msg the incoming message
247 check_result (void *cls,
248 const struct IssueResultMessage *irm)
251 size_t size = ntohs (irm->header.size) - sizeof (*irm);
252 str = (char*) &irm[1];
253 if ( (size > sizeof (struct IssueResultMessage)) &&
254 ('\0' != str[size - sizeof (struct IssueResultMessage) - 1]) )
257 return GNUNET_SYSERR;
263 * Handler for messages received from the GNS service
265 * @param cls the `struct GNUNET_GNS_Handle *`
266 * @param loookup_msg the incoming message
269 handle_exchange_result (void *cls,
270 const struct ExchangeResultMessage *erm)
272 struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls;
273 struct GNUNET_IDENTITY_PROVIDER_Operation *op;
274 struct GNUNET_IDENTITY_PROVIDER_Token token;
275 uint64_t ticket_nonce;
276 uint32_t r_id = ntohl (erm->id);
279 for (op = handle->op_head; NULL != op; op = op->next)
280 if (op->r_id == r_id)
284 str = GNUNET_strdup ((char*)&erm[1]);
285 op = handle->op_head;
286 GNUNET_CONTAINER_DLL_remove (handle->op_head,
290 ticket_nonce = ntohl (erm->ticket_nonce);
291 if (NULL != op->ex_cb)
292 op->ex_cb (op->cls, &token, ticket_nonce);
299 * Handler for messages received from the GNS service
301 * @param cls the `struct GNUNET_GNS_Handle *`
302 * @param loookup_msg the incoming message
305 handle_result (void *cls,
306 const struct IssueResultMessage *irm)
308 struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls;
309 struct GNUNET_IDENTITY_PROVIDER_Operation *op;
310 struct GNUNET_IDENTITY_PROVIDER_Token token;
311 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
312 uint32_t r_id = ntohl (irm->id);
318 for (op = handle->op_head; NULL != op; op = op->next)
319 if (op->r_id == r_id)
323 str = GNUNET_strdup ((char*)&irm[1]);
324 label_str = strtok (str, ",");
326 if (NULL == label_str)
332 ticket_str = strtok (NULL, ",");
333 if (NULL == ticket_str)
339 token_str = strtok (NULL, ",");
340 if (NULL == token_str)
346 GNUNET_CONTAINER_DLL_remove (handle->op_head,
349 ticket.data = ticket_str;
350 token.data = token_str;
351 if (NULL != op->iss_cb)
352 op->iss_cb (op->cls, label_str, &ticket, &token);
359 * Try again to connect to the service.
361 * @param cls handle to the identity provider service.
364 reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h)
366 struct GNUNET_MQ_MessageHandler handlers[] = {
367 GNUNET_MQ_hd_var_size (result,
368 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT,
369 struct IssueResultMessage,
371 GNUNET_MQ_hd_var_size (exchange_result,
372 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT,
373 struct ExchangeResultMessage,
375 GNUNET_MQ_handler_end ()
377 struct GNUNET_IDENTITY_PROVIDER_Operation *op;
379 GNUNET_assert (NULL == h->mq);
380 LOG (GNUNET_ERROR_TYPE_DEBUG,
381 "Connecting to identity provider service.\n");
383 h->mq = GNUNET_CLIENT_connect (h->cfg,
390 for (op = h->op_head; NULL != op; op = op->next)
391 GNUNET_MQ_send_copy (h->mq,
397 * Connect to the identity provider service.
399 * @param cfg the configuration to use
400 * @return handle to use
402 struct GNUNET_IDENTITY_PROVIDER_Handle *
403 GNUNET_IDENTITY_PROVIDER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
405 struct GNUNET_IDENTITY_PROVIDER_Handle *h;
407 h = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Handle);
420 * Issue an identity token
422 * @param id identity service to query
423 * @param service_name for which service is an identity wanted
424 * @param cb function to call with the result (will only be called once)
425 * @param cb_cls closure for @a cb
426 * @return handle to abort the operation
428 struct GNUNET_IDENTITY_PROVIDER_Operation *
429 GNUNET_IDENTITY_PROVIDER_issue_token (struct GNUNET_IDENTITY_PROVIDER_Handle *id,
430 const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss_key,
431 const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
433 struct GNUNET_TIME_Absolute expiration,
435 GNUNET_IDENTITY_PROVIDER_IssueCallback cb,
438 struct GNUNET_IDENTITY_PROVIDER_Operation *op;
439 struct IssueMessage *im;
442 slen = strlen (scopes) + 1;
443 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct IssueMessage))
448 op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
452 op->r_id = id->r_id_gen++;
453 op->env = GNUNET_MQ_msg_extra (im,
455 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE);
457 im->iss_key = *iss_key;
458 im->aud_key = *aud_key;
459 im->nonce = htonl (nonce);
460 im->expiration = GNUNET_TIME_absolute_hton (expiration);
461 GNUNET_memcpy (&im[1], scopes, slen);
462 GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
466 GNUNET_MQ_send_copy (id->mq,
473 * Exchange a token ticket for a token
475 * @param id identity provider service
476 * @param ticket ticket to exchange
477 * @param cont function to call once the operation finished
478 * @param cont_cls closure for @a cont
479 * @return handle to abort the operation
481 struct GNUNET_IDENTITY_PROVIDER_Operation *
482 GNUNET_IDENTITY_PROVIDER_exchange_ticket (struct GNUNET_IDENTITY_PROVIDER_Handle *id,
483 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket,
484 const struct GNUNET_CRYPTO_EcdsaPrivateKey *aud_privkey,
485 GNUNET_IDENTITY_PROVIDER_ExchangeCallback cont,
488 struct GNUNET_IDENTITY_PROVIDER_Operation *op;
489 struct ExchangeMessage *em;
493 ticket_str = GNUNET_IDENTITY_PROVIDER_ticket_to_string (ticket);
495 slen = strlen (ticket_str) + 1;
496 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct ExchangeMessage))
498 GNUNET_free (ticket_str);
502 op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
506 op->r_id = id->r_id_gen++;
507 op->env = GNUNET_MQ_msg_extra (em,
509 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE);
510 em->aud_privkey = *aud_privkey;
511 em->id = htonl (op->r_id);
512 GNUNET_memcpy (&em[1], ticket_str, slen);
513 GNUNET_free (ticket_str);
514 GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
518 GNUNET_MQ_send_copy (id->mq,
525 * Cancel an operation. Note that the operation MAY still
526 * be executed; this merely cancels the continuation; if the request
527 * was already transmitted, the service may still choose to complete
530 * @param op operation to cancel
533 GNUNET_IDENTITY_PROVIDER_cancel (struct GNUNET_IDENTITY_PROVIDER_Operation *op)
535 struct GNUNET_IDENTITY_PROVIDER_Handle *h = op->h;
537 GNUNET_CONTAINER_DLL_remove (h->op_head,
540 GNUNET_MQ_discard (op->env);
546 * Disconnect from service
548 * @param h handle to destroy
551 GNUNET_IDENTITY_PROVIDER_disconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h)
553 GNUNET_assert (NULL != h);
556 GNUNET_MQ_destroy (h->mq);
559 if (NULL != h->reconnect_task)
561 GNUNET_SCHEDULER_cancel (h->reconnect_task);
562 h->reconnect_task = NULL;
564 GNUNET_assert (NULL == h->op_head);
576 * @param token the token
579 GNUNET_IDENTITY_PROVIDER_token_destroy(struct GNUNET_IDENTITY_PROVIDER_Token *token)
581 GNUNET_assert (NULL != token);
582 if (NULL != token->data)
583 GNUNET_free (token->data);
588 * Returns string representation of token. A JSON-Web-Token.
590 * @param token the token
591 * @return The JWT (must be freed)
594 GNUNET_IDENTITY_PROVIDER_token_to_string (const struct GNUNET_IDENTITY_PROVIDER_Token *token)
596 return GNUNET_strdup (token->data);
600 * Returns string representation of ticket. Base64-Encoded
602 * @param ticket the ticket
603 * @return the Base64-Encoded ticket
606 GNUNET_IDENTITY_PROVIDER_ticket_to_string (const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
608 return GNUNET_strdup (ticket->data);
612 * Created a ticket from a string (Base64 encoded ticket)
614 * @param input Base64 encoded ticket
615 * @param ticket pointer where the ticket is stored
619 GNUNET_IDENTITY_PROVIDER_string_to_ticket (const char* input,
620 struct GNUNET_IDENTITY_PROVIDER_Ticket **ticket)
622 *ticket = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket));
623 (*ticket)->data = GNUNET_strdup (input);
631 * @param ticket the ticket to destroy
634 GNUNET_IDENTITY_PROVIDER_ticket_destroy(struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
636 GNUNET_assert (NULL != ticket);
637 if (NULL != ticket->data)
638 GNUNET_free (ticket->data);
639 GNUNET_free (ticket);
646 /* end of identity_provider_api.c */