summaryrefslogtreecommitdiff
path: root/libsoup/auth
diff options
context:
space:
mode:
authorCarlos Garcia Campos <cgarcia@igalia.com>2020-10-26 10:20:01 +0100
committerCarlos Garcia Campos <cgarcia@igalia.com>2020-10-28 09:36:28 +0100
commit8a918ee3cd75def6f9c1a6bdcb1008e99684ec6b (patch)
treefb2e595e7ef0e253ba97e7f05fe5cf9173f824da /libsoup/auth
parent50248a9d3127eec834e9b9450ea26d98683d0d55 (diff)
downloadlibsoup-8a918ee3cd75def6f9c1a6bdcb1008e99684ec6b.tar.gz
Move authenticate signal from SoupSession to SoupMessage
In case of tunneling the authenticate signal is emitted in the original message, since the tunneling message is an internal implementation detail. The authenticate signal is now true handled, and SoupAuthManager automatically pauses and unpauses the message when handled asynchronously. soup_auth_cancel() has been added to complete an async authentication when no credentials are provided.
Diffstat (limited to 'libsoup/auth')
-rw-r--r--libsoup/auth/soup-auth-manager.c37
-rw-r--r--libsoup/auth/soup-auth.c100
-rw-r--r--libsoup/auth/soup-auth.h8
3 files changed, 142 insertions, 3 deletions
diff --git a/libsoup/auth/soup-auth-manager.c b/libsoup/auth/soup-auth-manager.c
index 86f249d4..2af4a0b5 100644
--- a/libsoup/auth/soup-auth-manager.c
+++ b/libsoup/auth/soup-auth-manager.c
@@ -508,6 +508,21 @@ lookup_proxy_auth (SoupAuthManagerPrivate *priv, SoupMessage *msg)
}
static void
+async_auth_finished (SoupAuth *auth,
+ GParamSpec *pspec,
+ SoupMessage *msg)
+{
+ SoupSession *session;
+
+ session = g_object_steal_data (G_OBJECT (msg), "auth-msg-session");
+ if (!session)
+ return;
+
+ soup_session_unpause_message (session, msg);
+ g_object_unref (session);
+}
+
+static void
authenticate_auth (SoupAuthManager *manager, SoupAuth *auth,
SoupMessage *msg, gboolean prior_auth_failed,
gboolean proxy, gboolean can_interact)
@@ -533,8 +548,24 @@ authenticate_auth (SoupAuthManager *manager, SoupAuth *auth,
soup_uri_set_password (uri, NULL);
soup_uri_set_user (uri, NULL);
} else if (!soup_auth_is_authenticated (auth) && can_interact) {
- g_signal_emit (manager, signals[AUTHENTICATE], 0,
- msg, auth, prior_auth_failed);
+ SoupMessage *original_msg;
+ gboolean handled;
+
+ original_msg = soup_session_get_original_message_for_authentication (priv->session,
+ msg);
+ handled = soup_message_authenticate (original_msg, auth, prior_auth_failed);
+ if (handled && !soup_auth_is_authenticated (auth)) {
+ soup_session_pause_message (priv->session, msg);
+ g_object_set_data_full (G_OBJECT (msg), "auth-msg-session",
+ g_object_ref (priv->session),
+ g_object_unref);
+ g_signal_connect_object (auth, "notify::is-authenticated",
+ G_CALLBACK (async_auth_finished),
+ msg, 0);
+ g_signal_connect_object (auth, "notify::is-cancelled",
+ G_CALLBACK (async_auth_finished),
+ msg, 0);
+ }
}
}
@@ -578,7 +609,7 @@ record_auth_for_uri (SoupAuthManagerPrivate *priv, SoupURI *uri,
* since the old one might already be authenticated.)
*/
old_auth = g_hash_table_lookup (host->auths, auth_info);
- if (old_auth && (old_auth != auth || !prior_auth_failed)) {
+ if (old_auth && (old_auth != auth || !prior_auth_failed) && !soup_auth_is_cancelled (old_auth)) {
g_free (auth_info);
return old_auth;
} else {
diff --git a/libsoup/auth/soup-auth.c b/libsoup/auth/soup-auth.c
index 881ed9f9..62d0a677 100644
--- a/libsoup/auth/soup-auth.c
+++ b/libsoup/auth/soup-auth.c
@@ -38,6 +38,7 @@ typedef struct {
char *realm;
char *host;
gboolean proxy;
+ gboolean cancelled;
} SoupAuthPrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (SoupAuth, soup_auth, G_TYPE_OBJECT)
@@ -50,6 +51,7 @@ enum {
PROP_HOST,
PROP_IS_FOR_PROXY,
PROP_IS_AUTHENTICATED,
+ PROP_IS_CANCELLED,
LAST_PROP
};
@@ -60,6 +62,18 @@ soup_auth_init (SoupAuth *auth)
}
static void
+soup_auth_dispose (GObject *object)
+{
+ SoupAuth *auth = SOUP_AUTH (object);
+ SoupAuthPrivate *priv = soup_auth_get_instance_private (auth);
+
+ if (!priv->cancelled && !soup_auth_is_authenticated (auth))
+ soup_auth_cancel (auth);
+
+ G_OBJECT_CLASS (soup_auth_parent_class)->dispose (object);
+}
+
+static void
soup_auth_finalize (GObject *object)
{
SoupAuth *auth = SOUP_AUTH (object);
@@ -119,6 +133,8 @@ soup_auth_get_property (GObject *object, guint prop_id,
case PROP_IS_AUTHENTICATED:
g_value_set_boolean (value, soup_auth_is_authenticated (auth));
break;
+ case PROP_IS_CANCELLED:
+ g_value_set_boolean (value, priv->cancelled);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -138,6 +154,7 @@ soup_auth_class_init (SoupAuthClass *auth_class)
auth_class->can_authenticate = auth_can_authenticate;
+ object_class->dispose = soup_auth_dispose;
object_class->finalize = soup_auth_finalize;
object_class->set_property = soup_auth_set_property;
object_class->get_property = soup_auth_get_property;
@@ -208,6 +225,20 @@ soup_auth_class_init (SoupAuthClass *auth_class)
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
+ /**
+ * SoupAuth:is-cancelled:
+ *
+ * An alias for the #SoupAuth:is-cancelled property.
+ * (Whether or not the auth has been cancelled.)
+ **/
+ g_object_class_install_property (
+ object_class, PROP_IS_CANCELLED,
+ g_param_spec_boolean ("is-cancelled",
+ "Cancelled",
+ "Whether or not the auth is cancelled",
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
}
/**
@@ -289,6 +320,9 @@ soup_auth_update (SoupAuth *auth, SoupMessage *msg, const char *auth_header)
g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
g_return_val_if_fail (auth_header != NULL, FALSE);
+ if (priv->cancelled)
+ return FALSE;
+
scheme = soup_auth_get_scheme_name (auth);
if (g_ascii_strncasecmp (auth_header, scheme, strlen (scheme)) != 0)
return FALSE;
@@ -323,12 +357,17 @@ soup_auth_update (SoupAuth *auth, SoupMessage *msg, const char *auth_header)
void
soup_auth_authenticate (SoupAuth *auth, const char *username, const char *password)
{
+ SoupAuthPrivate *priv;
gboolean was_authenticated;
g_return_if_fail (SOUP_IS_AUTH (auth));
g_return_if_fail (username != NULL);
g_return_if_fail (password != NULL);
+ priv = soup_auth_get_instance_private (auth);
+ if (priv->cancelled)
+ return;
+
was_authenticated = soup_auth_is_authenticated (auth);
SOUP_AUTH_GET_CLASS (auth)->authenticate (auth, username, password);
if (was_authenticated != soup_auth_is_authenticated (auth))
@@ -336,6 +375,30 @@ soup_auth_authenticate (SoupAuth *auth, const char *username, const char *passwo
}
/**
+ * soup_auth_cancel:
+ * @auth: a #SoupAuth
+ *
+ * Call this on an auth to cancel it. You need to cancel an auth to complete
+ * an asynchronous authenticate operation when no credentials are provided
+ * (soup_auth_authenticate() is not called).
+ * The #SoupAuth will be cancelled on dispose if it hans't been authenticated.
+ */
+void
+soup_auth_cancel (SoupAuth *auth)
+{
+ SoupAuthPrivate *priv;
+
+ g_return_if_fail (SOUP_IS_AUTH (auth));
+
+ priv = soup_auth_get_instance_private (auth);
+ if (priv->cancelled)
+ return;
+
+ priv->cancelled = TRUE;
+ g_object_notify (G_OBJECT (auth), "is-cancelled");
+}
+
+/**
* soup_auth_is_for_proxy:
* @auth: a #SoupAuth
*
@@ -447,12 +510,37 @@ soup_auth_get_info (SoupAuth *auth)
gboolean
soup_auth_is_authenticated (SoupAuth *auth)
{
+ SoupAuthPrivate *priv;
+
g_return_val_if_fail (SOUP_IS_AUTH (auth), TRUE);
+ priv = soup_auth_get_instance_private (auth);
+ if (priv->cancelled)
+ return FALSE;
+
return SOUP_AUTH_GET_CLASS (auth)->is_authenticated (auth);
}
/**
+ * soup_auth_is_cancelled:
+ * @auth: a #SoupAuth
+ *
+ * Tests if @auth has been cancelled
+ *
+ * Returns: %TRUE if @auth has been cancelled
+ */
+gboolean
+soup_auth_is_cancelled (SoupAuth *auth)
+{
+ SoupAuthPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_AUTH (auth), TRUE);
+
+ priv = soup_auth_get_instance_private (auth);
+ return priv->cancelled;
+}
+
+/**
* soup_auth_get_authorization:
* @auth: a #SoupAuth
* @msg: the #SoupMessage to be authorized
@@ -490,9 +578,15 @@ gboolean
soup_auth_is_ready (SoupAuth *auth,
SoupMessage *msg)
{
+ SoupAuthPrivate *priv;
+
g_return_val_if_fail (SOUP_IS_AUTH (auth), TRUE);
g_return_val_if_fail (SOUP_IS_MESSAGE (msg), TRUE);
+ priv = soup_auth_get_instance_private (auth);
+ if (priv->cancelled)
+ return FALSE;
+
if (SOUP_AUTH_GET_CLASS (auth)->is_ready)
return SOUP_AUTH_GET_CLASS (auth)->is_ready (auth, msg);
else
@@ -513,8 +607,14 @@ soup_auth_is_ready (SoupAuth *auth,
gboolean
soup_auth_can_authenticate (SoupAuth *auth)
{
+ SoupAuthPrivate *priv;
+
g_return_val_if_fail (SOUP_IS_AUTH (auth), FALSE);
+ priv = soup_auth_get_instance_private (auth);
+ if (priv->cancelled)
+ return FALSE;
+
return SOUP_AUTH_GET_CLASS (auth)->can_authenticate (auth);
}
diff --git a/libsoup/auth/soup-auth.h b/libsoup/auth/soup-auth.h
index ab3f2519..284aa3da 100644
--- a/libsoup/auth/soup-auth.h
+++ b/libsoup/auth/soup-auth.h
@@ -67,8 +67,16 @@ SOUP_AVAILABLE_IN_2_4
void soup_auth_authenticate (SoupAuth *auth,
const char *username,
const char *password);
+
+SOUP_AVAILABLE_IN_ALL
+void soup_auth_cancel (SoupAuth *auth);
+
SOUP_AVAILABLE_IN_2_4
gboolean soup_auth_is_authenticated (SoupAuth *auth);
+
+SOUP_AVAILABLE_IN_ALL
+gboolean soup_auth_is_cancelled (SoupAuth *auth);
+
SOUP_AVAILABLE_IN_2_42
gboolean soup_auth_is_ready (SoupAuth *auth,
SoupMessage *msg);