add "realm" field to the struct. (SoupAuthClass) remove "get_realm"
authorDan Winship <danw@src.gnome.org>
Tue, 25 Sep 2007 03:11:18 +0000 (03:11 +0000)
committerDan Winship <danw@src.gnome.org>
Tue, 25 Sep 2007 03:11:18 +0000 (03:11 +0000)
* libsoup/soup-auth.h (SoupAuth): add "realm" field to the struct.
(SoupAuthClass) remove "get_realm" virtual method.

* libsoup/soup-auth.c (soup_auth_new_from_header_list): Parse the
WWW-Authenticate/Proxy-Authenticate header here, set realm, and
pass the params hash to the construct method.
(soup_auth_get_info): Return an identifier for the auth:
"SCHEME:REALM"

* libsoup/soup-auth-basic.c:
* libsoup/soup-auth-digest.c: update

* libsoup/soup-session.c (invalidate_auth, update_auth_internal):
use soup_auth_get_info().

svn path=/trunk/; revision=934

ChangeLog
libsoup/soup-auth-basic.c
libsoup/soup-auth-digest.c
libsoup/soup-auth.c
libsoup/soup-auth.h
libsoup/soup-session.c

index 8e3c018..84d5aeb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,22 @@
 2007-09-24  Dan Winship  <danw@gnome.org>
 
+       * libsoup/soup-auth.h (SoupAuth): add "realm" field to the struct.
+       (SoupAuthClass) remove "get_realm" virtual method.
+
+       * libsoup/soup-auth.c (soup_auth_new_from_header_list): Parse the
+       WWW-Authenticate/Proxy-Authenticate header here, set realm, and
+       pass the params hash to the construct method.
+       (soup_auth_get_info): Return an identifier for the auth:
+       "SCHEME:REALM"
+
+       * libsoup/soup-auth-basic.c:
+       * libsoup/soup-auth-digest.c: update
+
+       * libsoup/soup-session.c (invalidate_auth, update_auth_internal):
+       use soup_auth_get_info().
+
+2007-09-24  Dan Winship  <danw@gnome.org>
+
        * libsoup/soup-date.c (soup_date_parse): minor rfc850-date parsing
        improvement suggested by RFC2616 19.3.
 
index 235b7f3..003bda6 100644 (file)
 #include "soup-misc.h"
 #include "soup-uri.h"
 
-static void construct (SoupAuth *auth, const char *header);
+static void construct (SoupAuth *auth, GHashTable *auth_params);
 static GSList *get_protection_space (SoupAuth *auth, const SoupUri *source_uri);
-static const char *get_realm (SoupAuth *auth);
 static void authenticate (SoupAuth *auth, const char *username, const char *password);
 static gboolean is_authenticated (SoupAuth *auth);
 static char *get_authorization (SoupAuth *auth, SoupMessage *msg);
 
 typedef struct {
-       char *realm, *token;
+       char *token;
 } SoupAuthBasicPrivate;
 #define SOUP_AUTH_BASIC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_AUTH_BASIC, SoupAuthBasicPrivate))
 
@@ -41,7 +40,6 @@ finalize (GObject *object)
 {
        SoupAuthBasicPrivate *priv = SOUP_AUTH_BASIC_GET_PRIVATE (object);
 
-       g_free (priv->realm);
        g_free (priv->token);
 
        G_OBJECT_CLASS (soup_auth_basic_parent_class)->finalize (object);
@@ -59,7 +57,6 @@ soup_auth_basic_class_init (SoupAuthBasicClass *auth_basic_class)
 
        auth_class->construct = construct;
        auth_class->get_protection_space = get_protection_space;
-       auth_class->get_realm = get_realm;
        auth_class->authenticate = authenticate;
        auth_class->is_authenticated = is_authenticated;
        auth_class->get_authorization = get_authorization;
@@ -69,19 +66,9 @@ soup_auth_basic_class_init (SoupAuthBasicClass *auth_basic_class)
 
 
 static void
-construct (SoupAuth *auth, const char *header)
+construct (SoupAuth *auth, GHashTable *auth_params)
 {
-       SoupAuthBasicPrivate *priv = SOUP_AUTH_BASIC_GET_PRIVATE (auth);
-       GHashTable *tokens;
-
-       header += sizeof ("Basic");
-
-       tokens = soup_header_param_parse_list (header);
-       if (!tokens)
-               return;
-
-       priv->realm = soup_header_param_copy_token (tokens, "realm");
-       soup_header_param_destroy_hash (tokens);
+       ;
 }
 
 static GSList *
@@ -99,12 +86,6 @@ get_protection_space (SoupAuth *auth, const SoupUri *source_uri)
        return g_slist_prepend (NULL, space);
 }
 
-static const char *
-get_realm (SoupAuth *auth)
-{
-       return SOUP_AUTH_BASIC_GET_PRIVATE (auth)->realm;
-}
-
 static void
 authenticate (SoupAuth *auth, const char *username, const char *password)
 {
index 6b91147..3841e98 100644 (file)
@@ -21,9 +21,8 @@
 #include "soup-misc.h"
 #include "soup-uri.h"
 
-static void construct (SoupAuth *auth, const char *header);
+static void construct (SoupAuth *auth, GHashTable *auth_params);
 static GSList *get_protection_space (SoupAuth *auth, const SoupUri *source_uri);
-static const char *get_realm (SoupAuth *auth);
 static void authenticate (SoupAuth *auth, const char *username, const char *password);
 static gboolean is_authenticated (SoupAuth *auth);
 static char *get_authorization (SoupAuth *auth, SoupMessage *msg);
@@ -44,7 +43,6 @@ typedef struct {
        char           hex_a1[33];
 
        /* These are provided by the server */
-       char          *realm;
        char          *nonce;
        QOPType        qop_options;
        AlgorithmType  algorithm;
@@ -71,8 +69,6 @@ finalize (GObject *object)
 
        if (priv->user)
                g_free (priv->user);
-       if (priv->realm)
-               g_free (priv->realm);
        if (priv->nonce)
                g_free (priv->nonce);
        if (priv->domain)
@@ -94,7 +90,6 @@ soup_auth_digest_class_init (SoupAuthDigestClass *auth_digest_class)
        auth_class->scheme_name = "Digest";
 
        auth_class->get_protection_space = get_protection_space;
-       auth_class->get_realm = get_realm;
        auth_class->construct = construct;
        auth_class->authenticate = authenticate;
        auth_class->is_authenticated = is_authenticated;
@@ -149,27 +144,19 @@ decode_algorithm (const char *name)
 }
 
 static void
-construct (SoupAuth *auth, const char *header)
+construct (SoupAuth *auth, GHashTable *auth_params)
 {
        SoupAuthDigestPrivate *priv = SOUP_AUTH_DIGEST_GET_PRIVATE (auth);
-       GHashTable *tokens;
        char *tmp, *ptr;
 
-       header += sizeof ("Digest");
-
-       tokens = soup_header_param_parse_list (header);
-       if (!tokens)
-               return;
-
        priv->nc = 1;
        /* We're just going to do qop=auth for now */
        priv->qop = QOP_AUTH;
 
-       priv->realm = soup_header_param_copy_token (tokens, "realm");
-       priv->domain = soup_header_param_copy_token (tokens, "domain");
-       priv->nonce = soup_header_param_copy_token (tokens, "nonce");
+       priv->domain = soup_header_param_copy_token (auth_params, "domain");
+       priv->nonce = soup_header_param_copy_token (auth_params, "nonce");
 
-       tmp = soup_header_param_copy_token (tokens, "qop");
+       tmp = soup_header_param_copy_token (auth_params, "qop");
        ptr = tmp;
 
        while (ptr && *ptr) {
@@ -185,11 +172,9 @@ construct (SoupAuth *auth, const char *header)
        }
        g_free (tmp);
 
-       tmp = soup_header_param_copy_token (tokens, "algorithm");
+       tmp = soup_header_param_copy_token (auth_params, "algorithm");
        priv->algorithm = decode_algorithm (tmp);
        g_free (tmp);
-
-       soup_header_param_destroy_hash (tokens);
 }
 
 static GSList *
@@ -238,12 +223,6 @@ get_protection_space (SoupAuth *auth, const SoupUri *source_uri)
        return space;
 }
 
