From bfff95502c3b36ce132fa4bad76a1bf5e980c4c4 Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Tue, 13 Mar 2012 21:49:07 +0200 Subject: [PATCH] svc: add HTTP session handling Microsoft seems to have enabled server load balancing on Office365. Compared to the logs taken at the end of last year, the new logs now show that the server responses contain HTTP Set-Cookie: headers. We need to store the cookie and send it in all related SOAP requests so that the same server processes them. The highest layer, i.e. Certificate or MS-DLX, must now allocate a session which will be re-used in all requests. --- src/core/sipe-buddy.c | 6 ++++++ src/core/sipe-certificate.c | 51 ++++++++++++++++++++++++++++++++------------- src/core/sipe-svc.c | 38 +++++++++++++++++++++++++++++++-- src/core/sipe-svc.h | 22 ++++++++++++++++++- src/core/sipe-webticket.c | 12 ++++++++++- src/core/sipe-webticket.h | 4 +++- 6 files changed, 114 insertions(+), 19 deletions(-) diff --git a/src/core/sipe-buddy.c b/src/core/sipe-buddy.c index 01eef136..c5b4ca32 100644 --- a/src/core/sipe-buddy.c +++ b/src/core/sipe-buddy.c @@ -412,6 +412,7 @@ struct ms_dlx_data { gchar *other; guint max_returns; sipe_svc_callback *callback; + struct sipe_svc_session *session; /* must call ms_dlx_free() */ void (*failed_callback)(struct sipe_core_private *sipe_private, struct ms_dlx_data *mdd); @@ -425,6 +426,7 @@ static void ms_dlx_free(struct ms_dlx_data *mdd) entry = entry->next; } g_slist_free(mdd->search_rows); + sipe_svc_session_close(mdd->session); g_free(mdd->other); g_free(mdd); } @@ -484,6 +486,7 @@ static void ms_dlx_webticket(struct sipe_core_private *sipe_private, base_uri); if (sipe_svc_ab_entry_request(sipe_private, + mdd->session, auth_uri, wsse_security, query, @@ -510,6 +513,7 @@ static void ms_dlx_webticket_request(struct sipe_core_private *sipe_private, struct ms_dlx_data *mdd) { if (!sipe_webticket_request(sipe_private, + mdd->session, sipe_private->dlx_uri, "AddressBookWebTicketBearer", ms_dlx_webticket, @@ -782,6 +786,7 @@ void sipe_core_buddy_search(struct sipe_core_public *sipe_public, mdd->max_returns = 100; mdd->callback = search_ab_entry_response; mdd->failed_callback = search_ab_entry_failed; + mdd->session = sipe_svc_session_start(); ms_dlx_webticket_request(SIPE_CORE_PRIVATE, mdd); @@ -1136,6 +1141,7 @@ void sipe_core_buddy_get_info(struct sipe_core_public *sipe_public, mdd->max_returns = 1; mdd->callback = get_info_ab_entry_response; mdd->failed_callback = get_info_ab_entry_failed; + mdd->session = sipe_svc_session_start(); ms_dlx_webticket_request(sipe_private, mdd); diff --git a/src/core/sipe-certificate.c b/src/core/sipe-certificate.c index 71182808..3b7ea3f1 100644 --- a/src/core/sipe-certificate.c +++ b/src/core/sipe-certificate.c @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2011 SIPE Project + * Copyright (C) 2011-12 SIPE Project * * * This program is free software; you can redistribute it and/or modify @@ -54,6 +54,20 @@ struct sipe_certificate { struct sipe_cert_crypto *backend; }; +struct certificate_callback_data { + gchar *target; + struct sipe_svc_session *session; +}; + +static void callback_data_free(struct certificate_callback_data *ccd) +{ + if (ccd) { + sipe_svc_session_close(ccd->session); + g_free(ccd->target); + g_free(ccd); + } +} + void sipe_certificate_free(struct sipe_core_private *sipe_private) { struct sipe_certificate *sc = sipe_private->certificate; @@ -175,7 +189,7 @@ static void get_and_publish_cert(struct sipe_core_private *sipe_private, sipe_xml *soap_body, gpointer callback_data) { - gchar *target = callback_data; + struct certificate_callback_data *ccd = callback_data; gboolean success = (uri == NULL); /* abort case */ if (soap_body) { @@ -193,10 +207,10 @@ static void get_and_publish_cert(struct sipe_core_private *sipe_private, if (opaque) { add_certificate(sipe_private, - target, + ccd->target, opaque); SIPE_DEBUG_INFO("get_and_publish_cert: certificate for target '%s' added", - target); + ccd->target); /* Let's try this again... */ sip_transport_authentication_completed(sipe_private); @@ -214,7 +228,7 @@ static void get_and_publish_cert(struct sipe_core_private *sipe_private, uri); } - g_free(target); + callback_data_free(ccd); } static void certprov_webticket(struct sipe_core_private *sipe_private, @@ -223,7 +237,7 @@ static void certprov_webticket(struct sipe_core_private *sipe_private, const gchar *wsse_security, gpointer callback_data) { - gchar *target = callback_data; + struct certificate_callback_data *ccd = callback_data; if (wsse_security) { /* Got a Web Ticket for Certificate Provisioning Service */ @@ -238,18 +252,19 @@ static void certprov_webticket(struct sipe_core_private *sipe_private, SIPE_DEBUG_INFO_NOFORMAT("certprov_webticket: created certificate request"); if (sipe_svc_get_and_publish_cert(sipe_private, + ccd->session, auth_uri, wsse_security, certreq_base64, get_and_publish_cert, - target)) + ccd)) /* callback data passed down the line */ - target = NULL; + ccd = NULL; g_free(certreq_base64); } - if (target) { + if (ccd) { certificate_failure(sipe_private, _("Certificate request to %s failed"), base_uri); @@ -261,23 +276,31 @@ static void certprov_webticket(struct sipe_core_private *sipe_private, base_uri); } - g_free(target); + if (ccd) + callback_data_free(ccd); } gboolean sipe_certificate_tls_dsk_generate(struct sipe_core_private *sipe_private, const gchar *target, const gchar *uri) { - gchar *tmp = g_strdup(target); + struct certificate_callback_data *ccd = g_new0(struct certificate_callback_data, 1); gboolean ret; + ccd->session = sipe_svc_session_start(); + ret = sipe_webticket_request(sipe_private, + ccd->session, uri, "CertProvisioningServiceWebTicketProof_SHA1", certprov_webticket, - tmp); - if (!ret) - g_free(tmp); + ccd); + if (ret) { + ccd->target = g_strdup(target); + + } else { + callback_data_free(ccd); + } return(ret); } diff --git a/src/core/sipe-svc.c b/src/core/sipe-svc.c index e68ae8a2..0648c42b 100644 --- a/src/core/sipe-svc.c +++ b/src/core/sipe-svc.c @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2011 SIPE Project + * Copyright (C) 2011-12 SIPE Project * * * This program is free software; you can redistribute it and/or modify @@ -66,6 +66,10 @@ struct sipe_svc { GSList *pending_requests; }; +struct sipe_svc_session { + HttpSession *session; +}; + static void sipe_svc_request_free(struct svc_request *data) { if (data->conn) @@ -105,6 +109,21 @@ static void sipe_svc_init(struct sipe_core_private *sipe_private) sipe_private->svc = g_new0(struct sipe_svc, 1); } +struct sipe_svc_session *sipe_svc_session_start(void) +{ + struct sipe_svc_session *session = g_new0(struct sipe_svc_session, 1); + session->session = http_conn_session_create(); + return(session); +} + +void sipe_svc_session_close(struct sipe_svc_session *session) +{ + if (session) { + http_conn_session_free(session->session); + g_free(session); + } +} + static void sipe_svc_https_response(int return_code, const gchar *body, SIPE_UNUSED_PARAMETER const gchar *content_type, @@ -138,6 +157,7 @@ static void sipe_svc_https_response(int return_code, static gboolean sipe_svc_https_request(struct sipe_core_private *sipe_private, const gchar *method, + struct sipe_svc_session *session, const gchar *uri, const gchar *content_type, const gchar *soap_action, @@ -162,7 +182,7 @@ static gboolean sipe_svc_https_request(struct sipe_core_private *sipe_private, data->auth.password = sipe_private->password; data->conn = http_conn_create(SIPE_CORE_PUBLIC, - NULL, /* HttpSession */ + session->session, method, HTTP_CONN_SSL, HTTP_CONN_NO_REDIRECT, @@ -191,6 +211,7 @@ static gboolean sipe_svc_https_request(struct sipe_core_private *sipe_private, } static gboolean sipe_svc_wsdl_request(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *uri, const gchar *additional_ns, const gchar *soap_action, @@ -231,6 +252,7 @@ static gboolean sipe_svc_wsdl_request(struct sipe_core_private *sipe_private, gboolean ret = sipe_svc_https_request(sipe_private, HTTP_CONN_POST, + session, uri, "text/xml", soap_action, @@ -245,6 +267,7 @@ static gboolean sipe_svc_wsdl_request(struct sipe_core_private *sipe_private, } static gboolean new_soap_req(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *uri, const gchar *soap_action, const gchar *wsse_security, @@ -254,6 +277,7 @@ static gboolean new_soap_req(struct sipe_core_private *sipe_private, gpointer callback_data) { return(sipe_svc_wsdl_request(sipe_private, + session, uri, "xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" " "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " @@ -280,6 +304,7 @@ static void sipe_svc_wsdl_response(struct svc_request *data, } gboolean sipe_svc_get_and_publish_cert(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *uri, const gchar *wsse_security, const gchar *certreq, @@ -325,6 +350,7 @@ gboolean sipe_svc_get_and_publish_cert(struct sipe_core_private *sipe_private, g_free(uuid); ret = new_soap_req(sipe_private, + session, uri, "http://schemas.microsoft.com/OCS/AuthWebServices/GetAndPublishCert", wsse_security, @@ -338,6 +364,7 @@ gboolean sipe_svc_get_and_publish_cert(struct sipe_core_private *sipe_private, } gboolean sipe_svc_ab_entry_request(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *uri, const gchar *wsse_security, const gchar *search, @@ -368,6 +395,7 @@ gboolean sipe_svc_ab_entry_request(struct sipe_core_private *sipe_private, max_returns); ret = new_soap_req(sipe_private, + session, uri, "DistributionListExpander/IAddressBook/SearchAbEntry", wsse_security, @@ -389,6 +417,7 @@ gboolean sipe_svc_ab_entry_request(struct sipe_core_private *sipe_private, * I guess we'll have to see what happens in real life... */ gboolean sipe_svc_webticket_lmc(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *service_uri, sipe_svc_callback *callback, gpointer callback_data) @@ -414,6 +443,7 @@ gboolean sipe_svc_webticket_lmc(struct sipe_core_private *sipe_private, service_uri); gboolean ret = sipe_svc_wsdl_request(sipe_private, + session, "https://login.microsoftonline.com:443/RST2.srf", "xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" " "xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" " @@ -431,6 +461,7 @@ gboolean sipe_svc_webticket_lmc(struct sipe_core_private *sipe_private, } gboolean sipe_svc_webticket(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *uri, const gchar *wsse_security, const gchar *service_uri, @@ -465,6 +496,7 @@ gboolean sipe_svc_webticket(struct sipe_core_private *sipe_private, secret); gboolean ret = new_soap_req(sipe_private, + session, uri, "http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue", wsse_security, @@ -494,6 +526,7 @@ static void sipe_svc_metadata_response(struct svc_request *data, } gboolean sipe_svc_metadata(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *uri, sipe_svc_callback *callback, gpointer callback_data) @@ -501,6 +534,7 @@ gboolean sipe_svc_metadata(struct sipe_core_private *sipe_private, gchar *mex_uri = g_strdup_printf("%s/mex", uri); gboolean ret = sipe_svc_https_request(sipe_private, HTTP_CONN_GET, + session, mex_uri, "text", NULL, diff --git a/src/core/sipe-svc.h b/src/core/sipe-svc.h index 83421e68..e1b08ea1 100644 --- a/src/core/sipe-svc.h +++ b/src/core/sipe-svc.h @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2011 SIPE Project + * Copyright (C) 2011-12 SIPE Project * * * This program is free software; you can redistribute it and/or modify @@ -29,6 +29,7 @@ /* Forward declarations */ struct sipe_core_private; +struct sipe_svc_session; struct sipe_tls_random; struct _sipe_xml; @@ -48,6 +49,20 @@ typedef void (sipe_svc_callback)(struct sipe_core_private *sipe_private, gpointer callback_data); /** + * Start a session of related service requests + * + * @return Opaque session pointer + */ +struct sipe_svc_session *sipe_svc_session_start(void); + +/** + * Close a session of related service requests + * + * @param session Opaque session pointer + */ +void sipe_svc_session_close(struct sipe_svc_session *session); + +/** * Trigger fetch of Get & Publish certificate * * @param sipe_private SIPE core private data @@ -59,6 +74,7 @@ typedef void (sipe_svc_callback)(struct sipe_core_private *sipe_private, * @return @c TRUE if certificate fetch was triggered */ gboolean sipe_svc_get_and_publish_cert(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *uri, const gchar *wsse_security, const gchar *certreq, @@ -79,6 +95,7 @@ gboolean sipe_svc_get_and_publish_cert(struct sipe_core_private *sipe_private, * @return @c TRUE if search was triggered */ gboolean sipe_svc_ab_entry_request(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *uri, const gchar *wsse_security, const gchar *search, @@ -100,6 +117,7 @@ gboolean sipe_svc_ab_entry_request(struct sipe_core_private *sipe_private, * @return @c TRUE if token fetch was triggered */ gboolean sipe_svc_webticket(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *uri, const gchar *wsse_security, const gchar *service_uri, @@ -117,6 +135,7 @@ gboolean sipe_svc_webticket(struct sipe_core_private *sipe_private, * @return @c TRUE if token fetch was triggered */ gboolean sipe_svc_webticket_lmc(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *service_uri, sipe_svc_callback *callback, gpointer callback_data); @@ -131,6 +150,7 @@ gboolean sipe_svc_webticket_lmc(struct sipe_core_private *sipe_private, * @return @c TRUE if metadata fetch was triggered */ gboolean sipe_svc_metadata(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *uri, sipe_svc_callback *callback, gpointer callback_data); diff --git a/src/core/sipe-webticket.c b/src/core/sipe-webticket.c index 0c3c4567..4e157478 100644 --- a/src/core/sipe-webticket.c +++ b/src/core/sipe-webticket.c @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2011 SIPE Project + * Copyright (C) 2011-12 SIPE Project * * * This program is free software; you can redistribute it and/or modify @@ -59,6 +59,8 @@ struct webticket_callback_data { sipe_webticket_callback *callback; gpointer callback_data; + + struct sipe_svc_session *session; }; static void callback_data_free(struct webticket_callback_data *wcd) @@ -305,6 +307,7 @@ static void webticket_token(struct sipe_core_private *sipe_private, uri); if (sipe_svc_webticket(sipe_private, + wcd->session, wcd->webticket_fedbearer_uri, wsse_security, wcd->service_auth_uri, @@ -328,6 +331,7 @@ static void webticket_token(struct sipe_core_private *sipe_private, wcd->tried_fedbearer = TRUE; if (sipe_svc_webticket_lmc(sipe_private, + wcd->session, wcd->webticket_fedbearer_uri, webticket_token, wcd)) { @@ -399,6 +403,7 @@ static void webticket_metadata(struct sipe_core_private *sipe_private, /* Try Negotiate authentication first */ success = sipe_svc_webticket(sipe_private, + wcd->session, wcd->webticket_negotiate_uri, NULL, wcd->service_auth_uri, @@ -409,6 +414,7 @@ static void webticket_metadata(struct sipe_core_private *sipe_private, } else { wcd->tried_fedbearer = TRUE; success = sipe_svc_webticket_lmc(sipe_private, + wcd->session, wcd->webticket_fedbearer_uri, webticket_token, wcd); @@ -494,6 +500,7 @@ static void service_metadata(struct sipe_core_private *sipe_private, SIPE_DEBUG_INFO("webservice_metadata: Auth URI %s", auth_uri); if (sipe_svc_metadata(sipe_private, + wcd->session, ticket_uri, webticket_metadata, wcd)) { @@ -522,6 +529,7 @@ static void service_metadata(struct sipe_core_private *sipe_private, } gboolean sipe_webticket_request(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *base_uri, const gchar *port_name, sipe_webticket_callback *callback, @@ -529,6 +537,7 @@ gboolean sipe_webticket_request(struct sipe_core_private *sipe_private, { 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); @@ -538,6 +547,7 @@ gboolean sipe_webticket_request(struct sipe_core_private *sipe_private, wcd->service_port = port_name; wcd->callback = callback; wcd->callback_data = callback_data; + wcd->session = session; } else { g_free(wcd); } diff --git a/src/core/sipe-webticket.h b/src/core/sipe-webticket.h index 0f92a1a4..ad627be8 100644 --- a/src/core/sipe-webticket.h +++ b/src/core/sipe-webticket.h @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2011 SIPE Project + * Copyright (C) 2011-12 SIPE Project * * * This program is free software; you can redistribute it and/or modify @@ -29,6 +29,7 @@ /* Forward declarations */ struct sipe_core_private; +struct sipe_svc_session; /** * Web Ticket callback @@ -56,6 +57,7 @@ typedef void (sipe_webticket_callback)(struct sipe_core_private *sipe_private, * @return @c TRUE if web ticket fetch was triggered */ gboolean sipe_webticket_request(struct sipe_core_private *sipe_private, + struct sipe_svc_session *session, const gchar *base_uri, const gchar *port_name, sipe_webticket_callback *callback, -- 2.11.4.GIT