diff --git a/libsoup/soup-auth-manager-ntlm.c b/libsoup/soup-auth-manager-ntlm.c
index 49db613..ac2c262 100644
--- a/libsoup/soup-auth-manager-ntlm.c
+++ b/libsoup/soup-auth-manager-ntlm.c
@@ -12,6 +12,13 @@
 
 #include <ctype.h>
 #include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
 
 #include "soup-auth-manager-ntlm.h"
 #include "soup-auth-ntlm.h"
@@ -32,6 +39,7 @@ static void request_started (SoupSessionFeature *feature, SoupSession *session,
 			     SoupMessage *msg, SoupSocket *socket);
 static void request_unqueued (SoupSessionFeature *feature,
 			      SoupSession *session, SoupMessage *msg);
+static void sso_ntlm_close (gint *fd_helper, pid_t *childpid);
 static gboolean add_feature (SoupSessionFeature *feature, GType type);
 static gboolean remove_feature (SoupSessionFeature *feature, GType type);
 static gboolean has_feature (SoupSessionFeature *feature, GType type);
@@ -42,6 +50,10 @@ G_DEFINE_TYPE_WITH_CODE (SoupAuthManagerNTLM, soup_auth_manager_ntlm, SOUP_TYPE_
 
 typedef enum {
 	SOUP_NTLM_NEW,
+	SOUP_NTLM_SENT_SSO_REQUEST,
+	SOUP_NTLM_RECEIVED_SSO_CHALLENGE,
+	SOUP_NTLM_SENT_SSO_RESPONSE,
+	SOUP_NTLM_SSO_FAILED,
 	SOUP_NTLM_SENT_REQUEST,
 	SOUP_NTLM_RECEIVED_CHALLENGE,
 	SOUP_NTLM_SENT_RESPONSE,
@@ -52,6 +64,7 @@ typedef struct {
 	SoupSocket *socket;
 	SoupNTLMState state;
 	char *response_header;
+	char *challenge_header;
 
 	char *nonce, *domain;
 	SoupAuth *auth;
@@ -63,6 +76,9 @@ typedef struct {
 	SoupSession *session;
 	GHashTable *connections_by_msg;
 	GHashTable *connections_by_id;
+
+	gint fd_helper;
+	pid_t childpid;
 } SoupAuthManagerNTLMPrivate;
 #define SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_AUTH_MANAGER_NTLM, SoupAuthManagerNTLMPrivate))
 
@@ -84,12 +100,15 @@ soup_auth_manager_ntlm_init (SoupAuthManagerNTLM *ntlm)
 
 	priv->connections_by_id = g_hash_table_new (NULL, NULL);
 	priv->connections_by_msg = g_hash_table_new (NULL, NULL);
+	priv->fd_helper = -1;
+	priv->childpid = 0;
 }
 
 static void
 free_ntlm_connection (SoupNTLMConnection *conn)
 {
 	g_free (conn->response_header);
+	g_free (conn->challenge_header);
 	g_free (conn->nonce);
 	g_free (conn->domain);
 	if (conn->auth)
@@ -114,6 +133,8 @@ finalize (GObject *object)
 	g_hash_table_destroy (priv->connections_by_id);
 	g_hash_table_destroy (priv->connections_by_msg);
 
+	sso_ntlm_close (&priv->fd_helper, &priv->childpid);
+
 	G_OBJECT_CLASS (soup_auth_manager_ntlm_parent_class)->finalize (object);
 }
 
@@ -218,6 +239,142 @@ get_connection_for_msg (SoupAuthManagerNTLMPrivate *priv, SoupMessage *msg)
 }
 
 static void
+sso_ntlm_close (gint *fd_helper, pid_t *childpid)
+{
+	if (*fd_helper != -1) {
+		close (*fd_helper);
+		*fd_helper = -1;
+	}
+
+	if (*childpid) {
+		gint ret, i;
+		for (i = 0; i < 4; i++) {
+			ret = waitpid (*childpid, NULL, WNOHANG);
+			if (ret == *childpid || errno == ECHILD)
+				break;
+			switch (i) {
+			case 0:
+				kill (*childpid, SIGTERM);
+				break;
+			case 2:
+				kill (*childpid, SIGKILL);
+				break;
+			case 1:
+			case 3:
+				sleep (1);
+				break;
+			}
+		}
+		*childpid = 0;
+	}
+}
+
+#define NTLM_AUTH_HELPER "/usr/bin/ntlm_auth"
+
+static gboolean
+sso_ntlm_initiate (gint *fd_helper, pid_t *childpid)
+{
+	gint sockfds[2];
+	pid_t pid;
+	char *username = NULL, *slash, *domain = NULL;
+	char *arg_username = NULL, *arg_domain = NULL;
+
+	if (*fd_helper != -1 || *childpid) {
+		sso_ntlm_close (fd_helper, childpid);
+	}
+
+	username = getenv ("NTLMUSER");
+	if (!username)
+		username = getenv ("USER");
+	if (!username)
+		goto done;
+
+	slash = strpbrk (username, "\\/");
+	if (slash) {
+		domain = g_strdup (username);
+		slash = domain + (slash - username);
+		*slash = '\0';
+		username = slash + 1;
+	}
+
+	arg_username = g_strdup_printf ("--username '%s'", username);
+	if (domain)
+		arg_domain = g_strdup_printf ("--domain '%s'", domain);
+
+	if (access (NTLM_AUTH_HELPER, X_OK))
+		goto done;
+
+	if (socketpair (AF_UNIX, SOCK_STREAM, 0, sockfds))
+		goto done;
+
+	pid = fork ();
+	if (!pid) {
+		/* child process */
+		if (dup2 (sockfds[1], 0) == -1 || dup2 (sockfds[1], 1) == -1)
+			exit (1);
+
+		execl (NTLM_AUTH_HELPER, "--helper-protocol ntlmssp-client-1", "--use-cached-creds", arg_username, arg_domain, NULL);
+
+		exit (1);
+	} else if (pid == -1) {
+		close (sockfds[0]);
+		close (sockfds[1]);
+		goto done;
+	}
+
+	close (sockfds[1]);
+	*fd_helper = sockfds[0];
+	*childpid = pid;
+	if (domain) {
+		g_free (domain);
+		g_free (arg_domain);
+	}
+	g_free (arg_username);
+	return TRUE;
+
+done:
+	if (domain) {
+		g_free (domain);
+		g_free (arg_domain);
+	}
+	g_free (arg_username);
+
+	return FALSE;
+}
+
+static char *
+sso_ntlm_response (gint fd_helper, const char* input, SoupNTLMState conn_state)
+{
+	ssize_t size;
+	char buf[1024], *response = NULL;
+
+	if (write (fd_helper, input, strlen (input)) < 0 ||
+	    (size = read (fd_helper, buf, 1024)) < 5 ) {
+		goto done;
+	}
+	/* Samba/winbind installed but not configured */
+	if (conn_state == SOUP_NTLM_NEW &&
+	    buf[0] == 'P' && buf[1] == 'W' && buf[size-1] == '\n') {
+		response = g_strdup ("PW");
+		goto done;
+	}
+	/* invalid response */
+	if (conn_state == SOUP_NTLM_NEW &&
+	    (buf[0] != 'Y' || buf[1] != 'R' || buf[2] != ' ' || buf[size-1] != '\n'))
+		goto done;
+	if (conn_state == SOUP_NTLM_RECEIVED_SSO_CHALLENGE &&
+	    (buf[0] != 'K' || buf[1] != 'K' || buf[2] != ' ' || buf[size-1] != '\n'))
+		goto done;
+
+	response = g_strndup (buf + 3, size - 4);
+	*(response + size - 4) = '\0';
+	response = g_strconcat ("NTLM ", response, NULL);
+	goto done;
+done:
+	return response;
+}
+
+static void
 ntlm_authorize_pre (SoupMessage *msg, gpointer ntlm)
 {
 	SoupAuthManagerNTLMPrivate *priv =
@@ -250,13 +407,18 @@ ntlm_authorize_pre (SoupMessage *msg, gpointer ntlm)
 		goto done;
 	}
 
-	conn->state = SOUP_NTLM_RECEIVED_CHALLENGE;
+	conn->challenge_header = g_strdup (val + 5);
 	conn->auth = soup_auth_ntlm_new (conn->domain,
 					 soup_message_get_uri (msg)->host);
-	soup_auth_manager_emit_authenticate (SOUP_AUTH_MANAGER (ntlm), msg,
-					     conn->auth, FALSE);
+	if (conn->state == SOUP_NTLM_SENT_SSO_REQUEST)
+		conn->state = SOUP_NTLM_RECEIVED_SSO_CHALLENGE;
+	else {
+		conn->state = SOUP_NTLM_RECEIVED_CHALLENGE;
+		soup_auth_manager_emit_authenticate (SOUP_AUTH_MANAGER (ntlm), msg,
+						     conn->auth, FALSE);
+	}
 
- done:
+done:
 	/* Remove the WWW-Authenticate headers so the session won't try
 	 * to do Basic auth too.
 	 */
@@ -276,25 +438,46 @@ ntlm_authorize_post (SoupMessage *msg, gpointer ntlm)
 	if (!conn || !conn->auth)
 		return;
 
-	username = soup_auth_ntlm_get_username (conn->auth);
-	password = soup_auth_ntlm_get_password (conn->auth);
-	if (!username || !password)
+	if (conn->state == SOUP_NTLM_RECEIVED_SSO_CHALLENGE) {
+		char *input;
+		input = g_strdup_printf ("TT %s\n", conn->challenge_header);
+		conn->response_header = sso_ntlm_response (priv->fd_helper,
+							   input,
+							   conn->state);
+		sso_ntlm_close (&priv->fd_helper, &priv->childpid);
+		if (!conn->response_header) {
+			g_free (input);
+			goto ssofailure;
+		}
+		soup_session_requeue_message (priv->session, msg);
+		g_free (input);
 		goto done;
-
-	slash = strpbrk (username, "\\/");
-	if (slash) {
-		domain = g_strdup (username);
-		slash = domain + (slash - username);
-		*slash = '\0';
-		username = slash + 1;
-	} else
-		domain = conn->domain;
-
-	conn->response_header = soup_ntlm_response (conn->nonce,
-						    username, password,
-						    NULL, domain);
-	soup_session_requeue_message (priv->session, msg);
-
+ssofailure:
+		conn->state = SOUP_NTLM_SSO_FAILED;
+		soup_session_requeue_message (priv->session, msg);
+		goto done;
+	}
+	else {
+		username = soup_auth_ntlm_get_username (conn->auth);
+		password = soup_auth_ntlm_get_password (conn->auth);
+
+		if (!username || !password)
+			goto done;
+
+		slash = strpbrk (username, "\\/");
+		if (slash) {
+			domain = g_strdup (username);
+			slash = domain + (slash - username);
+			*slash = '\0';
+			username = slash + 1;
+		} else
+			domain = conn->domain;
+
+		conn->response_header = soup_ntlm_response (conn->nonce,
+							    username, password,
+							    NULL, domain);
+		soup_session_requeue_message (priv->session, msg);
+	}
 done:
 	if (domain != conn->domain)
 		g_free (domain);
@@ -341,6 +524,40 @@ request_started (SoupSessionFeature *ntlm, SoupSession *session,
 
 	switch (conn->state) {
 	case SOUP_NTLM_NEW:
+		/* Try SSO first, start the request without emit Authentication signal.
+		 * If SSO fails, go back to original request handling process.
+		 */
+		if (sso_ntlm_initiate (&priv->fd_helper, &priv->childpid)) {
+			header = sso_ntlm_response (priv->fd_helper, "YR\n", conn->state);
+			if (header) {
+				if (g_ascii_strcasecmp (header, "PW")) {
+					conn->state = SOUP_NTLM_SENT_SSO_REQUEST;
+					break;
+				}
+				else {
+					g_free (header);
+					header = NULL;
+					goto ssofailure;
+				}
+			}
+			else {
+				g_warning ("NTLM Single-Sign-On by using %s faied", NTLM_AUTH_HELPER);
+				goto ssofailure;
+			}
+		}
+ssofailure:
+		sso_ntlm_close (&priv->fd_helper, &priv->childpid);
+		header = soup_ntlm_request ();
+		conn->state = SOUP_NTLM_SENT_REQUEST;
+		break;
+	case SOUP_NTLM_RECEIVED_SSO_CHALLENGE:
+		header = conn->response_header;
+		conn->response_header = NULL;
+		conn->state = SOUP_NTLM_SENT_SSO_RESPONSE;
+		break;
+	case SOUP_NTLM_SSO_FAILED:
+		/* Restart request without SSO */
+		g_warning ("NTLM Single-Sign-On by using %s faied", NTLM_AUTH_HELPER);
 		header = soup_ntlm_request ();
 		conn->state = SOUP_NTLM_SENT_REQUEST;
 		break;
