Blob Blame History Raw
From a660e5650d0f460810ea75c44d044b6924659f59 Mon Sep 17 00:00:00 2001
From: Jonathan Lebon <jlebon@redhat.com>
Date: Fri, 14 Oct 2016 09:25:01 -0400
Subject: [PATCH] OstreeFetcher: provide proxy credentials if needed

There seems to be an issue in libsoup which causes basic auth
credentials to not be passed to the proxy during requests. We thus have
to handle PROXY_UNAUTHORIZED responses and provide the auth ourselves.

Related: https://bugzilla.redhat.com/show_bug.cgi?id=1370558
Related: https://bugzilla.gnome.org/show_bug.cgi?id=772932

Closes: #529
Approved by: cgwalters
---
 src/libostree/ostree-fetcher.c | 60 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 56 insertions(+), 4 deletions(-)

diff --git a/src/libostree/ostree-fetcher.c b/src/libostree/ostree-fetcher.c
index 3ddf238..c2dc8ea 100644
--- a/src/libostree/ostree-fetcher.c
+++ b/src/libostree/ostree-fetcher.c
@@ -65,6 +65,9 @@ typedef struct {
 
   /* Also protected by output_stream_set_lock. */
   guint64 total_downloaded;
+
+  GError *oob_error;
+
 } ThreadClosure;
 
 static void
@@ -159,6 +162,8 @@ thread_closure_unref (ThreadClosure *thread_closure)
       g_clear_pointer (&thread_closure->output_stream_set, g_hash_table_unref);
       g_mutex_clear (&thread_closure->output_stream_set_lock);
 
+      g_clear_pointer (&thread_closure->oob_error, g_error_free);
+
       g_slice_free (ThreadClosure, thread_closure);
     }
 }
@@ -276,6 +281,29 @@ session_thread_config_flags (ThreadClosure *thread_closure,
     }
 }
 
+static void
+on_authenticate (SoupSession *session, SoupMessage *msg, SoupAuth *auth,
+                 gboolean retrying, gpointer user_data)
+{
+  ThreadClosure *thread_closure = user_data;
+
+  if (msg->status_code == SOUP_STATUS_PROXY_UNAUTHORIZED)
+    {
+      SoupURI *uri = NULL;
+      g_object_get (session, SOUP_SESSION_PROXY_URI, &uri, NULL);
+      if (retrying)
+        {
+          g_autofree char *s = soup_uri_to_string (uri, FALSE);
+          g_set_error (&thread_closure->oob_error,
+                       G_IO_ERROR, G_IO_ERROR_PROXY_AUTH_FAILED,
+                       "Invalid username or password for proxy '%s'", s);
+        }
+      else
+        soup_auth_authenticate (auth, soup_uri_get_user (uri),
+                                      soup_uri_get_password (uri));
+    }
+}
+
 static void
 session_thread_set_proxy_cb (ThreadClosure *thread_closure,
                              gpointer data)
@@ -285,6 +313,17 @@ session_thread_set_proxy_cb (ThreadClosure *thread_closure,
   g_object_set (thread_closure->session,
                 SOUP_SESSION_PROXY_URI,
                 proxy_uri, NULL);
+
+  /* libsoup won't necessarily pass any embedded username and password to proxy
+   * requests, so we have to be ready to handle 407 and handle them ourselves.
+   * See also: https://bugzilla.gnome.org/show_bug.cgi?id=772932
+   * */
+  if (soup_uri_get_user (proxy_uri) &&
+      soup_uri_get_password (proxy_uri))
+    {
+      g_signal_connect (thread_closure->session, "authenticate",
+                        G_CALLBACK (on_authenticate), thread_closure);
+    }
 }
 
 #ifdef HAVE_LIBSOUP_CLIENT_CERTS
@@ -998,10 +1037,23 @@ on_request_sent (GObject        *object,
                   code = G_IO_ERROR_FAILED;
                 }
 
-              local_error = g_error_new (G_IO_ERROR, code,
-                                         "Server returned status %u: %s",
-                                         msg->status_code,
-                                         soup_status_get_phrase (msg->status_code));
+              {
+                g_autofree char *errmsg =
+                  g_strdup_printf ("Server returned status %u: %s",
+                                   msg->status_code,
+                                   soup_status_get_phrase (msg->status_code));
+
+                /* Let's make OOB errors be the final one since they're probably
+                 * the cause for the error here. */
+                if (pending->thread_closure->oob_error)
+                  {
+                    local_error =
+                      g_error_copy (pending->thread_closure->oob_error);
+                    g_prefix_error (&local_error, "%s: ", errmsg);
+                  }
+                else
+                  local_error = g_error_new_literal (G_IO_ERROR, code, errmsg);
+              }
 
               if (pending->mirrorlist->len > 1)
                 g_prefix_error (&local_error,
-- 
2.10.1