webticket: only retrieve RealmInfo once
[siplcs.git] / src / core / sipe-webticket.c
bloba566045217c3870fe7578221ea15f5255a7af926
1 /**
2 * @file sipe-webticket.c
4 * pidgin-sipe
6 * Copyright (C) 2011-12 SIPE Project <http://sipe.sourceforge.net/>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Specification references:
26 * - [MS-OCAUTHWS]: http://msdn.microsoft.com/en-us/library/ff595592.aspx
27 * - MS Tech-Ed Europe 2010 "UNC310: Microsoft Lync 2010 Technology Explained"
28 * http://ecn.channel9.msdn.com/o9/te/Europe/2010/pptx/unc310.pptx
31 #include <string.h>
32 #include <time.h>
34 #include <glib.h>
36 #include "sipe-common.h"
37 #include "sipe-backend.h"
38 #include "sipe-core.h"
39 #include "sipe-core-private.h"
40 #include "sipe-digest.h"
41 #include "sipe-svc.h"
42 #include "sipe-tls.h"
43 #include "sipe-webticket.h"
44 #include "sipe-utils.h"
45 #include "sipe-xml.h"
47 struct webticket_queued_data {
48 sipe_webticket_callback *callback;
49 gpointer callback_data;
52 struct webticket_callback_data {
53 gchar *service_uri;
54 const gchar *service_port;
55 gchar *service_auth_uri;
57 gchar *webticket_negotiate_uri;
58 gchar *webticket_fedbearer_uri;
60 gboolean tried_fedbearer;
61 gboolean requires_signing;
62 enum {
63 TOKEN_STATE_NONE = 0,
64 TOKEN_STATE_SERVICE,
65 TOKEN_STATE_FEDERATION,
66 TOKEN_STATE_FED_BEARER,
67 } token_state;
69 struct sipe_tls_random entropy;
71 sipe_webticket_callback *callback;
72 gpointer callback_data;
74 struct sipe_svc_session *session;
76 GSList *queued;
79 struct webticket_token {
80 gchar *auth_uri;
81 gchar *token;
82 time_t expires;
85 struct sipe_webticket {
86 GHashTable *cache;
87 GHashTable *pending;
89 gchar *webticket_adfs_uri;
91 gboolean retrieved_realminfo;
94 void sipe_webticket_free(struct sipe_core_private *sipe_private)
96 struct sipe_webticket *webticket = sipe_private->webticket;
97 if (!webticket)
98 return;
100 g_free(webticket->webticket_adfs_uri);
101 if (webticket->pending)
102 g_hash_table_destroy(webticket->pending);
103 if (webticket->cache)
104 g_hash_table_destroy(webticket->cache);
105 g_free(webticket);
106 sipe_private->webticket = NULL;
109 static void free_token(gpointer data)
111 struct webticket_token *wt = data;
112 g_free(wt->auth_uri);
113 g_free(wt->token);
114 g_free(wt);
117 static void sipe_webticket_init(struct sipe_core_private *sipe_private)
119 struct sipe_webticket *webticket;
121 if (sipe_private->webticket)
122 return;
124 sipe_private->webticket = webticket = g_new0(struct sipe_webticket, 1);
126 webticket->cache = g_hash_table_new_full(g_str_hash,
127 g_str_equal,
128 g_free,
129 free_token);
130 webticket->pending = g_hash_table_new(g_str_hash,
131 g_str_equal);
134 /* takes ownership of "token" */
135 static void cache_token(struct sipe_core_private *sipe_private,
136 const gchar *service_uri,
137 const gchar *auth_uri,
138 gchar *token,
139 time_t expires)
141 struct webticket_token *wt = g_new0(struct webticket_token, 1);
142 wt->auth_uri = g_strdup(auth_uri);
143 wt->token = token;
144 wt->expires = expires;
145 g_hash_table_insert(sipe_private->webticket->cache,
146 g_strdup(service_uri),
147 wt);
150 static const struct webticket_token *cache_hit(struct sipe_core_private *sipe_private,
151 const gchar *service_uri)
153 const struct webticket_token *wt;
155 sipe_webticket_init(sipe_private);
157 /* make sure a cached Web Ticket is still valid for 60 seconds */
158 wt = g_hash_table_lookup(sipe_private->webticket->cache,
159 service_uri);
160 if (wt && (wt->expires < time(NULL) + 60)) {
161 SIPE_DEBUG_INFO("cache_hit: cached token for URI %s has expired",
162 service_uri);
163 wt = NULL;
166 return(wt);
169 /* frees just the main request data, when this is called "queued" is cleared */
170 static void callback_data_free(struct webticket_callback_data *wcd)
172 if (wcd) {
173 sipe_tls_free_random(&wcd->entropy);
174 g_free(wcd->webticket_negotiate_uri);
175 g_free(wcd->webticket_fedbearer_uri);
176 g_free(wcd->service_auth_uri);
177 g_free(wcd->service_uri);
178 g_free(wcd);
182 static void queue_request(struct webticket_callback_data *wcd,
183 sipe_webticket_callback *callback,
184 gpointer callback_data)
186 struct webticket_queued_data *wqd = g_new0(struct webticket_queued_data, 1);
188 wqd->callback = callback;
189 wqd->callback_data = callback_data;
191 wcd->queued = g_slist_prepend(wcd->queued, wqd);
194 static void callback_execute(struct sipe_core_private *sipe_private,
195 struct webticket_callback_data *wcd,
196 const gchar *auth_uri,
197 const gchar *wsse_security,
198 const gchar *failure_msg)
200 GSList *entry = wcd->queued;
202 /* complete main request */
203 wcd->callback(sipe_private,
204 wcd->service_uri,
205 auth_uri,
206 wsse_security,
207 failure_msg,
208 wcd->callback_data);
210 /* complete queued requests */
211 while (entry) {
212 struct webticket_queued_data *wqd = entry->data;
214 SIPE_DEBUG_INFO("callback_execute: completing queue request URI %s (Auth URI %s)",
215 wcd->service_uri, auth_uri);
216 wqd->callback(sipe_private,
217 wcd->service_uri,
218 auth_uri,
219 wsse_security,
220 failure_msg,
221 wqd->callback_data);
223 g_free(wqd);
224 entry = entry->next;
226 g_slist_free(wcd->queued);
228 /* drop request from pending hash */
229 g_hash_table_remove(sipe_private->webticket->pending,
230 wcd->service_uri);
233 static gchar *extract_raw_xml_attribute(const gchar *xml,
234 const gchar *name)
236 gchar *attr_start = g_strdup_printf("%s=\"", name);
237 gchar *data = NULL;
238 const gchar *start = strstr(xml, attr_start);
240 if (start) {
241 const gchar *value = start + strlen(attr_start);
242 const gchar *end = strchr(value, '"');
243 if (end) {
244 data = g_strndup(value, end - value);
248 g_free(attr_start);
249 return(data);
252 static gchar *generate_timestamp(const gchar *raw,
253 const gchar *lifetime_tag)
255 gchar *lifetime = sipe_xml_extract_raw(raw, lifetime_tag, FALSE);
256 gchar *timestamp = NULL;
257 if (lifetime)
258 timestamp = g_strdup_printf("<wsu:Timestamp xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" wsu:Id=\"timestamp\">%s</wsu:Timestamp>",
259 lifetime);
260 g_free(lifetime);
261 return(timestamp);
264 static gchar *generate_fedbearer_wsse(const gchar *raw)
266 gchar *timestamp = generate_timestamp(raw, "wst:Lifetime");
267 gchar *keydata = sipe_xml_extract_raw(raw, "EncryptedData", TRUE);
268 gchar *wsse_security = NULL;
270 if (timestamp && keydata) {
271 SIPE_DEBUG_INFO_NOFORMAT("generate_fedbearer_wsse: found timestamp & keydata");
272 wsse_security = g_strconcat(timestamp, keydata, NULL);
275 g_free(keydata);
276 g_free(timestamp);
277 return(wsse_security);
280 static gchar *generate_federation_wsse(const gchar *raw)
282 gchar *timestamp = generate_timestamp(raw, "t:Lifetime");
283 gchar *keydata = sipe_xml_extract_raw(raw, "saml:Assertion", TRUE);
284 gchar *wsse_security = NULL;
286 if (timestamp && keydata) {
287 SIPE_DEBUG_INFO_NOFORMAT("generate_federation_wsse: found timestamp & keydata");
288 wsse_security = g_strconcat(timestamp, keydata, NULL);
291 g_free(keydata);
292 g_free(timestamp);
293 return(wsse_security);
296 static gchar *generate_sha1_proof_wsse(const gchar *raw,
297 struct sipe_tls_random *entropy,
298 time_t *expires)
300 gchar *timestamp = generate_timestamp(raw, "Lifetime");
301 gchar *keydata = sipe_xml_extract_raw(raw, "saml:Assertion", TRUE);
302 gchar *wsse_security = NULL;
304 if (timestamp && keydata) {
305 gchar *expires_string = sipe_xml_extract_raw(timestamp,
306 "Expires",
307 FALSE);
309 if (entropy) {
310 gchar *assertionID = extract_raw_xml_attribute(keydata,
311 "AssertionID");
314 * WS-Trust 1.3
316 * http://docs.oasis-open.org/ws-sx/ws-trust/200512/CK/PSHA1:
318 * "The key is computed using P_SHA1() from the TLS sepcification to generate
319 * a bit stream using entropy from both sides. The exact form is:
321 * key = P_SHA1(Entropy_REQ, Entropy_RES)"
323 gchar *entropy_res_base64 = sipe_xml_extract_raw(raw, "BinarySecret", FALSE);
324 gsize entropy_res_length;
325 guchar *entropy_response = g_base64_decode(entropy_res_base64,
326 &entropy_res_length);
327 guchar *key = sipe_tls_p_sha1(entropy->buffer,
328 entropy->length,
329 entropy_response,
330 entropy_res_length,
331 entropy->length);
332 g_free(entropy_response);
333 g_free(entropy_res_base64);
335 SIPE_DEBUG_INFO_NOFORMAT("generate_sha1_proof_wsse: found timestamp & keydata");
337 if (assertionID && key) {
338 /* same as SIPE_DIGEST_HMAC_SHA1_LENGTH */
339 guchar digest[SIPE_DIGEST_SHA1_LENGTH];
340 gchar *base64;
341 gchar *signed_info;
342 gchar *canon;
344 SIPE_DEBUG_INFO_NOFORMAT("generate_sha1_proof_wsse: found assertionID and successfully computed the key");
346 /* Digest over reference element (#timestamp -> wsu:Timestamp) */
347 sipe_digest_sha1((guchar *) timestamp,
348 strlen(timestamp),
349 digest);
350 base64 = g_base64_encode(digest,
351 SIPE_DIGEST_SHA1_LENGTH);
353 /* XML-Sig: SignedInfo for reference element */
354 signed_info = g_strdup_printf("<SignedInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">"
355 "<CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>"
356 "<SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#hmac-sha1\"/>"
357 "<Reference URI=\"#timestamp\">"
358 "<Transforms>"
359 "<Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>"
360 "</Transforms>"
361 "<DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/>"
362 "<DigestValue>%s</DigestValue>"
363 "</Reference>"
364 "</SignedInfo>",
365 base64);
366 g_free(base64);
368 /* XML-Sig: SignedInfo in canonical form */
369 canon = sipe_xml_exc_c14n(signed_info);
370 g_free(signed_info);
372 if (canon) {
373 gchar *signature;
375 /* calculate signature */
376 sipe_digest_hmac_sha1(key, entropy->length,
377 (guchar *)canon,
378 strlen(canon),
379 digest);
380 base64 = g_base64_encode(digest,
381 SIPE_DIGEST_HMAC_SHA1_LENGTH);
383 /* XML-Sig: Signature from SignedInfo + Key */
384 signature = g_strdup_printf("<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\">"
385 " %s"
386 " <SignatureValue>%s</SignatureValue>"
387 " <KeyInfo>"
388 " <wsse:SecurityTokenReference wsse:TokenType=\"http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1\">"
389 " <wsse:KeyIdentifier ValueType=\"http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID\">%s</wsse:KeyIdentifier>"
390 " </wsse:SecurityTokenReference>"
391 " </KeyInfo>"
392 "</Signature>",
393 canon,
394 base64,
395 assertionID);
396 g_free(base64);
397 g_free(canon);
399 wsse_security = g_strconcat(timestamp,
400 keydata,
401 signature,
402 NULL);
403 g_free(signature);
408 g_free(key);
409 g_free(assertionID);
410 } else {
411 /* token doesn't require signature */
412 SIPE_DEBUG_INFO_NOFORMAT("generate_sha1_proof_wsse: found timestamp & keydata, no signing required");
413 wsse_security = g_strconcat(timestamp,
414 keydata,
415 NULL);
418 *expires = 0;
419 if (expires_string) {
420 *expires = sipe_utils_str_to_time(expires_string);
421 g_free(expires_string);
425 g_free(keydata);
426 g_free(timestamp);
427 return(wsse_security);
430 static gboolean initiate_fedbearer(struct sipe_core_private *sipe_private,
431 struct webticket_callback_data *wcd);
432 static void webticket_token(struct sipe_core_private *sipe_private,
433 const gchar *uri,
434 const gchar *raw,
435 sipe_xml *soap_body,
436 gpointer callback_data)
438 struct webticket_callback_data *wcd = callback_data;
439 gboolean failed = TRUE;
441 if (soap_body) {
442 switch (wcd->token_state) {
443 case TOKEN_STATE_NONE:
444 SIPE_DEBUG_INFO_NOFORMAT("webticket_token: ILLEGAL STATE - should not happen...");
445 break;
447 case TOKEN_STATE_SERVICE: {
448 /* WebTicket for Web Service */
449 time_t expires;
450 gchar *wsse_security = generate_sha1_proof_wsse(raw,
451 wcd->requires_signing ? &wcd->entropy : NULL,
452 &expires);
454 if (wsse_security) {
455 /* cache takes ownership of wsse_security */
456 cache_token(sipe_private,
457 wcd->service_uri,
458 wcd->service_auth_uri,
459 wsse_security,
460 expires);
461 callback_execute(sipe_private,
462 wcd,
463 wcd->service_auth_uri,
464 wsse_security,
465 NULL);
466 failed = FALSE;
468 break;
471 case TOKEN_STATE_FEDERATION: {
472 /* WebTicket from ADFS for federated authentication */
473 gchar *wsse_security = generate_federation_wsse(raw);
475 if (wsse_security) {
477 SIPE_DEBUG_INFO("webticket_token: received valid SOAP message from ADFS %s",
478 uri);
480 if (sipe_svc_webticket_lmc_federated(sipe_private,
481 wcd->session,
482 wsse_security,
483 wcd->webticket_fedbearer_uri,
484 webticket_token,
485 wcd)) {
486 wcd->token_state = TOKEN_STATE_FED_BEARER;
488 /* callback data passed down the line */
489 wcd = NULL;
491 g_free(wsse_security);
493 break;
496 case TOKEN_STATE_FED_BEARER: {
497 /* WebTicket for federated authentication */
498 gchar *wsse_security = generate_fedbearer_wsse(raw);
500 if (wsse_security) {
502 SIPE_DEBUG_INFO("webticket_token: received valid SOAP message from service %s",
503 uri);
505 if (sipe_svc_webticket(sipe_private,
506 wcd->session,
507 wcd->webticket_fedbearer_uri,
508 wsse_security,
509 wcd->service_auth_uri,
510 &wcd->entropy,
511 webticket_token,
512 wcd)) {
513 wcd->token_state = TOKEN_STATE_SERVICE;
515 /* callback data passed down the line */
516 wcd = NULL;
518 g_free(wsse_security);
520 break;
523 /* end of: switch (wcd->token_state) { */
526 } else if (uri) {
527 /* Retry with federated authentication? */
528 if (wcd->webticket_fedbearer_uri && !wcd->tried_fedbearer) {
529 SIPE_DEBUG_INFO("webticket_token: anonymous authentication to service %s failed, retrying with federated authentication",
530 uri);
532 if (initiate_fedbearer(sipe_private, wcd)) {
533 /* callback data passed down the line */
534 wcd = NULL;
539 if (wcd) {
540 if (failed) {
541 gchar *failure_msg = NULL;
543 if (soap_body) {
544 failure_msg = sipe_xml_data(sipe_xml_child(soap_body,
545 "Body/Fault/Detail/error/internalerror/text"));
546 /* XML data can end in &#x000D;&#x000A; */
547 g_strstrip(failure_msg);
550 callback_execute(sipe_private,
551 wcd,
552 uri,
553 NULL,
554 failure_msg);
555 g_free(failure_msg);
557 callback_data_free(wcd);
561 static gboolean fedbearer_authentication(struct sipe_core_private *sipe_private,
562 struct webticket_callback_data *wcd)
564 struct sipe_webticket *webticket = sipe_private->webticket;
565 gboolean success;
567 if (webticket->webticket_adfs_uri) {
568 if ((success = sipe_svc_webticket_adfs(sipe_private,
569 wcd->session,
570 webticket->webticket_adfs_uri,
571 webticket_token,
572 wcd)))
573 wcd->token_state = TOKEN_STATE_FEDERATION;
574 } else {
575 if ((success = sipe_svc_webticket_lmc(sipe_private,
576 wcd->session,
577 wcd->webticket_fedbearer_uri,
578 webticket_token,
579 wcd)))
580 wcd->token_state = TOKEN_STATE_FED_BEARER;
583 /* If TRUE then callback data has been passed down the line */
584 return(success);
587 static void realminfo(struct sipe_core_private *sipe_private,
588 const gchar *uri,
589 SIPE_UNUSED_PARAMETER const gchar *raw,
590 sipe_xml *realminfo,
591 gpointer callback_data)
593 struct sipe_webticket *webticket = sipe_private->webticket;
594 struct webticket_callback_data *wcd = callback_data;
596 /* Only try retrieving of RealmInfo once */
597 webticket->retrieved_realminfo = TRUE;
599 if (realminfo) {
600 /* detect ADFS setup. See also:
602 * http://en.wikipedia.org/wiki/Active_Directory_Federation_Services
604 * NOTE: this is based on observed behaviour.
605 * It is unkown if this is documented somewhere...
607 SIPE_DEBUG_INFO("realminfo: data for user %s retrieved successfully",
608 sipe_private->username);
610 webticket->webticket_adfs_uri = sipe_xml_data(sipe_xml_child(realminfo,
611 "STSAuthURL"));
614 if (webticket->webticket_adfs_uri)
615 SIPE_DEBUG_INFO("realminfo: ADFS setup detected: %s",
616 webticket->webticket_adfs_uri);
617 else
618 SIPE_DEBUG_INFO_NOFORMAT("realminfo: no RealmInfo found or no ADFS setup detected - try direct login");
620 if (!fedbearer_authentication(sipe_private, wcd)) {
621 callback_execute(sipe_private,
622 wcd,
623 uri,
624 NULL,
625 NULL);
626 callback_data_free(wcd);
630 static gboolean initiate_fedbearer(struct sipe_core_private *sipe_private,
631 struct webticket_callback_data *wcd)
633 gboolean success;
635 if (sipe_private->webticket->retrieved_realminfo) {
636 /* skip retrieval and go to authentication */
637 success = fedbearer_authentication(sipe_private, wcd);
638 } else {
639 success = sipe_svc_realminfo(sipe_private,
640 wcd->session,
641 realminfo,
642 wcd);
645 wcd->tried_fedbearer = TRUE;
647 return(success);
650 static void webticket_metadata(struct sipe_core_private *sipe_private,
651 const gchar *uri,
652 SIPE_UNUSED_PARAMETER const gchar *raw,
653 sipe_xml *metadata,
654 gpointer callback_data)
656 struct webticket_callback_data *wcd = callback_data;
658 if (metadata) {
659 const sipe_xml *node;
661 SIPE_DEBUG_INFO("webticket_metadata: metadata for service %s retrieved successfully",
662 uri);
664 /* Authentication ports accepted by WebTicket Service */
665 for (node = sipe_xml_child(metadata, "service/port");
666 node;
667 node = sipe_xml_twin(node)) {
668 const gchar *auth_uri = sipe_xml_attribute(sipe_xml_child(node,
669 "address"),
670 "location");
672 if (auth_uri) {
673 if (sipe_strcase_equal(sipe_xml_attribute(node, "name"),
674 "WebTicketServiceWinNegotiate")) {
675 SIPE_DEBUG_INFO("webticket_metadata: WebTicket Windows Negotiate Auth URI %s", auth_uri);
676 g_free(wcd->webticket_negotiate_uri);
677 wcd->webticket_negotiate_uri = g_strdup(auth_uri);
678 } else if (sipe_strcase_equal(sipe_xml_attribute(node, "name"),
679 "WsFedBearer")) {
680 SIPE_DEBUG_INFO("webticket_metadata: WebTicket FedBearer Auth URI %s", auth_uri);
681 g_free(wcd->webticket_fedbearer_uri);
682 wcd->webticket_fedbearer_uri = g_strdup(auth_uri);
687 if (wcd->webticket_negotiate_uri || wcd->webticket_fedbearer_uri) {
688 gboolean success;
690 /* Entropy: 256 random bits */
691 if (!wcd->entropy.buffer)
692 sipe_tls_fill_random(&wcd->entropy, 256);
694 if (wcd->webticket_negotiate_uri) {
695 /* Try Negotiate authentication first */
697 success = sipe_svc_webticket(sipe_private,
698 wcd->session,
699 wcd->webticket_negotiate_uri,
700 NULL,
701 wcd->service_auth_uri,
702 &wcd->entropy,
703 webticket_token,
704 wcd);
705 wcd->token_state = TOKEN_STATE_SERVICE;
706 } else {
707 success = initiate_fedbearer(sipe_private,
708 wcd);
711 if (success) {
712 /* callback data passed down the line */
713 wcd = NULL;
718 if (wcd) {
719 callback_execute(sipe_private,
720 wcd,
721 uri,
722 NULL,
723 NULL);
724 callback_data_free(wcd);
728 static void service_metadata(struct sipe_core_private *sipe_private,
729 const gchar *uri,
730 SIPE_UNUSED_PARAMETER const gchar *raw,
731 sipe_xml *metadata,
732 gpointer callback_data)
734 struct webticket_callback_data *wcd = callback_data;
736 if (metadata) {
737 const sipe_xml *node;
738 gchar *policy = g_strdup_printf("%s_policy", wcd->service_port);
739 gchar *ticket_uri = NULL;
741 SIPE_DEBUG_INFO("webservice_metadata: metadata for service %s retrieved successfully",
742 uri);
744 /* WebTicket policies accepted by Web Service */
745 for (node = sipe_xml_child(metadata, "Policy");
746 node;
747 node = sipe_xml_twin(node)) {
748 if (sipe_strcase_equal(sipe_xml_attribute(node, "Id"),
749 policy)) {
751 SIPE_DEBUG_INFO_NOFORMAT("webservice_metadata: WebTicket policy found");
753 ticket_uri = sipe_xml_data(sipe_xml_child(node,
754 "ExactlyOne/All/EndorsingSupportingTokens/Policy/IssuedToken/Issuer/Address"));
755 if (ticket_uri) {
756 /* this token type requires signing */
757 wcd->requires_signing = TRUE;
758 } else {
759 /* try alternative token type */
760 ticket_uri = sipe_xml_data(sipe_xml_child(node,
761 "ExactlyOne/All/SignedSupportingTokens/Policy/IssuedToken/Issuer/Address"));
763 if (ticket_uri) {
764 SIPE_DEBUG_INFO("webservice_metadata: WebTicket URI %s", ticket_uri);
766 break;
769 g_free(policy);
771 if (ticket_uri) {
773 /* Authentication ports accepted by Web Service */
774 for (node = sipe_xml_child(metadata, "service/port");
775 node;
776 node = sipe_xml_twin(node)) {
777 if (sipe_strcase_equal(sipe_xml_attribute(node, "name"),
778 wcd->service_port)) {
779 const gchar *auth_uri;
781 SIPE_DEBUG_INFO_NOFORMAT("webservice_metadata: authentication port found");
783 auth_uri = sipe_xml_attribute(sipe_xml_child(node,
784 "address"),
785 "location");
786 if (auth_uri) {
787 SIPE_DEBUG_INFO("webservice_metadata: Auth URI %s", auth_uri);
789 if (sipe_svc_metadata(sipe_private,
790 wcd->session,
791 ticket_uri,
792 webticket_metadata,
793 wcd)) {
794 /* Remember for later */
795 wcd->service_auth_uri = g_strdup(auth_uri);
797 /* callback data passed down the line */
798 wcd = NULL;
801 break;
804 g_free(ticket_uri);
808 if (wcd) {
809 callback_execute(sipe_private,
810 wcd,
811 uri,
812 NULL,
813 NULL);
814 callback_data_free(wcd);
818 gboolean sipe_webticket_request(struct sipe_core_private *sipe_private,
819 struct sipe_svc_session *session,
820 const gchar *base_uri,
821 const gchar *port_name,
822 sipe_webticket_callback *callback,
823 gpointer callback_data)
825 const struct webticket_token *wt = cache_hit(sipe_private, base_uri);
826 gboolean ret;
828 /* cache hit for this URI? */
829 if (wt) {
830 SIPE_DEBUG_INFO("sipe_webticket_request: using cached token for URI %s (Auth URI %s)",
831 base_uri, wt->auth_uri);
832 callback(sipe_private,
833 base_uri,
834 wt->auth_uri,
835 wt->token,
836 NULL,
837 callback_data);
838 ret = TRUE;
839 } else {
840 GHashTable *pending = sipe_private->webticket->pending;
841 struct webticket_callback_data *wcd = g_hash_table_lookup(pending,
842 base_uri);
844 /* is there already a pending request for this URI? */
845 if (wcd) {
846 SIPE_DEBUG_INFO("sipe_webticket_request: pending request found for URI %s - queueing",
847 base_uri);
848 queue_request(wcd, callback, callback_data);
849 ret = TRUE;
850 } else {
851 wcd = g_new0(struct webticket_callback_data, 1);
853 ret = sipe_svc_metadata(sipe_private,
854 session,
855 base_uri,
856 service_metadata,
857 wcd);
859 if (ret) {
860 wcd->service_uri = g_strdup(base_uri);
861 wcd->service_port = port_name;
862 wcd->callback = callback;
863 wcd->callback_data = callback_data;
864 wcd->session = session;
865 wcd->token_state = TOKEN_STATE_NONE;
866 g_hash_table_insert(pending,
867 wcd->service_uri, /* borrowed */
868 wcd); /* borrowed */
869 } else {
870 g_free(wcd);
875 return(ret);
879 Local Variables:
880 mode: c
881 c-file-style: "bsd"
882 indent-tabs-mode: t
883 tab-width: 8
884 End: