libsoup r1059 - in trunk: . libsoup tests



Author: danw
Date: Mon Jan 28 17:55:06 2008
New Revision: 1059
URL: http://svn.gnome.org/viewvc/libsoup?rev=1059&view=rev

Log:
	* libsoup/soup-message.c (soup_message_set_auth)
	(soup_message_set_proxy_auth): Use soup_message_headers_replace(),
	not soup_message_headers_append(), since only a single
	Authorization/Proxy-Authorization header is allowed. #512517.

	* libsoup/soup-auth-manager-ntlm.c (ntlm_request_started): Don't
	set an NTLM Authorization header if the message already has a
	Basic or Digest one.

	* tests/ntlm-test.c: Add some Basic auth and mixed NTLM/Basic auth
	tests


Modified:
   trunk/ChangeLog
   trunk/libsoup/soup-auth-manager-ntlm.c
   trunk/libsoup/soup-message.c
   trunk/tests/ntlm-test.c

Modified: trunk/libsoup/soup-auth-manager-ntlm.c
==============================================================================
--- trunk/libsoup/soup-auth-manager-ntlm.c	(original)
+++ trunk/libsoup/soup-auth-manager-ntlm.c	Mon Jan 28 17:55:06 2008
@@ -16,6 +16,7 @@
 #include "soup-auth-manager-ntlm.h"
 #include "soup-auth-ntlm.h"
 #include "soup-message.h"
+#include "soup-message-private.h"
 #include "soup-misc.h"
 #include "soup-session.h"
 #include "soup-session-private.h"
@@ -286,7 +287,7 @@
 		break;
 	}
 
-	if (header) {
+	if (header && !soup_message_get_auth (msg)) {
 		soup_message_headers_replace (msg->request_headers,
 					      "Authorization", header);
 		g_free (header);

Modified: trunk/libsoup/soup-message.c
==============================================================================
--- trunk/libsoup/soup-message.c	(original)
+++ trunk/libsoup/soup-message.c	Mon Jan 28 17:55:06 2008
@@ -925,8 +925,8 @@
 
 	g_object_ref (priv->auth);
 	token = soup_auth_get_authorization (auth, msg);
-	soup_message_headers_append (msg->request_headers,
-				     "Authorization", token);
+	soup_message_headers_replace (msg->request_headers,
+				      "Authorization", token);
 	g_free (token);
 }
 
@@ -979,8 +979,8 @@
 
 	g_object_ref (priv->proxy_auth);
 	token = soup_auth_get_authorization (auth, msg);
-	soup_message_headers_append (msg->request_headers,
-				     "Proxy-Authorization", token);
+	soup_message_headers_replace (msg->request_headers,
+				      "Proxy-Authorization", token);
 	g_free (token);
 }
 

Modified: trunk/tests/ntlm-test.c
==============================================================================
--- trunk/tests/ntlm-test.c	(original)
+++ trunk/tests/ntlm-test.c	Mon Jan 28 17:55:06 2008
@@ -46,51 +46,100 @@
 #define NTLM_RESPONSE_USER(response) ((response)[87] == 'h' ? NTLM_AUTHENTICATED_ALICE : NTLM_AUTHENTICATED_BOB)
 
 static void
