[libsoup/wip/auth] soup-message: expose auth/proxy-auth



commit 94ab8c1140f58e762e747344ec522521f8a518af
Author: Dan Winship <danw gnome org>
Date:   Fri Dec 28 16:45:31 2012 -0500

    soup-message: expose auth/proxy-auth
    
    Add SoupMessage:auth and :proxy-auth properties, make the
    corresponding getters and setters public, so that callers can force
    their own authentication in some cases.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=690839

 libsoup/libsoup-2.4.sym        |    4 +
 libsoup/soup-auth-manager.c    |    1 -
 libsoup/soup-message-private.h |    8 --
 libsoup/soup-message.c         |  173 +++++++++++++++++++++++++++++++++++-----
 libsoup/soup-message.h         |   16 ++++
 tests/auth-test.c              |   57 +++++++++++++
 6 files changed, 230 insertions(+), 29 deletions(-)
---
diff --git a/libsoup/libsoup-2.4.sym b/libsoup/libsoup-2.4.sym
index be4cd7f..dfea679 100644
--- a/libsoup/libsoup-2.4.sym
+++ b/libsoup/libsoup-2.4.sym
@@ -227,11 +227,13 @@ soup_message_disable_feature
 soup_message_finished
 soup_message_flags_get_type
 soup_message_get_address
+soup_message_get_auth
 soup_message_get_first_party
 soup_message_get_flags
 soup_message_get_https_status
 soup_message_get_http_version
 soup_message_get_priority
+soup_message_get_proxy_auth
 soup_message_get_soup_request
 soup_message_get_type
 soup_message_get_uri
@@ -276,11 +278,13 @@ soup_message_new
 soup_message_new_from_uri
 soup_message_priority_get_type
 soup_message_restarted
+soup_message_set_auth
 soup_message_set_chunk_allocator
 soup_message_set_first_party
 soup_message_set_flags
 soup_message_set_http_version
 soup_message_set_priority
+soup_message_set_proxy_auth
 soup_message_set_redirect
 soup_message_set_request
 soup_message_set_response
diff --git a/libsoup/soup-auth-manager.c b/libsoup/soup-auth-manager.c
index f40a928..c2b39eb 100644
--- a/libsoup/soup-auth-manager.c
+++ b/libsoup/soup-auth-manager.c
@@ -14,7 +14,6 @@
 #include "soup-auth-manager.h"
 #include "soup.h"
 #include "soup-connection-auth.h"
-#include "soup-message-private.h"
 #include "soup-message-queue.h"
 #include "soup-path-map.h"
 #include "soup-session-private.h"
diff --git a/libsoup/soup-message-private.h b/libsoup/soup-message-private.h
index 35cc988..c26d476 100644
--- a/libsoup/soup-message-private.h
+++ b/libsoup/soup-message-private.h
@@ -89,14 +89,6 @@ void soup_message_io_server    (SoupMessage               *msg,
                                gpointer                   user_data);
 void soup_message_io_cleanup   (SoupMessage               *msg);
 
-/* Auth handling */
-void           soup_message_set_auth       (SoupMessage *msg,
-                                           SoupAuth    *auth);
-SoupAuth      *soup_message_get_auth       (SoupMessage *msg);
-void           soup_message_set_proxy_auth (SoupMessage *msg,
-                                           SoupAuth    *auth);
-SoupAuth      *soup_message_get_proxy_auth (SoupMessage *msg);
-
 /* I/O */
 void                soup_message_io_stop        (SoupMessage          *msg);
 void                soup_message_io_finished    (SoupMessage          *msg);
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index 23fd8b0..54f4568 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -139,6 +139,8 @@ enum {
        PROP_TLS_CERTIFICATE,
        PROP_TLS_ERRORS,
        PROP_PRIORITY,
+       PROP_AUTH,
+       PROP_PROXY_AUTH,
 
        LAST_PROP
 };