-static const char *
-get_realm (SoupAuth *auth)
-{
-       return SOUP_AUTH_DIGEST_GET_PRIVATE (auth)->realm;
-}
-
 static void
 authenticate (SoupAuth *auth, const char *username, const char *password)
 {
@@ -269,11 +248,7 @@ authenticate (SoupAuth *auth, const char *username, const char *password)
        soup_md5_update (&ctx, username, strlen (username));
 
        soup_md5_update (&ctx, ":", 1);
-       if (priv->realm) {
-               soup_md5_update (&ctx, priv->realm,
-                                strlen (priv->realm));
-       }
-
+       soup_md5_update (&ctx, auth->realm, strlen (auth->realm));
        soup_md5_update (&ctx, ":", 1);
        if (password)
                soup_md5_update (&ctx, password, strlen (password));
@@ -397,7 +372,7 @@ get_authorization (SoupAuth *auth, SoupMessage *msg)
                "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", %s%s%s "
                "%s%s%s %s%s%s uri=\"%s\", response=\"%s\"",
                priv->user,
-               priv->realm,
+               auth->realm,
                priv->nonce,
 
                priv->qop ? "cnonce=\"" : "",
index 5c7ac8d..51ad491 100644 (file)
 #include "soup-auth.h"
 #include "soup-auth-basic.h"
 #include "soup-auth-digest.h"
+#include "soup-headers.h"
 
 G_DEFINE_TYPE (SoupAuth, soup_auth, G_TYPE_OBJECT)
 
 static void
+finalize (GObject *object)
+{
+       SoupAuth *auth = SOUP_AUTH (object);
+
+       g_free (auth->realm);
+
+       G_OBJECT_CLASS (soup_auth_parent_class)->finalize (object);
+}
+
+static void
 soup_auth_class_init (SoupAuthClass *auth_class)
 {
+       GObjectClass *object_class = G_OBJECT_CLASS (auth_class);
+
+       object_class->finalize = finalize;
 }
 
 static void
@@ -27,15 +41,18 @@ soup_auth_init (SoupAuth *auth)
 {
 }
 
+typedef GType (*GTypeFunc) (void);
+
 typedef struct {
-       const char  *scheme;
-       GType      (*type_func) (void);
-       int          strength;
+       const char *name;
+       int         len;
+       GTypeFunc   type_func;
+       int         strength;
 } AuthScheme; 
 
 static AuthScheme known_auth_schemes [] = {
-       { "Basic",  soup_auth_basic_get_type,  0 },
-       { "Digest", soup_auth_digest_get_type, 3 },
+       { "Basic",  sizeof ("Basic") - 1,  soup_auth_basic_get_type,  0 },
+       { "Digest", sizeof ("Digest") - 1, soup_auth_digest_get_type, 3 },
        { NULL }
 };
 
@@ -53,18 +70,21 @@ static AuthScheme known_auth_schemes [] = {
 SoupAuth *
 soup_auth_new_from_header_list (const GSList *vals)
 {
-       char *header = NULL;
+       char *header = NULL, *realm;
        AuthScheme *scheme = NULL, *iter;
        SoupAuth *auth = NULL;
+       GHashTable *params;
 
        g_return_val_if_fail (vals != NULL, NULL);
 
        while (vals) {
                char *tryheader = vals->data;
 
-               for (iter = known_auth_schemes; iter->scheme; iter++) {
-                       if (!g_ascii_strncasecmp (tryheader, iter->scheme, 
-                                           strlen (iter->scheme))) {
+               for (iter = known_auth_schemes; iter->name; iter++) {
+                       if (!g_ascii_strncasecmp (tryheader, iter->name, 
+                                                 iter->len) &&
+                           (!tryheader[iter->len] ||
+                            g_ascii_isspace (tryheader[iter->len]))) {
                                if (!scheme || 
                                    scheme->strength < iter->strength) {
                                        header = tryheader;
@@ -81,16 +101,20 @@ soup_auth_new_from_header_list (const GSList *vals)
        if (!scheme)
                return NULL;
 
-       auth = g_object_new (scheme->type_func (), NULL);
-       if (!auth)
+       params = soup_header_param_parse_list (header + scheme->len);
+       if (!params)
                return NULL;
-
-       SOUP_AUTH_GET_CLASS (auth)->construct (auth, header);
-       if (!soup_auth_get_realm (auth)) {
-               g_object_unref (auth);
+       realm = soup_header_param_copy_token (params, "realm");
+       if (!realm) {
+               soup_header_param_destroy_hash (params);
                return NULL;
        }
 
+       auth = g_object_new (scheme->type_func (), NULL);
+       auth->realm = realm;
+
+       SOUP_AUTH_GET_CLASS (auth)->construct (auth, params);
+       soup_header_param_destroy_hash (params);
        return auth;
 }
 
@@ -143,7 +167,28 @@ soup_auth_get_realm (SoupAuth *auth)
 {
        g_return_val_if_fail (SOUP_IS_AUTH (auth), NULL);
 
-       return SOUP_AUTH_GET_CLASS (auth)->get_realm (auth);
+       return auth->realm;
+}
+
+/**
+ * soup_auth_get_info:
+ * @auth: a #SoupAuth
+ *
+ * Gets an identifier for @auth. #SoupAuth objects from the same
+ * server with the same identifier refer to the same authentication
+ * domain (eg, the URLs associated with them take the same usernames
+ * and passwords).
+ *
+ * Return value: the identifier
+ **/
+char *
+soup_auth_get_info (SoupAuth *auth)
+{
+       g_return_val_if_fail (SOUP_IS_AUTH (auth), NULL);
+
+       return g_strdup_printf ("%s:%s",
+                               SOUP_AUTH_GET_CLASS (auth)->scheme_name,
+                               auth->realm);
 }
 
 /**
index be49573..0feda0c 100644 (file)
@@ -18,6 +18,7 @@
 typedef struct {
        GObject parent;
 
+       char *realm;
 } SoupAuth;
 
 typedef struct {
@@ -26,13 +27,11 @@ typedef struct {
        const char *scheme_name;
 
        void         (*construct)            (SoupAuth      *auth,
-                                             const char    *header);
+                                             GHashTable    *auth_params);
 
        GSList *     (*get_protection_space) (SoupAuth      *auth,
                                              const SoupUri *source_uri);
 
-       const char * (*get_realm)            (SoupAuth      *auth);
-
        void         (*authenticate)         (SoupAuth      *auth,
                                              const char    *username,
                                              const char    *password);
@@ -49,6 +48,7 @@ SoupAuth   *soup_auth_new_from_header_list  (const GSList  *vals);
 
 const char *soup_auth_get_scheme_name       (SoupAuth      *auth);
 const char *soup_auth_get_realm             (SoupAuth      *auth);
+char       *soup_auth_get_info              (SoupAuth      *auth);
 
 void        soup_auth_authenticate          (SoupAuth      *auth,
                                             const char    *username,
index 5c35d40..ef4a412 100644 (file)
@@ -692,20 +692,17 @@ lookup_auth (SoupSession *session, SoupMessage *msg, gboolean proxy)
 static void
 invalidate_auth (SoupSessionHost *host, SoupAuth *auth)
 {
-       char *realm;
+       char *info;
        gpointer key, value;
 
-       realm = g_strdup_printf ("%s:%s",
-                                soup_auth_get_scheme_name (auth),
-                                soup_auth_get_realm (auth));
-
-       if (g_hash_table_lookup_extended (host->auths, realm, &key, &value) &&
+       info = soup_auth_get_info (auth);
+       if (g_hash_table_lookup_extended (host->auths, info, &key, &value) &&
            auth == (SoupAuth *)value) {
-               g_hash_table_remove (host->auths, realm);
+               g_hash_table_remove (host->auths, info);
                g_free (key);
                g_object_unref (auth);
        }
-       g_free (realm);
+       g_free (info);
 }
 
 static gboolean
@@ -749,10 +746,10 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
 {
        SoupSessionHost *host;
        SoupAuth *new_auth, *prior_auth, *old_auth;
-       gpointer old_path, old_realm;
+       gpointer old_path, old_auth_info;
        const SoupUri *msg_uri;
        const char *path;
-       char *realm;
+       char *auth_info;
        GSList *pspace, *p;
        gboolean prior_auth_failed = FALSE;
 
@@ -771,17 +768,21 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
        if (!new_auth)
                return FALSE;
 
+       auth_info = soup_auth_get_info (new_auth);
+
        /* See if this auth is the same auth we used last time */
        prior_auth = proxy ? soup_message_get_proxy_auth (msg) : soup_message_get_auth (msg);
-       if (prior_auth &&
-           G_OBJECT_TYPE (prior_auth) == G_OBJECT_TYPE (new_auth) &&
-           !strcmp (soup_auth_get_realm (prior_auth),
-                    soup_auth_get_realm (new_auth))) {
-               /* The server didn't like the username/password we
-                * provided before. Invalidate it and note this fact.
-                */
-               invalidate_auth (host, prior_auth);
-               prior_auth_failed = TRUE;
+       if (prior_auth) {
+               char *old_auth_info = soup_auth_get_info (prior_auth);
+
+               if (!strcmp (old_auth_info, auth_info)) {
+                       /* The server didn't like the username/password we
+                        * provided before. Invalidate it and note this fact.
+                        */
+                       invalidate_auth (host, prior_auth);
+                       prior_auth_failed = TRUE;
+               }
+               g_free (old_auth_info);
        }
 
        if (!host->auth_realms) {
@@ -789,18 +790,13 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
                host->auths = g_hash_table_new (g_str_hash, g_str_equal);
        }
 
-       /* Record where this auth realm is used */
-       realm = g_strdup_printf ("%s:%s",
-                                soup_auth_get_scheme_name (new_auth),
-                                soup_auth_get_realm (new_auth));
-
-       /* 
-        * RFC 2617 is somewhat unclear about the scope of protection
-        * spaces with regard to proxies.  The only mention of it is
-        * as an aside in section 3.2.1, where it is defining the fields
-        * of a Digest challenge and says that the protection space is
-        * always the entire proxy.  Is this the case for all authentication
-        * schemes or just Digest?  Who knows, but we're assuming all.
+       /* Record where this auth realm is used. RFC 2617 is somewhat
+        * unclear about the scope of protection spaces with regard to
+        * proxies. The only mention of it is as an aside in section
+        * 3.2.1, where it is defining the fields of a Digest
+        * challenge and says that the protection space is always the
+        * entire proxy. Is this the case for all authentication
+        * schemes or just Digest? Who knows, but we're assuming all.
         */
        if (proxy)
                pspace = g_slist_prepend (NULL, g_strdup (""));
@@ -810,14 +806,14 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
        for (p = pspace; p; p = p->next) {
                path = p->data;
                if (g_hash_table_lookup_extended (host->auth_realms, path,
-                                                 &old_path, &old_realm)) {
+                                                 &old_path, &old_auth_info)) {
                        g_hash_table_remove (host->auth_realms, old_path);
                        g_free (old_path);
-                       g_free (old_realm);
+                       g_free (old_auth_info);
                }
 
                g_hash_table_insert (host->auth_realms,
-                                    g_strdup (path), g_strdup (realm));
+                                    g_strdup (path), g_strdup (auth_info));
        }
        soup_auth_free_protection_space (new_auth, pspace);
 
@@ -825,13 +821,13 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
         * pre-existing auth, we keep that rather than the new one,
         * since the old one might already be authenticated.)
         */
-       old_auth = g_hash_table_lookup (host->auths, realm);
+       old_auth = g_hash_table_lookup (host->auths, auth_info);
        if (old_auth) {
-               g_free (realm);
+               g_free (auth_info);
                g_object_unref (new_auth);
                new_auth = old_auth;
        } else 
-               g_hash_table_insert (host->auths, realm, new_auth);
+               g_hash_table_insert (host->auths, auth_info, new_auth);
 
        /* If we need to authenticate, try to do it. */
        if (!soup_auth_is_authenticated (new_auth)) {