+clear_state (gpointer connections, GObject *ex_connection)
+{
+	g_hash_table_remove (connections, ex_connection);
+}
+
+static void
 server_callback (SoupServer *server, SoupMessage *msg,
 		 const char *path, GHashTable *query,
 		 SoupClientContext *client, gpointer data)
 {
 	GHashTable *connections = data;
+	SoupSocket *socket;
 	const char *auth;
-	NTLMServerState state, required_user;
-	gboolean not_found = FALSE;
+	NTLMServerState state, required_user = 0;
+	gboolean auth_required = FALSE, not_found = FALSE;
+	gboolean basic_allowed = FALSE, ntlm_allowed = FALSE;
 
 	if (msg->method != SOUP_METHOD_GET) {
 		soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
 		return;
 	}
 
-	if (!strcmp (path, "/noauth"))
-		required_user = 0;
-	else if (!strncmp (path, "/alice", 6))
+	if (!strncmp (path, "/alice", 6)) {
+		auth_required = TRUE;
+		ntlm_allowed = TRUE;
 		required_user = NTLM_AUTHENTICATED_ALICE;
-	else if (!strncmp (path, "/bob", 4))
+	} else if (!strncmp (path, "/bob", 4)) {
+		auth_required = TRUE;
+		ntlm_allowed = TRUE;
 		required_user = NTLM_AUTHENTICATED_BOB;
+	} else if (!strncmp (path, "/either", 7)) {
+		auth_required = TRUE;
+		ntlm_allowed = basic_allowed = TRUE;
+	} else if (!strncmp (path, "/basic", 6)) {
+		auth_required = TRUE;
+		basic_allowed = TRUE;
+	}
+
 	if (strstr (path, "/404"))
 		not_found = TRUE;
 
-	state = GPOINTER_TO_INT (g_hash_table_lookup (connections, soup_client_context_get_socket (client)));
+	socket = soup_client_context_get_socket (client);
+	state = GPOINTER_TO_INT (g_hash_table_lookup (connections, socket));
 	auth = soup_message_headers_get (msg->request_headers, "Authorization");
 
-	if (auth && !strncmp (auth, "NTLM ", 5)) {
-		if (!strncmp (auth + 5, NTLM_REQUEST_START,
-			      strlen (NTLM_REQUEST_START)))
-			state = NTLM_RECEIVED_REQUEST;
-		else if (state == NTLM_SENT_CHALLENGE &&
-			 !strncmp (auth + 5, NTLM_RESPONSE_START,
-				   strlen (NTLM_RESPONSE_START)))
-			state = NTLM_RESPONSE_USER (auth + 5);
-		else
-			state = NTLM_UNAUTHENTICATED;
+	if (auth) {
+		if (!strncmp (auth, "NTLM ", 5)) {
+			if (!strncmp (auth + 5, NTLM_REQUEST_START,
+				      strlen (NTLM_REQUEST_START))) {
+				state = NTLM_RECEIVED_REQUEST;
+				/* If they start, they must finish */
+				auth_required = ntlm_allowed = TRUE;
+				basic_allowed = FALSE;
+			} else if (state == NTLM_SENT_CHALLENGE &&
+				   !strncmp (auth + 5, NTLM_RESPONSE_START,
+					     strlen (NTLM_RESPONSE_START))) {
+				state = NTLM_RESPONSE_USER (auth + 5);
+			} else
+				state = NTLM_UNAUTHENTICATED;
+		} else if (!strncmp (auth, "Basic ", 6) && basic_allowed) {
+			gsize len;
+			char *decoded = (char *)g_base64_decode (auth + 6, &len);
+
+			if (!strncmp (decoded, "alice:password", len) ||
+			    !strncmp (decoded, "bob:password", len))
+				auth_required = FALSE;
+		}
 	}
 
-	if (state == NTLM_RECEIVED_REQUEST) {
+	if (ntlm_allowed && state > NTLM_SENT_CHALLENGE &&
+	    (!required_user || required_user == state))
+		auth_required = FALSE;
+
+	if (auth_required) {
 		soup_message_set_status (msg, SOUP_STATUS_UNAUTHORIZED);
-		soup_message_headers_append (msg->response_headers,
-					     "WWW-Authenticate",
-					     "NTLM " NTLM_CHALLENGE);
-		state = NTLM_SENT_CHALLENGE;
-	} else if (!required_user || required_user == state) {
+
+		if (basic_allowed) {
+			soup_message_headers_append (msg->response_headers,
+						     "WWW-Authenticate",
+						     "Basic realm=\"ntlm-test\"");
+		}
+
+		if (state == NTLM_RECEIVED_REQUEST) {
+			soup_message_headers_append (msg->response_headers,
+						     "WWW-Authenticate",
+						     "NTLM " NTLM_CHALLENGE);
+			state = NTLM_SENT_CHALLENGE;
+		} else if (ntlm_allowed) {
+			soup_message_headers_append (msg->response_headers,
+						     "WWW-Authenticate", "NTLM");
+			soup_message_headers_append (msg->response_headers,
+						     "Connection", "close");
+		}
+	} else {
 		if (not_found)
 			soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
 		else {
@@ -99,16 +148,10 @@
 						   "OK\r\n", 4);
 			soup_message_set_status (msg, SOUP_STATUS_OK);
 		}
-	} else {
-		soup_message_set_status (msg, SOUP_STATUS_UNAUTHORIZED);
-		soup_message_headers_append (msg->response_headers,
-					     "WWW-Authenticate", "NTLM");
-		soup_message_headers_append (msg->response_headers,
-					     "Connection", "close");
 	}
 
-	g_hash_table_insert (connections, soup_client_context_get_socket (client),
-			     GINT_TO_POINTER (state));
+	g_hash_table_insert (connections, socket, GINT_TO_POINTER (state));
+	g_object_weak_ref (G_OBJECT (socket), clear_state, connections);
 }
 
 static void
@@ -119,28 +162,33 @@
 }
 
 typedef struct {
-	gboolean got_prompt;
-	gboolean sent_request;
-	gboolean got_challenge;
-	gboolean sent_response;
+	gboolean got_ntlm_prompt;
+	gboolean got_basic_prompt;
+	gboolean sent_ntlm_request;
+	gboolean got_ntlm_challenge;
+	gboolean sent_ntlm_response;
+	gboolean sent_basic_response;
 } NTLMState;
 
 static void