@@ -244,6 +246,12 @@ soup_message_set_property (GObject *object, guint prop_id,
        case PROP_PRIORITY:
                priv->priority = g_value_get_enum (value);
                break;
+       case PROP_AUTH:
+               soup_message_set_auth (msg, g_value_get_object (value));
+               break;
+       case PROP_PROXY_AUTH:
+               soup_message_set_proxy_auth (msg, g_value_get_object (value));
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -314,6 +322,12 @@ soup_message_get_property (GObject *object, guint prop_id,
        case PROP_PRIORITY:
                g_value_set_enum (value, priv->priority);
                break;
+       case PROP_AUTH:
+               g_value_set_object (value, priv->auth);
+               break;
+       case PROP_PROXY_AUTH:
+               g_value_set_object (value, priv->proxy_auth);
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -939,6 +953,57 @@ soup_message_class_init (SoupMessageClass *message_class)
                                   SOUP_TYPE_MESSAGE_PRIORITY,
                                   SOUP_MESSAGE_PRIORITY_NORMAL,
                                   G_PARAM_READWRITE));
+       /**
+        * SOUP_MESSAGE_AUTH:
+        *
+        * Alias for the #SoupMessage:auth property, qv.
+        *
+        * Since: 2.46
+        **/
+       /**
+        * SoupMessage:auth:
+        *
+        * The #SoupAuth used with this request.
+        *
+        * Note that the #SoupSession will overwrite this before
+        * sending the message if it believes that a different
+        * #SoupAuth is the correct one to be using.
+        *
+        * Since: 2.46
+        */
+       g_object_class_install_property (
+               object_class, PROP_AUTH,
+               g_param_spec_object (SOUP_MESSAGE_AUTH,
+                                    "Auth",
+                                    "The SoupAuth used with this request",
+                                    SOUP_TYPE_AUTH,
+                                    G_PARAM_READWRITE));
+       /**
+        * SOUP_MESSAGE_PROXY_AUTH:
+        *
+        * Alias for the #SoupMessage:proxy-auth property, qv.
+        *
+        * Since: 2.46
+        **/
+       /**
+        * SoupMessage:proxy-auth:
+        *
+        * The #SoupAuth used with this request for proxy
+        * authentication.
+        *
+        * Note that the #SoupSession will overwrite this before
+        * sending the message if it believes that a different
+        * #SoupAuth is the correct one to be using.
+        *
+        * Since: 2.46
+        */
+       g_object_class_install_property (
+               object_class, PROP_PROXY_AUTH,
+               g_param_spec_object (SOUP_MESSAGE_PROXY_AUTH,
+                                    "Proxy auth",
+                                    "The SoupAuth used with this request for proxy authentication",
+                                    SOUP_TYPE_AUTH,
+                                    G_PARAM_READWRITE));
 }
 
 
@@ -1272,6 +1337,23 @@ soup_message_add_status_code_handler (SoupMessage *msg,
 }
 
 
