cpw.qulogic.msn: 74d8e44e: Finally got MSN token updating working (...

qulogic at pidgin.im qulogic at pidgin.im
Sun Jun 15 04:26:03 EDT 2008


-----------------------------------------------------------------
Revision: 74d8e44ec0c60b1e362ada585e3b24dd17f404bd
Ancestor: c8ee1c4be39bd910d6ff74766ff5995a12ce0ab7
Author: qulogic at pidgin.im
Date: 2008-06-15T06:22:25
Branch: im.pidgin.cpw.qulogic.msn
URL: http://d.pidgin.im/viewmtn/revision/info/74d8e44ec0c60b1e362ada585e3b24dd17f404bd

Modified files:
        libpurple/protocols/msn/nexus.c
        libpurple/protocols/msn/nexus.h

ChangeLog: 

Finally got MSN token updating working (I think).

So it seems after creating the signature, the xmlnode_to_str must have
added some xmlns attributes which were sent to the server. I thought that 
CanonicalizationMethod stuff the XML specified meant the server would 
normalize everything nicely, but apparently not.

I added the xmlns to the XML string before creating the signature and 
it looks like things work now. It just needs a full 8-hour test to be 
certain.

Did a bit of re-factoring to the token response parsing, as well. It 
should now fail the first time something shows up that isn't expected, 
or if something is missing, instead of blindly going forward with half 
the tokens we requested.

References #4875.


-------------- next part --------------
============================================================
--- libpurple/protocols/msn/nexus.c	0fc81f23bf6f0be33db2235462d430206ad4383b
+++ libpurple/protocols/msn/nexus.c	b6c25ad1732442ea5dfbd8e8451b3837e6bb5ac8
@@ -239,31 +239,70 @@ struct _MsnNexusUpdateData {
 	gpointer data;
 };
 
-static void
-save_tokens(GHashTable *table, const char *str)
+static gboolean
+nexus_parse_token(MsnNexus *nexus, int id, xmlnode *node)
 {
+	char *token_str, *expiry_str;
+	const char *id_str;
 	char **elems, **cur, **tokens;
+	xmlnode *token = xmlnode_get_child(node, "RequestedSecurityToken/BinarySecurityToken");
+	xmlnode *secret = xmlnode_get_child(node, "RequestedProofToken/BinarySecret");
+	xmlnode *expires = xmlnode_get_child(node, "LifeTime/Expires");
 
-	elems = g_strsplit(str, "&", 0);
+	if (!token)
+		return FALSE;
 
+	/* Use the ID that the server sent us */
+	if (id == -1) {
+		id_str = xmlnode_get_attrib(token, "Id");
+		if (id_str == NULL)
+			return FALSE;
+
+		id = atol(id_str + 7) - 1;	/* 'Compact#' or 'PPToken#' */
+		if (id >= nexus->token_len)
+			return FALSE;	/* Where did this come from? */
+	}
+
+	token_str = xmlnode_get_data(token);
+	if (token_str == NULL)
+		return FALSE;
+
+	elems = g_strsplit(token_str, "&", 0);
+
 	for (cur = elems; *cur != NULL; cur++) {
 		tokens = g_strsplit(*cur, "=", 2);
-		g_hash_table_insert(table, tokens[0], tokens[1]);
+		g_hash_table_insert(nexus->tokens[id].token, tokens[0], tokens[1]);
 		/* Don't free each of the tokens, only the array. */
 		g_free(tokens);
 	}
 	g_strfreev(elems);
+	g_free(token_str);
+
+	if (secret)
+		nexus->tokens[id].secret = xmlnode_get_data(secret);
+	else
+		nexus->tokens[id].secret = NULL;
+
+	/* Yay for MS using ISO-8601 */
+	expiry_str = xmlnode_get_data(expires);
+	nexus->tokens[id].expiry = purple_str_to_time(expiry_str,
+		FALSE, NULL, NULL, NULL);
+	g_free(expiry_str);
+
+	purple_debug_info("msnp15", "Updated ticket for domain '%s', expires at %" G_GINT64_FORMAT ".\n",
+	                  ticket_domains[id][SSO_VALID_TICKET_DOMAIN],
+	                  (gint64)nexus->tokens[id].expiry);
+	return TRUE;
 }
 
 static gboolean
-nexus_parse_response(MsnNexus *nexus, int id, xmlnode *xml)
+nexus_parse_response(MsnNexus *nexus, xmlnode *xml)
 {
 	xmlnode *node;
 	xmlnode *cipher;
 	xmlnode *secret;
 	char *data;
-	gboolean result = FALSE;
-	gboolean parse_all = (id == -1);
+	gboolean result;
 
 	node = xmlnode_get_child(xml, "Body/RequestSecurityTokenResponseCollection/RequestSecurityTokenResponse");
 
@@ -278,47 +317,10 @@ nexus_parse_response(MsnNexus *nexus, in
 	nexus->secret = (char *)purple_base64_decode(data, NULL);
 	g_free(data);
 
-	for (node = node->next; node; node = node->next) {
-		xmlnode *token = xmlnode_get_child(node, "RequestedSecurityToken/BinarySecurityToken");
-		xmlnode *secret = xmlnode_get_child(node, "RequestedProofToken/BinarySecret");
-		xmlnode *expires = xmlnode_get_child(node, "LifeTime/Expires");
+	result = TRUE;
+	for (node = node->next; node && result; node = node->next)
+		result = nexus_parse_token(nexus, -1, node);
 
-		if (token) {
-			char *token_str, *expiry_str;
-			const char *id_str = xmlnode_get_attrib(token, "Id");
-
-			if (id_str == NULL) continue;
-
-			if (parse_all)
-				id = atol(id_str + 7) - 1;	/* 'Compact#' or 'PPToken#' */
-			if (id >= nexus->token_len)
-				continue;	/* Where did this come from? */
-
-			token_str = xmlnode_get_data(token);
-			if (token_str == NULL) continue;
-
-			save_tokens(nexus->tokens[id].token, token_str);
-			g_free(token_str);
-
-			if (secret)
-				nexus->tokens[id].secret = xmlnode_get_data(secret);
-			else
-				nexus->tokens[id].secret = NULL;
-
-			/* Yay for MS using ISO-8601 */
-			expiry_str = xmlnode_get_data(expires);
-
-			nexus->tokens[id].expiry = purple_str_to_time(expiry_str,
-				FALSE, NULL, NULL, NULL);
-
-			g_free(expiry_str);
-
-			purple_debug_info("msnp15", "Updated ticket for domain '%s'\n",
-			                  ticket_domains[id][SSO_VALID_TICKET_DOMAIN]);
-			result = TRUE;
-		}
-	}
-
 	return result;
 }
 
@@ -335,7 +337,7 @@ nexus_got_response_cb(MsnSoapMessage *re
 		return;
 	}
 
-	if (!nexus_parse_response(nexus, -1, resp->xml)) {
+	if (!nexus_parse_response(nexus, resp->xml)) {
 		msn_session_set_error(session, MSN_ERROR_SERVCONN, _("Windows Live ID authentication:Invalid response"));
 		return;
 	}
@@ -400,7 +402,9 @@ nexus_got_update_cb(MsnSoapMessage *req,
 	gsize len;
 	char *key;
 
+#if 0
 	char *decrypted_pp;
+#endif
 	char *decrypted_data;
 
 	purple_debug_info("msnp15", "Got Update Response for %s.\n", ticket_domains[ud->id][SSO_VALID_TICKET_DOMAIN]);
@@ -422,31 +426,34 @@ nexus_got_update_cb(MsnSoapMessage *req,
 	g_free(tmp);
 	g_free(nonce);
 
+#if 0
+	/* Don't know what this is for yet */
 	tmp = xmlnode_get_data(xmlnode_get_child(resp->xml,
 		"Header/EncryptedPP/EncryptedData/CipherData/CipherValue"));
 	if (tmp) {
-		/* Don't know what this is for yet */
 		decrypted_pp = des3_cbc(key, iv, tmp, len, TRUE);
 		g_free(tmp);
 		purple_debug_info("msnp15", "Got Response Header EncryptedPP: %s\n", decrypted_pp);
 		g_free(decrypted_pp);
 	}
+#endif
 
 	tmp = xmlnode_get_data(xmlnode_get_child(resp->xml,
 		"Body/EncryptedData/CipherData/CipherValue"));
 	if (tmp) {
 		char *unescaped;
 		xmlnode *rstresponse;
+
 		unescaped = (char *)purple_base64_decode(tmp, &len);
 		g_free(tmp);
+
 		decrypted_data = des3_cbc(key, iv, unescaped, len, TRUE);
 		g_free(unescaped);
+		purple_debug_info("msnp15", "Got Response Body EncryptedData: %s\n", decrypted_data);
+
 		rstresponse = xmlnode_from_str(decrypted_data, -1);
 		g_hash_table_remove_all(nexus->tokens[ud->id].token);
-		save_tokens(nexus->tokens[ud->id].token,
-			xmlnode_get_data(xmlnode_get_child(rstresponse,
-				"RequestSecurityTokenResponse/RequestedSecurityToken/BinarySecurityToken")));
-		purple_debug_info("msnp15", "Got Response Body EncryptedData: %s\n", decrypted_data);
+		nexus_parse_token(nexus, ud->id, rstresponse);
 		g_free(decrypted_data);
 	}
 
@@ -501,7 +508,7 @@ msn_nexus_update_token(MsnNexus *nexus, 
 	sha1 = purple_cipher_context_new_by_name("sha1", NULL);
 
 	domain = g_strdup_printf(MSN_SSO_RST_TEMPLATE,
-	                         0,
+	                         id,
 	                         ticket_domains[id][SSO_VALID_TICKET_DOMAIN],
 	                         ticket_domains[id][SSO_VALID_TICKET_POLICY] != NULL ?
 	                             ticket_domains[id][SSO_VALID_TICKET_POLICY] :
@@ -527,6 +534,7 @@ msn_nexus_update_token(MsnNexus *nexus, 
 	purple_cipher_context_destroy(sha1);
 
 	signedinfo = g_strdup_printf(MSN_SSO_SIGNEDINFO_TEMPLATE,
+	                             id,
 	                             domain_b64,
 	                             timestamp_b64);
 
============================================================
--- libpurple/protocols/msn/nexus.h	f31747d07e80c34723ddf013669777e59e3d1a70
+++ libpurple/protocols/msn/nexus.h	c015938cf1c2a2103d878f909c550e0b6661c397
@@ -42,14 +42,14 @@ typedef enum
 #define SSO_POST_URL	"/RST.srf"
 
 #define MSN_SSO_RST_TEMPLATE \
-"<wst:RequestSecurityToken Id=\"RST%d\">"\
+"<wst:RequestSecurityToken xmlns=\"http://schemas.xmlsoap.org/ws/2004/04/trust\" Id=\"RST%d\">"\
 	"<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\
-	"<wsp:AppliesTo>"\
-		"<wsa:EndpointReference>"\
+	"<wsp:AppliesTo xmlns=\"http://schemas.xmlsoap.org/ws/2002/12/policy\">"\
+		"<wsa:EndpointReference xmlns=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\">"\
 			"<wsa:Address>%s</wsa:Address>"\
 		"</wsa:EndpointReference>"\
 	"</wsp:AppliesTo>"\
-	"<wsse:PolicyReference URI=\"%s\"></wsse:PolicyReference>"\
+	"<wsse:PolicyReference xmlns=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" URI=\"%s\"></wsse:PolicyReference>"\
 "</wst:RequestSecurityToken>"
 
 #define MSN_SSO_TEMPLATE "<?xml version='1.0' encoding='utf-8'?>"\
@@ -107,7 +107,7 @@ typedef enum
 #define MSN_SSO_AUTHINFO_SHA1_BASE64 "d2IeTF4DAkPEa/tVETHznsivEpc="
 
 #define MSN_SSO_TIMESTAMP_TEMPLATE \
-"<wsu:Timestamp Id=\"Timestamp\">"\
+"<wsu:Timestamp xmlns=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" Id=\"Timestamp\">"\
 	"<wsu:Created>%s</wsu:Created>"\
 	"<wsu:Expires>%s</wsu:Expires>"\
 "</wsu:Timestamp>"
@@ -116,7 +116,7 @@ typedef enum
 "<SignedInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">"\
 	"<CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></CanonicalizationMethod>"\
 	"<SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#hmac-sha1\"></SignatureMethod>"\
-	"<Reference URI=\"#RST0\">"\
+	"<Reference URI=\"#RST%d\">"\
 		"<Transforms>"\
 			"<Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></Transform>"\
 		"</Transforms>"\


More information about the Commits mailing list