-ntlm_prompt_check (SoupMessage *msg, gpointer user_data)
+prompt_check (SoupMessage *msg, gpointer user_data)
 {
 	NTLMState *state = user_data;
 	const char *header;
 
-	if (state->sent_request)
-		return;
 	header = soup_message_headers_get (msg->response_headers,
-					    "WWW-Authenticate");
-	if (header && !strcmp (header, "NTLM"))
-		state->got_prompt = TRUE;
+					   "WWW-Authenticate");
+	if (header && strstr (header, "Basic "))
+		state->got_basic_prompt = TRUE;
+	if (!state->sent_ntlm_request) {
+		if (header && strstr (header, "NTLM") &&
+		    !strstr (header, NTLM_CHALLENGE))
+			state->got_ntlm_prompt = TRUE;
+	}
 }
 
 static void
-ntlm_challenge_check (SoupMessage *msg, gpointer user_data)
+challenge_check (SoupMessage *msg, gpointer user_data)
 {
 	NTLMState *state = user_data;
 	const char *header;
@@ -148,38 +196,42 @@
 	header = soup_message_headers_get (msg->response_headers,
 					    "WWW-Authenticate");
 	if (header && !strncmp (header, "NTLM ", 5))
-		state->got_challenge = TRUE;
+		state->got_ntlm_challenge = TRUE;
 }
 
 static void
-ntlm_request_check (SoupMessage *msg, gpointer user_data)
+request_check (SoupMessage *msg, gpointer user_data)
 {
 	NTLMState *state = user_data;
 	const char *header;
 
 	header = soup_message_headers_get (msg->request_headers,
-					    "Authorization");
+					   "Authorization");
 	if (header && !strncmp (header, "NTLM " NTLM_REQUEST_START,
 				strlen ("NTLM " NTLM_REQUEST_START)))
-		state->sent_request = TRUE;
+		state->sent_ntlm_request = TRUE;
 }
 
 static void
-ntlm_response_check (SoupMessage *msg, gpointer user_data)
+response_check (SoupMessage *msg, gpointer user_data)
 {
 	NTLMState *state = user_data;
 	const char *header;
 
 	header = soup_message_headers_get (msg->request_headers,
-					    "Authorization");
+					   "Authorization");
 	if (header && !strncmp (header, "NTLM " NTLM_RESPONSE_START,
 				strlen ("NTLM " NTLM_RESPONSE_START)))