+/**
+ * soup_message_set_auth:
+ * @msg: a #SoupMessage
+ * @auth: a #SoupAuth, or %NULL
+ *
+ * Sets @msg to authenticate to its destination using @auth, which
+ * must have already been fully authenticated. If @auth is %NULL, @msg
+ * will not authenticate to its destination.
+ *
+ * Note that the #SoupSession will overwrite this before sending the
+ * message if it believes that a different #SoupAuth is the correct
+ * one to be using. This method is primarily useful if you want to
+ * force the use of Basic auth on a request before having seen a
+ * 401 Unauthorized response.
+ *
+ * Since: 2.46
+ **/
 void
 soup_message_set_auth (SoupMessage *msg, SoupAuth *auth)
 {
@@ -1283,24 +1365,43 @@ soup_message_set_auth (SoupMessage *msg, SoupAuth *auth)
 
        priv = SOUP_MESSAGE_GET_PRIVATE (msg);
 
-       if (priv->auth) {
-               g_object_unref (priv->auth);
-               soup_message_headers_remove (msg->request_headers,
-                                            "Authorization");
+       if (auth != priv->auth) {
+               if (priv->auth)
+                       g_object_unref (priv->auth);
+               priv->auth = auth;
+               if (priv->auth)
+                       g_object_ref (priv->auth);
        }
-       priv->auth = auth;
-       if (!priv->auth)
-               return;
 
-       g_object_ref (priv->auth);
-       token = soup_auth_get_authorization (auth, msg);
-       if (token) {
+       if (priv->auth) {
+               token = soup_auth_get_authorization (auth, msg);
                soup_message_headers_replace (msg->request_headers,
                                              "Authorization", token);
                g_free (token);
+       } else {
+               soup_message_headers_remove (msg->request_headers,
+                                            "Authorization");
        }
 }
 
+/**
+ * soup_message_get_auth:
+ * @msg: a #SoupMessage
+ *
+ * Gets the #SoupAuth used by @msg for authentication.
+ *
+ * Note that libsoup updates #SoupMessage:auth only immediately before
+ * sending a message; if you call soup_message_get_auth() from a
+ * #SoupSession:authenticate handler, it will return the #SoupAuth
+ * that previously failed (or %NULL if the previous attempt was
+ * unauthenticated), not the #SoupAuth that is currently being
+ * authenticated.
+ *
+ * Return value: (transfer none): the #SoupAuth used by @msg for
+ * authentication, or %NULL if @msg is unauthenticated.
+ *
+ * Since: 2.46
+ **/
 SoupAuth *
 soup_message_get_auth (SoupMessage *msg)
 {
@@ -1309,6 +1410,24 @@ soup_message_get_auth (SoupMessage *msg)
        return SOUP_MESSAGE_GET_PRIVATE (msg)->auth;
 }
 
+/**
+ * soup_message_set_proxy_auth:
+ * @msg: a #SoupMessage
+ * @auth: a #SoupAuth, or %NULL
+ *
+ * Sets @msg to authenticate to its proxy using @auth, which must have
+ * already been fully authenticated. If @auth is %NULL, @msg will not
+ * authenticate to its proxy.
+ *
+ * As with soup_message_set_auth(), note that the #SoupSession will
+ * overwrite this before sending the message if it believes that a
+ * different #SoupAuth is the correct one to be using. This method is
+ * primarily useful if you want to force the use of Basic auth on a
+ * request before having seen a 407 Proxy Authentication Required
+ * response.
+ *
+ * Since: 2.46
+ **/
 void
 soup_message_set_proxy_auth (SoupMessage *msg, SoupAuth *auth)
 {
@@ -1320,22 +1439,36 @@ soup_message_set_proxy_auth (SoupMessage *msg, SoupAuth *auth)
 
        priv = SOUP_MESSAGE_GET_PRIVATE (msg);
 
+       if (auth != priv->proxy_auth) {
+               if (priv->proxy_auth)
+                       g_object_unref (priv->proxy_auth);
+               priv->proxy_auth = auth;
+               if (priv->proxy_auth)
+                       g_object_ref (priv->proxy_auth);
+       }
+
        if (priv->proxy_auth) {
-               g_object_unref (priv->proxy_auth);
+               token = soup_auth_get_authorization (auth, msg);
+               soup_message_headers_replace (msg->request_headers,
+                                             "Proxy-Authorization", token);
+               g_free (token);
+       } else {
                soup_message_headers_remove (msg->request_headers,
                                             "Proxy-Authorization");
        }
-       priv->proxy_auth = auth;
-       if (!priv->proxy_auth)
-               return;
-
-       g_object_ref (priv->proxy_auth);
-       token = soup_auth_get_authorization (auth, msg);
-       soup_message_headers_replace (msg->request_headers,
-                                     "Proxy-Authorization", token);
-       g_free (token);
 }
 
+/**
+ * soup_message_get_proxy_auth:
+ * @msg: a #SoupMessage
+ *
+ * Gets the #SoupAuth used by @msg for authentication to its proxy..
+ *
+ * Return value: the #SoupAuth used by @msg for authentication to its
+ * proxy, or %NULL if @msg isn't authenticated to its proxy.
+ *
+ * Since: 2.46
+ **/
 SoupAuth *
 soup_message_get_proxy_auth (SoupMessage *msg)
 {
diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h
index b02d293..0df0e0d 100644
--- a/libsoup/soup-message.h
+++ b/libsoup/soup-message.h
@@ -77,6 +77,8 @@ GType soup_message_get_type (void);
 #define SOUP_MESSAGE_TLS_CERTIFICATE    "tls-certificate"
 #define SOUP_MESSAGE_TLS_ERRORS         "tls-errors"
 #define SOUP_MESSAGE_PRIORITY           "priority"
+#define SOUP_MESSAGE_AUTH               "auth"
+#define SOUP_MESSAGE_PROXY_AUTH         "proxy-auth"
 
 SoupMessage   *soup_message_new                 (const char        *method,
                                                 const char        *uri_string);
@@ -206,6 +208,20 @@ void                soup_message_set_priority   (SoupMessage        *msg,
 SOUP_AVAILABLE_IN_2_44
 SoupMessagePriority soup_message_get_priority   (SoupMessage        *msg);
 
+
+/* Auth handling */
+SOUP_AVAILABLE_IN_2_46
+void           soup_message_set_auth       (SoupMessage *msg,
+                                           SoupAuth    *auth);
+SOUP_AVAILABLE_IN_2_46
+SoupAuth      *soup_message_get_auth       (SoupMessage *msg);
+SOUP_AVAILABLE_IN_2_46
+void           soup_message_set_proxy_auth (SoupMessage *msg,
+                                           SoupAuth    *auth);
+SOUP_AVAILABLE_IN_2_46
+SoupAuth      *soup_message_get_proxy_auth (SoupMessage *msg);
+
+
 void soup_message_wrote_informational (SoupMessage *msg);
 void soup_message_wrote_headers       (SoupMessage *msg);
 void soup_message_wrote_chunk         (SoupMessage *msg);
diff --git a/tests/auth-test.c b/tests/auth-test.c
index 8ed5cea..3e49d2a 100644
--- a/tests/auth-test.c
+++ b/tests/auth-test.c
@@ -1162,6 +1162,62 @@ do_disappearing_auth_test (void)
        soup_test_server_quit_unref (server);
 }
 
+static void
+preauth_authenticate (SoupSession *session, SoupMessage *msg,
+                     SoupAuth *auth, gboolean retrying, gpointer data)
+{
+       gboolean *authenticated = data;
+
+       g_assert_false (*authenticated);
+
+       *authenticated = TRUE;
+       soup_auth_authenticate (auth, "user1", "realm1");
+}
+
+static void
+do_preauth_test (void)
+{
+       SoupSession *session;
+       SoupMessage *msg;
+       SoupAuth *auth;
+       char *uri;
+       gboolean authenticated;
+
+       session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
+       g_signal_connect (session, "authenticate",
+                         G_CALLBACK (preauth_authenticate),
+                         &authenticated);
+       uri = g_strconcat (base_uri, "Basic/realm1/", NULL);
+
+       /* Test with right password */
+       msg = soup_message_new (SOUP_METHOD_GET, uri);
+       auth = soup_auth_new (SOUP_TYPE_AUTH_BASIC, msg, "Basic realm=\"realm1\"");
+       soup_auth_authenticate (auth, "user1", "realm1");
+       soup_message_set_auth (msg, auth);
+       g_object_unref (auth);
+
+       authenticated = FALSE;
+       soup_session_send_message (session, msg);
+       g_assert_false (authenticated);
+       soup_test_assert_message_status (msg, SOUP_STATUS_OK);
+       g_object_unref (msg);
+
+       /* Test with wrong password */
+       msg = soup_message_new (SOUP_METHOD_GET, uri);
+       auth = soup_auth_new (SOUP_TYPE_AUTH_BASIC, msg, "Basic realm=\"realm1\"");
+       soup_auth_authenticate (auth, "user1", "wrong");
+       soup_message_set_auth (msg, auth);
+       g_object_unref (auth);
+
+       authenticated = FALSE;
+       soup_session_send_message (session, msg);
+       g_assert_true (authenticated);
+       soup_test_assert_message_status (msg, SOUP_STATUS_OK);
+       g_object_unref (msg);
+
+       g_free (uri);
+}
+
 static SoupAuthTest relogin_tests[] = {
        { "Auth provided via URL, should succeed",
          "Basic/realm12/", "1", TRUE, "01", SOUP_STATUS_OK },
@@ -1278,6 +1334,7 @@ main (int argc, char **argv)
        g_test_add_func ("/auth/auth-close", do_auth_close_test);
        g_test_add_func ("/auth/infinite-auth", do_infinite_auth_test);
        g_test_add_func ("/auth/disappearing-auth", do_disappearing_auth_test);
+       g_test_add_func ("/auth/preauth", do_preauth_test);
 
        ret = g_test_run ();
 


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