[gnome-online-accounts/wip/rishi/owncloud-gssapi: 10/10] owncloud: Support GSSAPI/Negotiate authentication



commit 0df95ae237668d28a96d7c2fccfc9ae4ee8eb4fa
Author: Debarshi Ray <debarshir gnome org>
Date:   Sat Feb 20 21:49:44 2016 +0100

    owncloud: Support GSSAPI/Negotiate authentication
    
    https://bugzilla.gnome.org/show_bug.cgi?id=762097

 src/goabackend/goaowncloudprovider.c |  273 ++++++++++++++++++++++++++++------
 1 files changed, 229 insertions(+), 44 deletions(-)
---
diff --git a/src/goabackend/goaowncloudprovider.c b/src/goabackend/goaowncloudprovider.c
index c95f0fe..58e6762 100644
--- a/src/goabackend/goaowncloudprovider.c
+++ b/src/goabackend/goaowncloudprovider.c
@@ -155,6 +155,7 @@ build_object (GoaProvider         *provider,
   gboolean contacts_enabled;
   gboolean documents_enabled;
   gboolean files_enabled;
+  gboolean gssapi_enabled;
   gboolean ret;
   const gchar *identity;
   gchar *uri_string;
@@ -176,18 +177,27 @@ build_object (GoaProvider         *provider,
                                                                               error))
     goto out;
 
+  gssapi_enabled = g_key_file_get_boolean (key_file, group, "XXX-GssApiEnabled", NULL);
   password_based = goa_object_get_password_based (GOA_OBJECT (object));
-  if (password_based == NULL)
+  if (gssapi_enabled)
     {
-      password_based = goa_password_based_skeleton_new ();
-      /* Ensure D-Bus method invocations run in their own thread */
-      g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (password_based),
-                                           
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
-      goa_object_skeleton_set_password_based (object, password_based);
-      g_signal_connect (password_based,
-                        "handle-get-password",
-                        G_CALLBACK (on_handle_get_password),
-                        NULL);
+      if (password_based != NULL)
+        goa_object_skeleton_set_password_based (object, NULL);
+    }
+  else
+    {
+      if (password_based == NULL)
+        {
+          password_based = goa_password_based_skeleton_new ();
+          /* Ensure D-Bus method invocations run in their own thread */
+          g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (password_based),
+                                               
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
+          goa_object_skeleton_set_password_based (object, password_based);
+          g_signal_connect (password_based,
+                            "handle-get-password",
+                            G_CALLBACK (on_handle_get_password),
+                            NULL);
+        }
     }
 
   account = goa_object_get_account (GOA_OBJECT (object));