-		state->sent_response = TRUE;
+		state->sent_ntlm_response = TRUE;
+	if (header && !strncmp (header, "Basic ", 6))
+		state->sent_basic_response = TRUE;
 }
 
 static void
 do_message (SoupSession *session, SoupURI *base_uri, const char *path,
-	    gboolean get_prompt, gboolean do_ntlm, guint status_code)
+	    gboolean get_ntlm_prompt, gboolean do_ntlm,
+	    gboolean get_basic_prompt, gboolean do_basic,
+	    guint status_code)
 {
 	SoupURI *uri;
 	SoupMessage *msg;
@@ -190,29 +242,40 @@
 	soup_uri_free (uri);
 
 	g_signal_connect (msg, "got_headers",
-			  G_CALLBACK (ntlm_prompt_check), &state);
+			  G_CALLBACK (prompt_check), &state);
 	g_signal_connect (msg, "got_headers",
-			  G_CALLBACK (ntlm_challenge_check), &state);
+			  G_CALLBACK (challenge_check), &state);
 	g_signal_connect (msg, "wrote-headers",
-			  G_CALLBACK (ntlm_request_check), &state);
+			  G_CALLBACK (request_check), &state);
 	g_signal_connect (msg, "wrote-headers",
-			  G_CALLBACK (ntlm_response_check), &state);
+			  G_CALLBACK (response_check), &state);
 
 	soup_session_send_message (session, msg);
 	debug_printf (1, "  %-10s -> ", path);
 
