summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Laban <david.laban@collabora.co.uk>2010-12-13 17:13:01 +0000
committerDavid Laban <david.laban@collabora.co.uk>2010-12-15 14:34:32 +0000
commit75a2d3a792b54c328b809e1f260ad1e49632fb6e (patch)
treee4ffcc6a4581b100247e4ec0110363745de34251
parentef71b9dd869a46476fff2a49b942eb04d9928832 (diff)
Ask for a password in priv_handle_auth() if not given.
This requires a call to tp_simple_password_manager_prompt_async(), so we create a data struct to help us split the function in half. Also, we move all checks from the second half of the function into the first, so they can be handled synchronously. The diff is clearer if you use git diff --patience.
-rw-r--r--src/sip-connection.c158
1 files changed, 139 insertions, 19 deletions
diff --git a/src/sip-connection.c b/src/sip-connection.c
index 51247fa..ad5caef 100644
--- a/src/sip-connection.c
+++ b/src/sip-connection.c
@@ -604,6 +604,54 @@ tpsip_connection_class_init (TpsipConnectionClass *klass)
G_STRUCT_OFFSET (TpsipConnectionClass, contacts_class));
}
+typedef struct {
+ TpsipConnection* self;
+ nua_handle_t *nh;
+ gchar *method;
+ gchar *realm;
+ gchar *user;
+} PrivHandleAuthData;
+
+static PrivHandleAuthData *
+priv_handle_auth_data_new (TpsipConnection* self,
+ nua_handle_t *nh,
+ const gchar *method,
+ const gchar *realm,
+ const gchar *user)
+{
+ PrivHandleAuthData *data = g_slice_new (PrivHandleAuthData);
+
+ data->self = g_object_ref (self);
+ data->nh = nua_handle_ref (nh);
+ data->method = g_strdup (method);
+ data->realm = g_strdup (realm);
+ data->user = g_strdup (user);
+
+ return data;
+}
+
+static void
+priv_handle_auth_data_free (PrivHandleAuthData *data)
+{
+ g_object_unref (data->self);
+ nua_handle_unref (data->nh);
+ g_free (data->method);
+ g_free (data->realm);
+ g_free (data->user);
+
+ g_slice_free (PrivHandleAuthData, data);
+}
+
+static void priv_password_manager_prompt_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data);
+static void priv_handle_auth_continue (TpsipConnection* self,
+ nua_handle_t *nh,
+ const gchar *method,
+ const gchar *realm,
+ const gchar *user,
+ const gchar *password);
+
static gboolean
priv_handle_auth (TpsipConnection* self,
int status,
@@ -618,7 +666,6 @@ priv_handle_auth (TpsipConnection* self,
const char *realm = NULL;
const char *user = NULL;
const char *password = NULL;
- gchar *auth = NULL;
if (status != 401 && status != 407)
return FALSE;
@@ -646,6 +693,12 @@ priv_handle_auth (TpsipConnection* self,
return FALSE;
}
+ if (method == NULL)
+ {
+ WARNING ("no method presented for authentication");
+ return FALSE;
+ }
+
/* step: determine which set of credentials to use */
if (home_realm)
{
@@ -679,6 +732,9 @@ priv_handle_auth (TpsipConnection* self,
/* fall back to the main username */
user = priv->auth_user;
password = priv->extra_auth_password;
+ if (password == NULL)
+ /* note that this prevents asking the user for a password */
+ password = "";
DEBUG("using the extra auth credentials");
}
@@ -689,37 +745,101 @@ priv_handle_auth (TpsipConnection* self,
if (sipfrom && sipfrom->a_url[0].url_user)
/* or use the userpart in "From" header */
user = sipfrom->a_url[0].url_user;
+ else
+ return FALSE;
}
if (password == NULL)
- password = "";
+ {
+ PrivHandleAuthData *data = NULL;
- /* step: if all info is available, create an authorization response */
- g_assert (realm != NULL);
- if (user && method) {
- if (realm[0] == '"')
- auth = g_strdup_printf ("%s:%s:%s:%s",
- method, realm, user, password);
- else
- auth = g_strdup_printf ("%s:\"%s\":%s:%s",
- method, realm, user, password);
+ DEBUG("asking the user for a password.");
+ data = priv_handle_auth_data_new (self, nh, method, realm,
+ user);
+ tp_simple_password_manager_prompt_async (priv->password_manager,
+ priv_password_manager_prompt_cb, data);
+ /* Promise that we'll handle it eventually, even if we end up just
+ * handling it with a blank password. */
+ return TRUE;
+ }
- DEBUG("%s authenticating user='%s' realm=%s",
- wa ? "server" : "proxy", user, realm);
- }
+ priv_handle_auth_continue (self, nh, method, realm,
+ user, password);
+ return TRUE;
+}
+
+static void
+priv_password_manager_prompt_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ PrivHandleAuthData *data = user_data;
+ GError *error = NULL;
+ const GString *password_string;
+ const gchar *password;
+
+ password_string = tp_simple_password_manager_prompt_finish (
+ TP_SIMPLE_PASSWORD_MANAGER (source_object), result, &error);
- if (auth == NULL)
+ if (error != NULL)
{
- WARNING ("authentication data are incomplete");
- return FALSE;
+ /* we promised to handle the auth challenge in priv_handle_auth() by
+ * returning TRUE, so we need to handle it anyway, even if it means
+ * doing it with a blank password.
+ */
+ DEBUG ("Auth channel failed: %s. Using blank password.", error->message);
+
+ password = "";
+
+ g_error_free (error);
}
+ else
+ {
+ TpsipConnectionPrivate *priv =
+ TPSIP_CONNECTION_GET_PRIVATE (data->self);
+
+ password = password_string->str;
+ /* also save it for later. */
+ g_free (priv->password);
+ priv->password = g_strdup (password);
+ }
+
+ priv_handle_auth_continue (data->self, data->nh, data->method, data->realm,
+ data->user, password);
+
+ priv_handle_auth_data_free (data);
+}
+
+static void
+priv_handle_auth_continue (TpsipConnection* self,
+ nua_handle_t *nh,
+ const gchar *method,
+ const gchar *realm,
+ const gchar *user,
+ const gchar *password)
+{
+ gchar *auth = NULL;
+
+ /* step: if all info is available, create an authorization response */
+ g_assert (realm != NULL);
+ g_assert (method != NULL);
+ g_assert (user != NULL);
+ g_assert (password != NULL);
+
+ if (realm[0] == '"')
+ auth = g_strdup_printf ("%s:%s:%s:%s",
+ method, realm, user, password);
+ else
+ auth = g_strdup_printf ("%s:\"%s\":%s:%s",
+ method, realm, user, password);
+
+ DEBUG ("%s-authenticating user='%s' realm=%s",
+ method, user, realm);
/* step: authenticate */
nua_authenticate(nh, NUTAG_AUTH(auth), TAG_END());
g_free (auth);
-
- return TRUE;
}
static gboolean