@@ -265,6 +275,7 @@ ensure_credentials_sync (GoaProvider         *provider,
                          GError             **error)
 {
   GoaHttpClient *http_client;
+  GoaPasswordBased *password_based;
   gboolean accept_ssl_errors;
   gboolean ret;
   gchar *username;
@@ -273,6 +284,7 @@ ensure_credentials_sync (GoaProvider         *provider,
   gchar *uri_webdav;
 
   http_client = NULL;
+  password_based = NULL;
   password = NULL;
   uri = NULL;
   uri_webdav = NULL;
@@ -280,14 +292,18 @@ ensure_credentials_sync (GoaProvider         *provider,
 
   ret = FALSE;
 
-  if (!goa_utils_get_credentials (provider, object, "password", &username, &password, cancellable, error))
+  password_based = goa_object_get_password_based (GOA_OBJECT (object));
+  if (password_based != NULL)
     {
-      if (error != NULL)
+      if (!goa_utils_get_credentials (provider, object, "password", &username, &password, cancellable, 
error))
         {
-          (*error)->domain = GOA_ERROR;
-          (*error)->code = GOA_ERROR_NOT_AUTHORIZED;
+          if (error != NULL)
+            {
+              (*error)->domain = GOA_ERROR;
+              (*error)->code = GOA_ERROR_NOT_AUTHORIZED;
+            }
+          goto out;
         }
-      goto out;
     }
 
   accept_ssl_errors = goa_util_lookup_keyfile_boolean (object, "AcceptSslErrors");
@@ -326,6 +342,7 @@ ensure_credentials_sync (GoaProvider         *provider,
 
  out:
   g_clear_object (&http_client);
+  g_clear_object (&password_based);
   g_free (username);
   g_free (password);
   g_free (uri);
@@ -339,6 +356,8 @@ static void
 add_entry (GtkWidget     *grid,
            gint           row,
            const gchar   *text,
+           gboolean       show,
+           GtkWidget    **out_label,
            GtkWidget    **out_entry)
 {
   GtkStyleContext *context;
@@ -350,16 +369,21 @@ add_entry (GtkWidget     *grid,
   gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL);
   gtk_widget_set_halign (label, GTK_ALIGN_END);
   gtk_widget_set_hexpand (label, TRUE);
+  gtk_widget_set_sensitive (label, show);
   gtk_grid_attach (GTK_GRID (grid), label, 0, row, 1, 1);
 
   entry = gtk_entry_new ();
   gtk_widget_set_hexpand (entry, TRUE);
+  gtk_widget_set_sensitive (entry, show);
   gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
   gtk_grid_attach (GTK_GRID (grid), entry, 1, row, 3, 1);
 
   gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
+
   if (out_entry != NULL)
     *out_entry = entry;
+  if (out_label != NULL)
+    *out_label = label;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -367,6 +391,7 @@ add_entry (GtkWidget     *grid,
 typedef struct
 {
   GCancellable *check_cancellable;
+  GCancellable *detect_cancellable;
 
   GtkDialog *dialog;
   GMainLoop *loop;
@@ -378,9 +403,12 @@ typedef struct
 
   GtkWidget *uri;
   GtkWidget *username;
+  GtkWidget *username_label;
   GtkWidget *password;
+  GtkWidget *password_label;
 
   gchar *account_object_path;
+  gint changed_id;
 
   GError *error;
 } AddAccountData;
@@ -473,27 +501,14 @@ normalize_uri (const gchar *address, gchar **server)
 }
 
 static void
-on_uri_username_or_password_changed (GtkEditable *editable, gpointer user_data)
+update_row_ui (GtkWidget *label, gboolean show)
 {
-  AddAccountData *data = user_data;
-  gboolean can_add;
-  const gchar *address;
-  gchar *uri;
+  GtkWidget *entry;
 
-  can_add = FALSE;
-  uri = NULL;
+  gtk_widget_set_sensitive (label, show);
 
-  address = gtk_entry_get_text (GTK_ENTRY (data->uri));
-  uri = normalize_uri (address, NULL);
-  if (uri == NULL)
-    goto out;
-
-  can_add = gtk_entry_get_text_length (GTK_ENTRY (data->username)) != 0
-            && gtk_entry_get_text_length (GTK_ENTRY (data->password)) != 0;
-
- out:
-  gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, can_add);
-  g_free (uri);
+  entry = gtk_label_get_mnemonic_widget (GTK_LABEL (label));
+  gtk_widget_set_sensitive (entry, show);
 }
 
 static void
@@ -516,6 +531,158 @@ show_progress_ui (GtkContainer *container, gboolean progress)
 }
 
 static void
+detect_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+  AddAccountData *data = user_data;
+  GoaHttpClient *client = GOA_HTTP_CLIENT (source_object);
+  GError *error;
+  gboolean enable_ok = FALSE;
+  gboolean enable_username_password = FALSE;
+  gboolean has_username_password = FALSE;
+  const gchar *error_msg = NULL;
+  gchar *auth = NULL;
+
+  error = NULL;
+  auth = goa_http_client_detect_finish (client, res, &error);
+  if (error != NULL)
+    {
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        {
+          g_error_free (error);
+          return;
+        }
+
+      if (g_error_matches (error, GOA_ERROR, GOA_ERROR_SSL))
+        {
+          enable_ok = TRUE;
+          enable_username_password = TRUE;
+        }
+
+      g_warning ("goa_http_client_detect() failed: %s (%s, %d)",
+                 error->message,
+                 g_quark_to_string (error->domain),
+                 error->code);
+      g_error_free (error);
+      goto out;
+    }
+
+  has_username_password = gtk_entry_get_text_length (GTK_ENTRY (data->username)) != 0
+                          && gtk_entry_get_text_length (GTK_ENTRY (data->password)) != 0;
+
+  if (auth == NULL)
+    {
+      enable_ok = TRUE;
+      enable_username_password = FALSE;
+    }
+  else
+    {
+      if (strstr (auth, "Negotiate") != NULL)
+        {
+          enable_ok = FALSE;
+          enable_username_password = FALSE;
+          error_msg = _("Authentication failed");
+        }
+      else if (strstr (auth, "Basic") != NULL)
+        {
+          enable_ok = has_username_password;
+          enable_username_password = TRUE;
+        }
+      else
+        {
+          enable_ok = FALSE;
+          enable_username_password = FALSE;
+          error_msg = _("Unknown authentication mechanism");
+        }
+    }
+
+  if (error_msg != NULL)
+    {
+      gchar *markup;
+
+      markup = g_strdup_printf ("<b>%s:</b>\n%s",
+                                _("Error connecting to ownCloud server"),
+                                error_msg);
+      gtk_label_set_markup (GTK_LABEL (data->cluebar_label), markup);
+      g_free (markup);
+
+      gtk_widget_set_no_show_all (data->cluebar, FALSE);
+      gtk_widget_show_all (data->cluebar);
+    }
+
+ out:
+  gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, enable_ok);
+  update_row_ui (data->password_label, enable_username_password);
+  update_row_ui (data->username_label, enable_username_password);
+  show_progress_ui (GTK_CONTAINER (data->progress_grid), FALSE);
+  g_free (auth);
+}
+
+static gboolean
+on_uri_changed_timeout (gpointer user_data)
+{
+  AddAccountData *data = user_data;
+  GoaHttpClient *http_client = NULL;
+  const gchar *address;
+  gchar *uri = NULL;
+  gchar *uri_webdav = NULL;
+
+  data->changed_id = 0;
+
+  address = gtk_entry_get_text (GTK_ENTRY (data->uri));
+  uri = normalize_uri (address, NULL);
+  if (uri == NULL)
+    goto out;
+
+  g_clear_object (&data->detect_cancellable);
+  data->detect_cancellable = g_cancellable_new ();
+
+  http_client = goa_http_client_new ();
+  uri_webdav = g_strconcat (uri, WEBDAV_ENDPOINT, NULL);
+  goa_http_client_detect (http_client, uri_webdav, data->detect_cancellable, detect_cb, data);
+
+  gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, FALSE);
+  update_row_ui (data->password_label, FALSE);
+  update_row_ui (data->username_label, FALSE);
+  show_progress_ui (GTK_CONTAINER (data->progress_grid), TRUE);
+
+ out:
+  g_clear_object (&http_client);
+  g_free (uri);
+  g_free (uri_webdav);
+  return G_SOURCE_REMOVE;
+}
+
+static void
+on_uri_changed (GtkEditable *editable, gpointer user_data)
+{
+  AddAccountData *data = user_data;
+
+  if (data->changed_id != 0)
+    g_source_remove (data->changed_id);
+
+  if (data->detect_cancellable != NULL)
+    g_cancellable_cancel (data->detect_cancellable);
+
+  data->changed_id = g_timeout_add (150, on_uri_changed_timeout, data);
+
+  gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, FALSE);
+  update_row_ui (data->password_label, FALSE);
+  update_row_ui (data->username_label, FALSE);
+}
+
+static void
+on_username_or_password_changed (GtkEditable *editable, gpointer user_data)
+{
+  AddAccountData *data = user_data;
+  gboolean can_add;
+
+  can_add = gtk_entry_get_text_length (GTK_ENTRY (data->username)) != 0
+            && gtk_entry_get_text_length (GTK_ENTRY (data->password)) != 0;
+
+  gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, can_add);
+}
+
+static void
 create_account_details_ui (GoaProvider    *provider,
                            GtkDialog      *dialog,
                            GtkBox         *vbox,
@@ -555,16 +722,17 @@ create_account_details_ui (GoaProvider    *provider,
   gtk_container_add (GTK_CONTAINER (grid0), grid1);
 
   row = 0;
-  add_entry (grid1, row++, _("_Server"), &data->uri);
-  add_entry (grid1, row++, _("User_name"), &data->username);
-  add_entry (grid1, row++, _("_Password"), &data->password);
+
+  add_entry (grid1, row++, _("_Server"), TRUE, NULL, &data->uri);
+  add_entry (grid1, row++, _("User_name"), FALSE, &data->username_label, &data->username);
+  add_entry (grid1, row++, _("_Password"), FALSE, &data->password_label, &data->password);
   gtk_entry_set_visibility (GTK_ENTRY (data->password), FALSE);
 
   gtk_widget_grab_focus ((new_account) ? data->uri : data->password);
 
-  g_signal_connect (data->uri, "changed", G_CALLBACK (on_uri_username_or_password_changed), data);
-  g_signal_connect (data->username, "changed", G_CALLBACK (on_uri_username_or_password_changed), data);
-  g_signal_connect (data->password, "changed", G_CALLBACK (on_uri_username_or_password_changed), data);
+  g_signal_connect (data->uri, "changed", G_CALLBACK (on_uri_changed), data);
+  g_signal_connect (data->username, "changed", G_CALLBACK (on_username_or_password_changed), data);
+  g_signal_connect (data->password, "changed", G_CALLBACK (on_username_or_password_changed), data);
 
   gtk_dialog_add_button (data->dialog, _("_Cancel"), GTK_RESPONSE_CANCEL);
   data->connect_button = gtk_dialog_add_button (data->dialog, _("C_onnect"), GTK_RESPONSE_OK);
@@ -650,7 +818,10 @@ dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data)
   AddAccountData *data = user_data;
 
   if (response_id == GTK_RESPONSE_CANCEL || response_id == GTK_RESPONSE_DELETE_EVENT)
-    g_cancellable_cancel (data->check_cancellable);
+    {
+      g_cancellable_cancel (data->check_cancellable);
+      g_cancellable_cancel (data->detect_cancellable);
+    }
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -668,9 +839,10 @@ add_account (GoaProvider    *provider,
   GoaHttpClient *http_client;
   GoaObject *ret;
   gboolean accept_ssl_errors;
+  gboolean gssapi_enabled = FALSE;
   const gchar *uri_text;
-  const gchar *password;
-  const gchar *username;
+  const gchar *password = "";
+  const gchar *username = "";
   const gchar *provider_type;
   gchar *presentation_identity;
   gchar *server;
@@ -710,8 +882,16 @@ add_account (GoaProvider    *provider,
     }
 
   uri_text = gtk_entry_get_text (GTK_ENTRY (data.uri));
-  username = gtk_entry_get_text (GTK_ENTRY (data.username));
-  password = gtk_entry_get_text (GTK_ENTRY (data.password));
+
+  if (gtk_widget_get_sensitive (data.username))
+    username = gtk_entry_get_text (GTK_ENTRY (data.username));
+  else
+    username = g_get_user_name ();
+
+  if (gtk_widget_get_sensitive (data.password))
+    password = gtk_entry_get_text (GTK_ENTRY (data.password));
+  else
+    gssapi_enabled = TRUE;
 
   uri = normalize_uri (uri_text, &server);
   presentation_identity = g_strconcat (username, "@", server, NULL);
@@ -795,6 +975,7 @@ add_account (GoaProvider    *provider,
   g_variant_builder_add (&details, "{ss}", "FilesEnabled", "true");
   g_variant_builder_add (&details, "{ss}", "Uri", uri);
   g_variant_builder_add (&details, "{ss}", "AcceptSslErrors", (accept_ssl_errors) ? "true" : "false");
+  g_variant_builder_add (&details, "{ss}", "XXX-GssApiEnabled", (gssapi_enabled) ? "true" : "false");
 
   /* OK, everything is dandy, add the account */
   /* we want the GoaClient to update before this method returns (so it
@@ -826,12 +1007,16 @@ add_account (GoaProvider    *provider,
   else
     g_assert (ret != NULL);
 
+  if (data.changed_id != 0)
+    g_source_remove (data.changed_id);
+
   g_free (presentation_identity);
   g_free (server);
   g_free (uri);
   g_free (data.account_object_path);
   g_clear_pointer (&data.loop, (GDestroyNotify) g_main_loop_unref);
   g_clear_object (&data.check_cancellable);
+  g_clear_object (&data.detect_cancellable);
   g_clear_object (&http_client);
   return ret;
 }


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