-	if (state.got_prompt) {
-		debug_printf (1, " PROMPT");
-		if (!get_prompt) {
+	if (state.got_ntlm_prompt) {
+		debug_printf (1, " NTLM_PROMPT");
+		if (!get_ntlm_prompt) {
 			debug_printf (1, "???");
 			errors++;
 		}
-	} else if (get_prompt) {
-		debug_printf (1, " no-prompt???");
+	} else if (get_ntlm_prompt) {
+		debug_printf (1, " no-ntlm-prompt???");
 		errors++;
 	}
 
-	if (state.sent_request) {
+	if (state.got_basic_prompt) {
+		debug_printf (1, " BASIC_PROMPT");
+		if (!get_basic_prompt) {
+			debug_printf (1, "???");
+			errors++;
+		}
+	} else if (get_basic_prompt) {
+		debug_printf (1, " no-basic-prompt???");
+		errors++;
+	}
+
+	if (state.sent_ntlm_request) {
 		debug_printf (1, " REQUEST");
 		if (!do_ntlm) {
 			debug_printf (1, "???");
@@ -223,7 +286,7 @@
 		errors++;
 	}
 
-	if (state.got_challenge) {
+	if (state.got_ntlm_challenge) {
 		debug_printf (1, " CHALLENGE");
 		if (!do_ntlm) {
 			debug_printf (1, "???");
@@ -234,14 +297,25 @@
 		errors++;
 	}
 
-	if (state.sent_response) {
-		debug_printf (1, " RESPONSE");
+	if (state.sent_ntlm_response) {
+		debug_printf (1, " NTLM_RESPONSE");
 		if (!do_ntlm) {
 			debug_printf (1, "???");
 			errors++;
 		}
 	} else if (do_ntlm) {
-		debug_printf (1, " no-response???");
+		debug_printf (1, " no-ntlm-response???");
+		errors++;
+	}
+
+	if (state.sent_basic_response) {
+		debug_printf (1, " BASIC_RESPONSE");
+		if (!do_basic) {
+			debug_printf (1, "???");
+			errors++;
+		}
+	} else if (do_basic) {
+		debug_printf (1, " no-basic-response???");
 		errors++;
 	}
 
@@ -256,10 +330,9 @@
 }
 
 static void
-do_ntlm_round (SoupURI *base_uri, const char *user)
+do_ntlm_round (SoupURI *base_uri, gboolean use_ntlm, const char *user)
 {
 	SoupSession *session;
-	gboolean use_ntlm = user != NULL;
 	gboolean alice = use_ntlm && !strcmp (user, "alice");
 	gboolean bob = use_ntlm && !strcmp (user, "bob");
 
@@ -269,31 +342,50 @@
 		SOUP_TYPE_SESSION_ASYNC,
 		SOUP_SESSION_USE_NTLM, use_ntlm,
 		NULL);
-	g_signal_connect (session, "authenticate",
-			  G_CALLBACK (authenticate), (char *)user);
+	if (user) {
+		g_signal_connect (session, "authenticate",
+				  G_CALLBACK (authenticate), (char *)user);
+	}
 
 	do_message (session, base_uri, "/noauth",
-		    FALSE, use_ntlm, SOUP_STATUS_OK);
+		    FALSE, use_ntlm,
+		    FALSE, FALSE,
+		    SOUP_STATUS_OK);
 	do_message (session, base_uri, "/alice",
 		    !use_ntlm || bob, FALSE,
+		    FALSE, FALSE,
 		    alice ? SOUP_STATUS_OK :
 		    SOUP_STATUS_UNAUTHORIZED);
 	do_message (session, base_uri, "/alice/404",
 		    !use_ntlm, bob,
+		    FALSE, FALSE,
 		    alice ? SOUP_STATUS_NOT_FOUND :
 		    SOUP_STATUS_UNAUTHORIZED);
 	do_message (session, base_uri, "/alice",
 		    !use_ntlm, bob,
+		    FALSE, FALSE,
 		    alice ? SOUP_STATUS_OK :
 		    SOUP_STATUS_UNAUTHORIZED);
 	do_message (session, base_uri, "/bob",
 		    !use_ntlm || alice, bob,
+		    FALSE, FALSE,
 		    bob ? SOUP_STATUS_OK :
 		    SOUP_STATUS_UNAUTHORIZED);
 	do_message (session, base_uri, "/alice",
 		    !use_ntlm || bob, alice,
+		    FALSE, FALSE,
 		    alice ? SOUP_STATUS_OK :
 		    SOUP_STATUS_UNAUTHORIZED);
+	do_message (session, base_uri, "/basic",
+		    FALSE, bob,
+		    TRUE, user != NULL,
+		    user != NULL ? SOUP_STATUS_OK :
+		    SOUP_STATUS_UNAUTHORIZED);
+	do_message (session, base_uri, "/either",
+		    !use_ntlm, FALSE,
+		    !use_ntlm, !use_ntlm && user != NULL,
+		    user != NULL ? SOUP_STATUS_OK :
+		    SOUP_STATUS_UNAUTHORIZED);
 
 	soup_session_abort (session);
 	g_object_unref (session);
@@ -302,12 +394,14 @@
 static void
 do_ntlm_tests (SoupURI *base_uri)
 {
-	debug_printf (1, "Round 1: Non-NTLM Connection\n");
-	do_ntlm_round (base_uri, NULL);
+	debug_printf (1, "Round 1: Non-NTLM Connection, no auth\n");
+	do_ntlm_round (base_uri, FALSE, NULL);
 	debug_printf (1, "Round 2: NTLM Connection, user=alice\n");
-	do_ntlm_round (base_uri, "alice");
+	do_ntlm_round (base_uri, TRUE, "alice");
 	debug_printf (1, "Round 3: NTLM Connection, user=bob\n");
-	do_ntlm_round (base_uri, "bob");
+	do_ntlm_round (base_uri, TRUE, "bob");
+	debug_printf (1, "Round 4: Non-NTLM Connection, user=alice\n");
+	do_ntlm_round (base_uri, FALSE, "alice");
 }
 
 int
@@ -333,8 +427,9 @@
 	soup_uri_free (uri);
 
 	g_main_loop_unref (loop);
-	g_hash_table_destroy (connections);
 
 	test_cleanup ();
+	g_hash_table_destroy (connections);
+
 	return errors != 0;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]