From 8de33e06f38cb241cd3fc47f9576c2b3ca6c69a8 Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Tue, 20 Nov 2012 15:50:57 +0200 Subject: [PATCH] webticket: implement caching Once we have generated a wsse_security string for a Service URI we store it and its Authentication URI in a hash table. If another request for the same URI is made then we simply use the stored token instead of requesting a new one. This will speed up all operations that depend on Web Tickets. NOTE: callers of sipe_webticket_request() must be prepared that the callback is called immediately from inside that function, i.e. the callback data must be properly initialized already. TODO: add expiration timestamp for tokens to cache. --- src/core/sipe-core-private.h | 4 +- src/core/sipe-core.c | 2 + src/core/sipe-webticket.c | 117 +++++++++++++++++++++++++++++++++++++------ src/core/sipe-webticket.h | 10 ++++ 4 files changed, 117 insertions(+), 16 deletions(-) diff --git a/src/core/sipe-core-private.h b/src/core/sipe-core-private.h index 23ac0456..a9105b1f 100644 --- a/src/core/sipe-core-private.h +++ b/src/core/sipe-core-private.h @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2010-11 SIPE Project + * Copyright (C) 2010-12 SIPE Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +29,7 @@ struct sipe_certificate; struct sipe_media_call_private; struct sipe_groupchat; struct sipe_svc; +struct sipe_webticket; /** * Private part of the Sipe data structure @@ -134,6 +135,7 @@ struct sipe_core_private { /* TLS-DSK: Certificates & Web services */ struct sipe_certificate *certificate; + struct sipe_webticket *webticket; struct sipe_svc *svc; /* [MS-DLX] server URI */ diff --git a/src/core/sipe-core.c b/src/core/sipe-core.c index 2071b3b9..dc049c0e 100644 --- a/src/core/sipe-core.c +++ b/src/core/sipe-core.c @@ -94,6 +94,7 @@ #include "sipe-subscriptions.h" #include "sipe-svc.h" #include "sipe-utils.h" +#include "sipe-webticket.h" /* locale_dir is unused if ENABLE_NLS is not defined */ void sipe_core_init(SIPE_UNUSED_PARAMETER const char *locale_dir) @@ -389,6 +390,7 @@ void sipe_core_deallocate(struct sipe_core_public *sipe_public) sip_csta_close(sipe_private); } + sipe_webticket_free(sipe_private); sipe_svc_free(sipe_private); if (sipe_backend_connection_is_valid(SIPE_CORE_PUBLIC)) { diff --git a/src/core/sipe-webticket.c b/src/core/sipe-webticket.c index 62ae2922..6c62d7c3 100644 --- a/src/core/sipe-webticket.c +++ b/src/core/sipe-webticket.c @@ -63,6 +63,72 @@ struct webticket_callback_data { struct sipe_svc_session *session; }; +struct webticket_token { + gchar *auth_uri; + gchar *token; +}; + +struct sipe_webticket { + GHashTable *cache; +}; + +void sipe_webticket_free(struct sipe_core_private *sipe_private) +{ + struct sipe_webticket *webticket = sipe_private->webticket; + if (!webticket) + return; + + if (webticket->cache) + g_hash_table_destroy(webticket->cache); + g_free(webticket); + sipe_private->webticket = NULL; +} + +static void free_token(gpointer data) +{ + struct webticket_token *wt = data; + g_free(wt->auth_uri); + g_free(wt->token); + g_free(wt); +} + +static void sipe_webticket_init(struct sipe_core_private *sipe_private) +{ + struct sipe_webticket *webticket; + + if (sipe_private->webticket) + return; + + sipe_private->webticket = webticket = g_new0(struct sipe_webticket, 1); + + webticket->cache = g_hash_table_new_full(g_str_hash, + g_str_equal, + g_free, + free_token); +} + +/* takes ownership of "token" */ +static void cache_token(struct sipe_core_private *sipe_private, + const gchar *service_uri, + const gchar *auth_uri, + gchar *token) +{ + struct webticket_token *wt = g_new0(struct webticket_token, 1); + wt->auth_uri = g_strdup(auth_uri); + wt->token = token; + g_hash_table_insert(sipe_private->webticket->cache, + g_strdup(service_uri), + wt); +} + +static const struct webticket_token *cache_hit(struct sipe_core_private *sipe_private, + const gchar *service_uri) +{ + sipe_webticket_init(sipe_private); + return(g_hash_table_lookup(sipe_private->webticket->cache, + service_uri)); +} + static void callback_data_free(struct webticket_callback_data *wcd) { if (wcd) { @@ -277,13 +343,17 @@ static void webticket_token(struct sipe_core_private *sipe_private, wcd->requires_signing ? &wcd->entropy : NULL); if (wsse_security) { + /* cache takes ownership of wsse_security */ + cache_token(sipe_private, + wcd->service_uri, + wcd->service_auth_uri, + wsse_security); callback_execute(sipe_private, wcd, wcd->service_auth_uri, wsse_security, NULL); failed = FALSE; - g_free(wsse_security); } /* WebTicket for federated authentication */ @@ -592,21 +662,38 @@ gboolean sipe_webticket_request(struct sipe_core_private *sipe_private, sipe_webticket_callback *callback, gpointer callback_data) { - struct webticket_callback_data *wcd = g_new0(struct webticket_callback_data, 1); - gboolean ret = sipe_svc_metadata(sipe_private, - session, - base_uri, - service_metadata, - wcd); - - if (ret) { - wcd->service_uri = g_strdup(base_uri); - wcd->service_port = port_name; - wcd->callback = callback; - wcd->callback_data = callback_data; - wcd->session = session; + const struct webticket_token *wt = cache_hit(sipe_private, base_uri); + gboolean ret; + + /* cache hit for this URI? */ + if (wt) { + SIPE_DEBUG_INFO("sipe_webticket_request: using cached token for URI %s (Auth URI %s)", + base_uri, wt->auth_uri); + callback(sipe_private, + base_uri, + wt->auth_uri, + wt->token, + NULL, + callback_data); + ret = TRUE; } else { - g_free(wcd); + struct webticket_callback_data *wcd = g_new0(struct webticket_callback_data, 1); + + ret = sipe_svc_metadata(sipe_private, + session, + base_uri, + service_metadata, + wcd); + + if (ret) { + wcd->service_uri = g_strdup(base_uri); + wcd->service_port = port_name; + wcd->callback = callback; + wcd->callback_data = callback_data; + wcd->session = session; + } else { + g_free(wcd); + } } return(ret); diff --git a/src/core/sipe-webticket.h b/src/core/sipe-webticket.h index 9b2de3bb..cd4b6e96 100644 --- a/src/core/sipe-webticket.h +++ b/src/core/sipe-webticket.h @@ -51,6 +51,9 @@ typedef void (sipe_webticket_callback)(struct sipe_core_private *sipe_private, /** * Request a Web Ticket for Web Service URI * + * NOTE: the callback can be called immediately if the Web Ticket is cached. + * The callback data must therefore be properly initialized already. + * * @param sipe_private SIPE core private data * @param base_uri Web Service base URI * @param port_name Web Service authentication port name @@ -64,3 +67,10 @@ gboolean sipe_webticket_request(struct sipe_core_private *sipe_private, const gchar *port_name, sipe_webticket_callback *callback, gpointer callback_data); + +/** + * Free webticket data + * + * @param sipe_private SIPE core private data + */ +void sipe_webticket_free(struct sipe_core_private *sipe_private); -- 2.11.4.GIT