[gnome-online-accounts/wip/kerberos: 3/4] goabackend: Add a kerberos provider



commit 363ef0f72ee5ed818d088c310cf5c994aa41351c
Author: Ray Strode <rstrode redhat com>
Date:   Sat Jun 23 03:54:35 2012 -0400

    goabackend: Add a kerberos provider
    
    This commit adds a goa backend for kerberos.
    
    This gives us the ability to integrate kerberos with control-center.
    
    We still need the service half of this for everything to be functional.

 configure.ac                         |   32 +
 src/goabackend/Makefile.am           |    8 +
 src/goabackend/goabackendtypes.h     |    3 +
 src/goabackend/goakerberosprovider.c | 1494 ++++++++++++++++++++++++++++++++++
 src/goabackend/goakerberosprovider.h |   43 +
 src/goabackend/goaprovider.c         |    4 +
 6 files changed, 1584 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index adea2b8..1fc7b89 100644
--- a/configure.ac
+++ b/configure.ac
@@ -91,6 +91,37 @@ if test "$enable_exchange" != "no"; then
   AC_DEFINE(GOA_EXCHANGE_ENABLED, 1, [Enable Microsoft Exchange data provider])
 fi
 
+# Kerberos
+AC_ARG_ENABLE([kerberos],
+              [AS_HELP_STRING([--enable-kerberos],
+              [Enable Kerberos provider])],
+              [with_kerberos=$enableval],
+              [enable_kerberos=no])
+AC_PATH_PROG([KRB5_CONFIG], krb5-config, none, $PATH:/usr/kerberos/bin)
+
+if test "x$KRB5_CONFIG" != "xnone"; then
+    KRB5_LIBS="`${KRB5_CONFIG} --libs krb5`"
+    KRB5_CFLAGS="`${KRB5_CONFIG} --cflags krb5`"
+    have_kerberos=yes
+else
+    KRB5_LIBS=""
+    KRB5_CFLAGS=""
+    have_kerberos=no
+fi
+AC_SUBST(KRB5_CFLAGS)
+AC_SUBST(KRB5_LIBS)
+
+if test "$enable_kerberos" != "no"; then
+  if test "$have_kerberos" = "no" ; then
+      AC_MSG_ERROR([kerberos support requested, but not available])
+  fi
+
+  PKG_CHECK_MODULES(GCR, gcr-3)
+  AC_DEFINE(GCR_API_SUBJECT_TO_CHANGE, 1, [Define to use the GCR API])
+  AC_DEFINE(GOA_KERBEROS_ENABLED, 1, [Enable Enterprise Identity data provider])
+fi
+AM_CONDITIONAL(BUILD_KERBEROS, [test x$enable_kerberos != xno])
+
 # Google
 AC_ARG_ENABLE([google], [AS_HELP_STRING([--enable-google], [Enable Google provider])], [], [enable_google=yes])
 AC_ARG_WITH(google-consumer-key,
@@ -259,6 +290,7 @@ echo "
 
 	Google provider:                ${enable_google} (OAuth 1.0, key:${with_google_consumer_key} secret:${with_google_consumer_secret})
 	Microsoft Exchange provider:    ${enable_exchange}
+	Kerberos provider:              ${enable_kerberos}
 	Twitter provider:               ${enable_twitter} (OAuth 1.0, key:${with_twitter_consumer_key} secret:${with_twitter_consumer_secret})
 	Yahoo provider:                 ${enable_yahoo} (OAuth 1.0, key:${with_yahoo_consumer_key} secret:${with_yahoo_consumer_secret})
 	Facebook provider:              ${enable_facebook} (OAuth 2.0, id:${with_facebook_client_id})
diff --git a/src/goabackend/Makefile.am b/src/goabackend/Makefile.am
index 7c29d84..ad608bd 100644
--- a/src/goabackend/Makefile.am
+++ b/src/goabackend/Makefile.am
@@ -6,6 +6,7 @@ EXTRA_DIST =
 INCLUDES = 							\
 	-I$(top_builddir)/src -I$(top_srcdir)/src		\
 	-I$(top_builddir)/src -I$(top_srcdir)/src		\
+	-I$(top_srcdir)/src/goaidentity				\
 	-DPACKAGE_LIBEXEC_DIR=\""$(libexecdir)"\" 		\
 	-DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" 		\
 	-DPACKAGE_DATA_DIR=\""$(datadir)"\" 			\
@@ -50,6 +51,9 @@ libgoa_backend_1_0_la_HEADERS =						\
 	goaeditablelabel.h						\
 	goaprovider.h							\
 	goaexchangeprovider.h						\
+	goakerberosprovider.h						\
+	goaoauthprovider.h						\
+	goaoauth2provider.h						\
 	goagoogleprovider.h						\
 	goafacebookprovider.h						\
 	goayahooprovider.h						\
@@ -66,6 +70,7 @@ libgoa_backend_1_0_la_SOURCES =						\
 	goaewsclient.h			goaewsclient.c			\
 	goaprovider.h			goaprovider.c			\
 	goaexchangeprovider.h		goaexchangeprovider.c		\
+	goakerberosprovider.h		goakerberosprovider.c		\
 	goalogging.h			goalogging.c			\
 	goaoauthprovider.h		goaoauthprovider.c		\
 	goaoauth2provider.h		goaoauth2provider.c		\
@@ -77,6 +82,7 @@ libgoa_backend_1_0_la_SOURCES =						\
 	goautils.h			goautils.c			\
 	goawebview.h			goawebview.c			\
 	nautilus-floating-bar.h		nautilus-floating-bar.c		\
+	$(top_srcdir)/src/goaidentity/org.gnome.Identity.c		\
 	$(NULL)
 
 libgoa_backend_1_0_la_CPPFLAGS =				\
@@ -88,6 +94,7 @@ libgoa_backend_1_0_la_CFLAGS =					\
 	-DGOA_API_IS_SUBJECT_TO_CHANGE				\
 	$(WEBKIT_GTK_CFLAGS)					\
 	$(JSON_GLIB_CFLAGS)					\
+	$(GCR_CFLAGS) 						\
 	$(GLIB_CFLAGS) 						\
 	$(GTK_CFLAGS) 						\
 	$(REST_CFLAGS)						\
@@ -100,6 +107,7 @@ libgoa_backend_1_0_la_LIBADD = 					\
 	$(top_builddir)/src/goa/libgoa-1.0.la			\
 	$(WEBKIT_GTK_LIBS)					\
 	$(JSON_GLIB_LIBS)					\
+	$(GCR_LIBS) 						\
 	$(GLIB_LIBS) 						\
 	$(GTK_LIBS) 						\
 	$(REST_LIBS)						\
diff --git a/src/goabackend/goabackendtypes.h b/src/goabackend/goabackendtypes.h
index db340c9..ee8b4bf 100644
--- a/src/goabackend/goabackendtypes.h
+++ b/src/goabackend/goabackendtypes.h
@@ -42,6 +42,9 @@ typedef struct _GoaProvider GoaProvider;
 struct _GoaExchangeProvider;
 typedef struct _GoaExchangeProvider GoaExchangeProvider;
 
+struct _GoaKerberosProvider;
+typedef struct _GoaKerberosProvider GoaKerberosProvider;
+
 struct _GoaOAuthProvider;
 typedef struct _GoaOAuthProvider GoaOAuthProvider;
 
diff --git a/src/goabackend/goakerberosprovider.c b/src/goabackend/goakerberosprovider.c
new file mode 100644
index 0000000..ed1bc6e
--- /dev/null
+++ b/src/goabackend/goakerberosprovider.c
@@ -0,0 +1,1494 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ray Strode <rstrode redhat com>
+ * Based on code from Debarshi Ray <debarshir gnome org>
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include "goalogging.h"
+#include "goaprovider.h"
+#include "goakerberosprovider.h"
+#include "goaeditablelabel.h"
+#include "goautils.h"
+#include "goaidentity.h"
+
+#include <gcr/gcr.h>
+
+#include "org.gnome.Identity.h"
+
+/**
+ * GoaKerberosProvider:
+ *
+ * The #GoaKerberosProvider structure contains only private request and should
+ * only be accessed using the provided API.
+ */
+struct _GoaKerberosProvider
+{
+  /*< private >*/
+  GoaProvider parent_instance;
+  GoaIdentityServiceManager *identity_manager;
+  GDBusObjectManager *object_manager;
+};
+
+typedef struct _GoaKerberosProviderClass GoaKerberosProviderClass;
+
+struct _GoaKerberosProviderClass
+{
+  GoaProviderClass parent_class;
+};
+
+/**
+ * SECTION:goakerberosprovider
+ * @title: GoaKerberosProvider
+ * @short_description: A provider for enterperise identity servers
+ *
+ * #GoaKerberosProvider is used to access enterperise identity servers.
+ */
+
+G_DEFINE_TYPE_WITH_CODE (GoaKerberosProvider, goa_kerberos_provider, GOA_TYPE_PROVIDER,
+                         g_io_extension_point_implement (GOA_PROVIDER_EXTENSION_POINT_NAME,
+                                                         g_define_type_id,
+                                                         "kerberos",
+                                                         0));
+
+static const gchar *
+get_provider_type (GoaProvider *provider)
+{
+  return "kerberos";
+}
+
+static gchar *
+get_provider_name (GoaProvider *provider, GoaObject *object)
+{
+  return g_strdup(_("Enterprise Identity"));
+}
+
+typedef struct
+{
+  GtkDialog *dialog;
+  GMainLoop *loop;
+
+  GtkWidget *cluebar;
+  GtkWidget *cluebar_label;
+  GtkWidget *spinner;
+
+  GtkWidget *realm;
+
+  GtkWidget *expander;
+  GtkWidget *username;
+  GtkWidget *server;
+
+  gchar *account_object_path;
+
+  GError *error;
+} SignInRequest;
+
+static void
+translate_error (GError **error)
+{
+  GError *new_error;
+
+  new_error = g_error_copy (*error);
+
+  if (g_dbus_error_strip_remote_error (new_error))
+    {
+      char   *error_name;
+      GError *final_error;
+
+      error_name = g_dbus_error_get_remote_error (*error);
+
+      final_error = g_dbus_error_new_for_dbus_error (error_name,
+                                                     new_error->message);
+
+      g_free (error_name);
+      g_error_free (*error);
+      *error = final_error;
+    }
+
+  g_error_free (new_error);
+}
+
+static void
+on_identity_signed_in (GoaIdentityServiceManager *manager,
+                       GAsyncResult              *result,
+                       GSimpleAsyncResult        *operation_result)
+{
+  gboolean  signed_in;
+  GError   *error;
+  char     *identity_object_path;
+
+  error = NULL;
+  signed_in = goa_identity_service_manager_call_sign_in_finish (manager,
+                                                                &identity_object_path,
+                                                                result,
+                                                                &error);
+
+  if (!signed_in)
+    {
+      translate_error (&error);
+
+      if (g_error_matches (error,
+                           G_IO_ERROR,
+                           G_IO_ERROR_CANCELLED))
+        {
+          g_clear_error (&error);
+          g_set_error_literal (&error,
+                               GOA_ERROR,
+                               GOA_ERROR_DIALOG_DISMISSED,
+                               "");
+        }
+
+      g_simple_async_result_take_error (operation_result, error);
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  g_simple_async_result_set_op_res_gpointer (operation_result,
+                                             g_strdup (identity_object_path),
+                                             (GDestroyNotify)
+                                             g_free);
+  g_simple_async_result_complete_in_idle (operation_result);
+  g_object_unref (operation_result);
+}
+
+static void
+on_identity_manager_ensured (GoaKerberosProvider *self,
+                             GAsyncResult        *result,
+                             GSimpleAsyncResult  *operation_result)
+{
+  GoaIdentityServiceManager *manager;
+  GError             *error;
+
+  error = NULL;
+  manager = goa_identity_service_manager_proxy_new_for_bus_finish (result, &error);
+  if (manager == NULL)
+    {
+      translate_error (&error);
+      g_simple_async_result_take_error (operation_result, error);
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  g_simple_async_result_set_op_res_gpointer (operation_result,
+                                             g_object_ref (manager),
+                                             (GDestroyNotify)
+                                             g_object_unref);
+  g_simple_async_result_complete_in_idle (operation_result);
+  g_object_unref (operation_result);
+}
+
+static void
+ensure_identity_manager (GoaKerberosProvider *self,
+                         GCancellable        *cancellable,
+                         GAsyncReadyCallback  callback,
+                         gpointer             user_data)
+{
+  GSimpleAsyncResult *operation_result;
+
+  operation_result = g_simple_async_result_new (G_OBJECT (self),
+                                                callback,
+                                                user_data,
+                                                ensure_identity_manager);
+  g_simple_async_result_set_check_cancellable (operation_result, cancellable);
+
+  g_object_set_data (G_OBJECT (operation_result),
+                     "cancellable",
+                     cancellable);
+
+  if (self->identity_manager != NULL)
+    {
+      g_simple_async_result_set_op_res_gpointer (operation_result,
+                                                 g_object_ref (self->identity_manager),
+                                                 (GDestroyNotify)
+                                                 g_object_unref);
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  goa_identity_service_manager_proxy_new_for_bus (G_BUS_TYPE_SESSION,
+                                                  G_DBUS_PROXY_FLAGS_NONE,
+                                                  "org.gnome.Identity",
+                                                  "/org/gnome/Identity/Manager",
+                                                  cancellable,
+                                                  (GAsyncReadyCallback)
+                                                  on_identity_manager_ensured,
+                                                  operation_result);
+}
+
+static void
+on_object_manager_ensured (GoaKerberosProvider *self,
+                           GAsyncResult        *result,
+                           GSimpleAsyncResult  *operation_result)
+{
+  GDBusObjectManager *manager;
+  GError *error;
+
+  error = NULL;
+  manager = goa_identity_service_object_manager_client_new_for_bus_finish (result, &error);
+  if (manager == NULL)
+    {
+      translate_error (&error);
+      g_simple_async_result_take_error (operation_result, error);
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  g_simple_async_result_set_op_res_gpointer (operation_result,
+                                             g_object_ref (manager),
+                                             (GDestroyNotify)
+                                             g_object_unref);
+  g_simple_async_result_complete_in_idle (operation_result);
+  g_object_unref (operation_result);
+}
+
+static void
+ensure_object_manager (GoaKerberosProvider *self,
+                       GCancellable        *cancellable,
+                       GAsyncReadyCallback  callback,
+                       gpointer             user_data)
+{
+  GSimpleAsyncResult *operation_result;
+
+  operation_result = g_simple_async_result_new (G_OBJECT (self),
+                                                callback,
+                                                user_data,
+                                                ensure_object_manager);
+  g_simple_async_result_set_check_cancellable (operation_result, cancellable);
+
+  g_object_set_data (G_OBJECT (operation_result),
+                     "cancellable",
+                     cancellable);
+
+  if (self->object_manager != NULL)
+    {
+      g_simple_async_result_set_op_res_gpointer (operation_result,
+                                                 g_object_ref (self->object_manager),
+                                                 (GDestroyNotify)
+                                                 g_object_unref);
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+  goa_identity_service_object_manager_client_new_for_bus (G_BUS_TYPE_SESSION,
+                                                          G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+                                                          "org.gnome.Identity",
+                                                          "/org/gnome/Identity",
+                                                          cancellable,
+                                                          (GAsyncReadyCallback)
+                                                          on_object_manager_ensured,
+                                                          operation_result);
+}
+
+static void
+on_secret_keys_exchanged_for_sign_in (GoaKerberosProvider *self,
+                                      GAsyncResult        *result,
+                                      GSimpleAsyncResult  *operation_result)
+{
+  const char       *identifier;
+  const char       *password;
+  GCancellable     *cancellable;
+  GError           *error;
+  GVariantBuilder   details;
+
+  error = NULL;
+
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
+                                             &error))
+    {
+      g_simple_async_result_take_error (operation_result, error);
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
+  password = g_object_get_data (G_OBJECT (operation_result), "password");
+  identifier = g_simple_async_result_get_source_tag (operation_result);
+
+  g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
+
+  if (password != NULL)
+    {
+      GcrSecretExchange *secret_exchange;
+      char *secret;
+
+      secret_exchange = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+
+      secret = gcr_secret_exchange_send (secret_exchange, password, -1);
+      g_variant_builder_add (&details, "{ss}", "initial-password", secret);
+      g_free (secret);
+    }
+
+  goa_identity_service_manager_call_sign_in (self->identity_manager,
+                                             identifier,
+                                             g_variant_builder_end (&details),
+                                             cancellable,
+                                             (GAsyncReadyCallback)
+                                             on_identity_signed_in,
+                                             operation_result);
+}
+
+static void
+on_secret_keys_exchanged (GoaIdentityServiceManager *manager,
+                          GAsyncResult              *result,
+                          GSimpleAsyncResult        *operation_result)
+{
+  GcrSecretExchange *secret_exchange;
+  char              *return_key;
+  GError            *error;
+
+  secret_exchange = g_simple_async_result_get_source_tag (operation_result);
+
+  error = NULL;
+  if (!goa_identity_service_manager_call_exchange_secret_keys_finish (manager,
+                                                                      &return_key,
+                                                                      result,
+                                                                      &error))
+    {
+      g_object_unref (secret_exchange);
+
+      g_simple_async_result_take_error (operation_result, error);
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  if (!gcr_secret_exchange_receive (secret_exchange, return_key))
+    {
+      g_object_unref (secret_exchange);
+
+      g_simple_async_result_set_error (operation_result,
+                                       GCR_ERROR,
+                                       GCR_ERROR_UNRECOGNIZED,
+                                       _("Identity service returned invalid key"));
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  g_simple_async_result_set_op_res_gpointer (operation_result,
+                                             secret_exchange,
+                                             (GDestroyNotify)
+                                             g_object_unref);
+  g_simple_async_result_complete_in_idle (operation_result);
+  g_object_unref (operation_result);
+}
+
+static void
+exchange_secret_keys (GoaKerberosProvider  *self,
+                      const char           *password,
+                      GCancellable         *cancellable,
+                      GAsyncReadyCallback   callback,
+                      gpointer              user_data)
+{
+
+  GSimpleAsyncResult *operation_result;
+  GcrSecretExchange  *secret_exchange;
+  char               *secret_key;
+
+  secret_exchange = gcr_secret_exchange_new (NULL);
+
+  operation_result = g_simple_async_result_new (G_OBJECT (self),
+                                                callback,
+                                                user_data,
+                                                secret_exchange);
+
+  if (password == NULL)
+    {
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
+                                                 NULL,
+                                                 NULL);
+      return;
+    }
+
+  secret_key = gcr_secret_exchange_begin (secret_exchange);
+
+  goa_identity_service_manager_call_exchange_secret_keys (self->identity_manager,
+                                                          secret_key,
+                                                          cancellable,
+                                                          (GAsyncReadyCallback)
+                                                          on_secret_keys_exchanged,
+                                                          operation_result);
+  g_free (secret_key);
+}
+
+static void
+on_identity_manager_ensured_for_sign_in (GoaKerberosProvider *self,
+                                         GAsyncResult        *result,
+                                         GSimpleAsyncResult  *operation_result)
+{
+  GoaIdentityServiceManager *manager;
+  const char                *password;
+  GCancellable              *cancellable;
+  GError                    *error;
+
+  error = NULL;
+
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
+                                             &error))
+    {
+      g_simple_async_result_take_error (operation_result, error);
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  manager = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+
+  if (self->identity_manager == NULL)
+    self->identity_manager = g_object_ref (manager);
+
+  cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
+  password = g_object_get_data (G_OBJECT (operation_result), "password");
+
+  exchange_secret_keys (self,
+                        password,
+                        cancellable,
+                        (GAsyncReadyCallback)
+                        on_secret_keys_exchanged_for_sign_in,
+                        operation_result);
+}
+
+static void
+sign_in_identity (GoaKerberosProvider  *self,
+                  const char           *identifier,
+                  const char           *password,
+                  GCancellable         *cancellable,
+                  GAsyncReadyCallback   callback,
+                  gpointer              user_data)
+{
+  GSimpleAsyncResult *operation_result;
+
+  operation_result = g_simple_async_result_new (G_OBJECT (self),
+                                                callback,
+                                                user_data,
+                                                (gpointer)
+                                                identifier);
+
+  g_simple_async_result_set_check_cancellable (operation_result, cancellable);
+
+  g_object_set_data (G_OBJECT (operation_result),
+                     "cancellable",
+                     cancellable);
+  g_object_set_data (G_OBJECT (operation_result),
+                     "password",
+                     (gpointer)
+                     password);
+
+  ensure_identity_manager (self,
+                           cancellable,
+                           (GAsyncReadyCallback)
+                           on_identity_manager_ensured_for_sign_in,
+                           operation_result);
+}
+
+static void
+on_object_manager_ensured_for_look_up (GoaKerberosProvider *self,
+                                       GAsyncResult        *result,
+                                       GSimpleAsyncResult  *operation_result)
+{
+  GDBusObjectManager *manager;
+  const char         *identifier;
+  GList              *objects, *node;
+  GError             *error;
+
+  error = NULL;
+
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
+                                             &error))
+    {
+      g_simple_async_result_take_error (operation_result, error);
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  manager = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+
+  if (self->object_manager == NULL)
+    self->object_manager = g_object_ref (manager);
+
+  identifier = g_simple_async_result_get_source_tag (operation_result);
+
+  g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
+                                             NULL,
+                                             NULL);
+  objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->object_manager));
+
+  for (node = objects; node != NULL; node = node->next)
+    {
+      GoaIdentityServiceIdentity *candidate_identity;
+      const char                 *candidate_identifier;
+      GDBusObject                *object;
+
+      object = node->data;
+
+      candidate_identity = GOA_IDENTITY_SERVICE_IDENTITY (g_dbus_object_get_interface (object, "org.gnome.Identity"));
+
+      if (candidate_identity == NULL)
+        continue;
+
+      candidate_identifier = goa_identity_service_identity_get_identifier (candidate_identity);
+
+      if (g_strcmp0 (candidate_identifier, identifier) == 0)
+        {
+          g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
+                                                     candidate_identity,
+                                                     (GDestroyNotify)
+                                                     g_object_unref);
+          break;
+        }
+
+      g_object_unref (candidate_identity);
+    }
+
+  g_list_free_full (objects, (GDestroyNotify) g_object_unref);
+  g_simple_async_result_complete_in_idle (G_SIMPLE_ASYNC_RESULT (operation_result));
+  g_object_unref (operation_result);
+}
+
+static void
+look_up_identity (GoaKerberosProvider  *self,
+                  const char           *identifier,
+                  GCancellable         *cancellable,
+                  GAsyncReadyCallback   callback,
+                  gpointer              user_data)
+{
+  GSimpleAsyncResult *operation_result;
+
+  operation_result = g_simple_async_result_new (G_OBJECT (self),
+                                                callback,
+                                                user_data,
+                                                (gpointer)
+                                                identifier);
+
+  g_simple_async_result_set_check_cancellable (operation_result, cancellable);
+
+  g_object_set_data (G_OBJECT (operation_result),
+                     "cancellable",
+                     cancellable);
+  ensure_object_manager (self,
+                         cancellable,
+                         (GAsyncReadyCallback)
+                         on_object_manager_ensured_for_look_up,
+                         operation_result);
+}
+
+static void
+on_account_signed_in (GoaProvider   *provider,
+                      GAsyncResult  *result,
+                      SignInRequest *request)
+{
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
+                                             &request->error))
+    {
+      g_main_loop_quit (request->loop);
+      return;
+    }
+
+  g_main_loop_quit (request->loop);
+}
+
+static gboolean
+get_ticket_sync (GoaKerberosProvider *self,
+                 GoaObject           *object,
+                 gboolean             is_interactive,
+                 GCancellable        *cancellable,
+                 GError             **error)
+{
+  GVariant            *credentials;
+  GError              *lookup_error;
+  GoaAccount          *account;
+  const char          *identifier;
+  const char          *password;
+  gboolean             has_password;
+  SignInRequest        request;
+  gboolean             ret;
+
+  ret = FALSE;
+
+  account = goa_object_peek_account (object);
+  identifier = goa_account_get_identity (account);
+  password = NULL;
+
+  lookup_error = NULL;
+  credentials = goa_utils_lookup_credentials_sync (GOA_PROVIDER (self),
+                                                   object,
+                                                   cancellable,
+                                                   &lookup_error);
+
+  if (credentials == NULL && !is_interactive)
+    {
+      if (lookup_error != NULL)
+          g_propagate_error (error, lookup_error);
+      else
+          g_set_error (error,
+                       GOA_ERROR,
+                       GOA_ERROR_NOT_AUTHORIZED,
+                       _("Could not find saved credentials for principal `%s' in keyring"), identifier);
+      goto out;
+    }
+
+  has_password = g_variant_lookup (credentials, "password", "&s", &password);
+  if (!has_password && !is_interactive)
+    {
+      g_set_error (error,
+                   GOA_ERROR,
+                   GOA_ERROR_NOT_AUTHORIZED,
+                   _("Did not find password for principal `%s' in credentials"),
+                   identifier);
+      goto out;
+    }
+
+  memset (&request, 0, sizeof (SignInRequest));
+  request.loop = g_main_loop_new (NULL, FALSE);
+  request.error = NULL;
+
+  sign_in_identity (self,
+                    identifier,
+                    password,
+                    cancellable,
+                    (GAsyncReadyCallback)
+                    on_account_signed_in,
+                    &request);
+
+  g_main_loop_run (request.loop);
+  g_main_loop_unref (request.loop);
+
+  if (request.error != NULL)
+    {
+      g_propagate_error (error, request.error);
+      goto out;
+    }
+
+  ret = TRUE;
+out:
+  if (credentials != NULL)
+    g_variant_unref (credentials);
+
+  return ret;
+}
+
+static gboolean
+on_handle_get_ticket (GoaTicketing          *interface,
+                      GDBusMethodInvocation *invocation)
+{
+  GoaObject *object;
+  GoaAccount *account;
+  GoaProvider *provider;
+  GError *error;
+  gboolean got_ticket;
+
+  object = GOA_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (interface)));
+  account = goa_object_peek_account (object);
+
+  provider = goa_provider_get_for_provider_type (goa_account_get_provider_type (account));
+  error = NULL;
+  got_ticket = get_ticket_sync (GOA_KERBEROS_PROVIDER (provider),
+                                object,
+                                TRUE /* Allow interaction */,
+                                NULL,
+                                &error);
+
+  if (!got_ticket)
+    g_dbus_method_invocation_take_error (invocation, error);
+  else
+    goa_ticketing_complete_get_ticket (interface, invocation);
+
+  g_object_unref (provider);
+  return TRUE;
+}
+
+static gboolean
+build_object (GoaProvider         *provider,
+              GoaObjectSkeleton   *object,
+              GKeyFile            *key_file,
+              const gchar         *group,
+              gboolean             just_added,
+              GError             **error)
+{
+  GoaAccount   *account;
+  GoaTicketing *ticketing;
+  gboolean      ticketing_enabled;
+  gboolean      ret;
+
+  ret = FALSE;
+
+  if (!GOA_PROVIDER_CLASS (goa_kerberos_provider_parent_class)->build_object (provider,
+                                                                              object,
+                                                                              key_file,
+                                                                              group,
+                                                                              just_added,
+                                                                              error))
+    goto out;
+
+  account = goa_object_get_account (GOA_OBJECT (object));
+
+  ticketing = goa_object_get_ticketing (GOA_OBJECT (object));
+  ticketing_enabled = g_key_file_get_boolean (key_file, group, "TicketingEnabled", NULL);
+
+  if (ticketing_enabled)
+    {
+      if (ticketing == NULL)
+        {
+          ticketing = goa_ticketing_skeleton_new ();
+
+          g_signal_connect (ticketing,
+                            "handle-get-ticket",
+                            G_CALLBACK (on_handle_get_ticket),
+                            NULL);
+
+          goa_object_skeleton_set_ticketing (object, ticketing);
+
+        }
+    }
+  else if (ticketing != NULL)
+    {
+      goa_object_skeleton_set_ticketing (object, NULL);
+    }
+
+  if (just_added)
+    {
+      goa_account_set_ticketing_disabled (account, !ticketing_enabled);
+
+      g_signal_connect (account,
+                        "notify::ticketing-disabled",
+                        G_CALLBACK (goa_util_account_notify_property_cb),
+                        "TicketingEnabled");
+    }
+
+  ret = TRUE;
+
+ out:
+  if (ticketing != NULL)
+    g_object_unref (ticketing);
+
+  return ret;
+}
+
+static void
+add_entry (GtkWidget     *grid1,
+           GtkWidget     *grid2,
+           const gchar   *text,
+           GtkWidget    **out_entry)
+{
+  GtkStyleContext *context;
+  GtkWidget *label;
+  GtkWidget *entry;
+
+  label = gtk_label_new_with_mnemonic (text);
+  context = gtk_widget_get_style_context (label);
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL);
+  gtk_widget_set_vexpand (label, TRUE);
+  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
+  gtk_container_add (GTK_CONTAINER (grid1), label);
+
+  entry = gtk_entry_new ();
+  gtk_widget_set_hexpand (entry, TRUE);
+  gtk_widget_set_vexpand (entry, TRUE);
+  gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
+  gtk_entry_set_max_length (GTK_ENTRY (entry), 132);
+  gtk_container_add (GTK_CONTAINER (grid2), entry);
+
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
+  if (out_entry != NULL)
+    *out_entry = entry;
+}
+
+static void
+create_account_details_ui (GtkBox        *vbox,
+                           gboolean       new_account,
+                           SignInRequest *request)
+{
+  GtkWidget *header_grid;
+  GtkWidget *grid1;
+  GtkWidget *grid2;
+  GtkWidget *hbox;
+  GtkWidget *label;
+  gchar *markup;
+  gint width;
+
+  request->cluebar = gtk_info_bar_new ();
+  gtk_info_bar_set_message_type (GTK_INFO_BAR (request->cluebar), GTK_MESSAGE_ERROR);
+  gtk_widget_set_no_show_all (request->cluebar, TRUE);
+  gtk_box_pack_start (GTK_BOX (vbox), request->cluebar, FALSE, FALSE, 0);
+
+  request->cluebar_label = gtk_label_new ("");
+  gtk_label_set_line_wrap (GTK_LABEL (request->cluebar_label), TRUE);
+  gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (request->cluebar))),
+                     request->cluebar_label);
+
+  header_grid = gtk_grid_new ();
+  gtk_orientable_set_orientation (GTK_ORIENTABLE (header_grid), GTK_ORIENTATION_HORIZONTAL);
+  gtk_box_pack_start (vbox, header_grid, FALSE, FALSE, 0);
+
+  label = gtk_label_new (NULL);
+  gtk_widget_set_hexpand (label, TRUE);
+  markup = g_strconcat ("<b>",
+                        (new_account) ? _("New Enterprise Identity") : _("Enterpise Identity"),
+                        "</b>",
+                        NULL);
+  gtk_label_set_markup (GTK_LABEL (label), markup);
+  g_free (markup);
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_container_add (GTK_CONTAINER (header_grid), label);
+
+  request->spinner = gtk_spinner_new ();
+  gtk_widget_set_no_show_all (request->spinner, TRUE);
+  gtk_container_add (GTK_CONTAINER (header_grid), request->spinner);
+
+  grid1 = gtk_grid_new ();
+  gtk_orientable_set_orientation (GTK_ORIENTABLE (grid1), GTK_ORIENTATION_VERTICAL);
+  gtk_grid_set_row_spacing (GTK_GRID (grid1), 12);
+
+  grid2 = gtk_grid_new ();
+  gtk_orientable_set_orientation (GTK_ORIENTABLE (grid2), GTK_ORIENTATION_VERTICAL);
+  gtk_grid_set_row_spacing (GTK_GRID (grid2), 12);
+
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+  gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE);
+  gtk_box_pack_start (GTK_BOX (hbox), grid1, FALSE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), grid2, TRUE, TRUE, 0);
+  gtk_box_pack_start (vbox, hbox, FALSE, FALSE, 0);
+
+  add_entry (grid1, grid2, _("User_name"), &request->username);
+  add_entry (grid1, grid2, _("_Realm"), &request->realm);
+
+  gtk_widget_grab_focus (request->username);
+
+  gtk_dialog_add_button (request->dialog, GTK_STOCK_CONNECT, GTK_RESPONSE_OK);
+  gtk_dialog_set_default_response (request->dialog, GTK_RESPONSE_OK);
+  gtk_dialog_set_response_sensitive (request->dialog, GTK_RESPONSE_OK, TRUE);
+
+  gtk_window_get_size (GTK_WINDOW (request->dialog), &width, NULL);
+  gtk_widget_set_size_request (GTK_WIDGET (request->dialog), width, -1);
+}
+
+static void
+add_account_cb (GoaManager   *manager,
+                GAsyncResult *result,
+                gpointer      user_data)
+{
+  SignInRequest *request = user_data;
+  goa_manager_call_add_account_finish (manager,
+                                       &request->account_object_path,
+                                       result,
+                                       &request->error);
+  if (request->error != NULL)
+    translate_error (&request->error);
+  g_main_loop_quit (request->loop);
+}
+
+static void
+remove_account_cb (GoaAccount   *account,
+                   GAsyncResult *result,
+                   GMainLoop    *loop)
+{
+  goa_account_call_remove_finish (account, result, NULL);
+  g_main_loop_quit (loop);
+}
+
+static gboolean
+refresh_account (GoaProvider    *provider,
+                 GoaClient      *client,
+                 GoaObject      *object,
+                 GtkWindow      *parent,
+                 GError        **error)
+{
+  GoaKerberosProvider *self = GOA_KERBEROS_PROVIDER (provider);
+  gboolean             got_ticket;
+
+  g_return_val_if_fail (GOA_IS_KERBEROS_PROVIDER (provider), FALSE);
+  g_return_val_if_fail (GOA_IS_CLIENT (client), FALSE);
+  g_return_val_if_fail (GOA_IS_OBJECT (object), FALSE);
+  g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  got_ticket = get_ticket_sync (self,
+                                object,
+                                TRUE /* Allow interaction */,
+                                NULL,
+                                error);
+  return got_ticket;
+}
+
+static void
+on_initial_sign_in_done (GoaKerberosProvider *self,
+                         GAsyncResult        *result,
+                         GSimpleAsyncResult  *operation_result)
+{
+  GError    *error;
+  gboolean   remember_password;
+  GoaObject *object;
+
+  object = g_simple_async_result_get_source_tag (operation_result);
+
+  remember_password = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (operation_result),
+                                                          "remember-password"));
+
+  error = NULL;
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), &error))
+    {
+      g_simple_async_result_take_error (operation_result, error);
+    }
+  else if (remember_password)
+    {
+      GVariantBuilder  builder;
+      const char      *object_path;
+
+      object_path = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+
+      if (object_path != NULL && object != NULL)
+        {
+          GcrSecretExchange *secret_exchange;
+          const char        *password;
+
+          secret_exchange = g_object_get_data (G_OBJECT (operation_result), "secret-exchange");
+          password = gcr_secret_exchange_get_secret (secret_exchange, NULL);
+
+          /* FIXME: we go to great lengths to keep the password in non-pageable memory,
+           * and then just duplicate it into a gvariant here
+           */
+          g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+          g_variant_builder_add (&builder,
+                                 "{sv}",
+                                 "password",
+                                 g_variant_new_string (password));
+
+          error = NULL;
+          goa_utils_store_credentials_for_object_sync (GOA_PROVIDER (self),
+                                                       object,
+                                                       g_variant_builder_end (&builder),
+                                                       NULL,
+                                                       NULL);
+        }
+    }
+
+  g_simple_async_result_complete_in_idle (operation_result);
+  g_object_unref (operation_result);
+}
+
+static void
+on_system_prompt_answered_for_initial_sign_in (GcrPrompt          *prompt,
+                                               GAsyncResult       *result,
+                                               GSimpleAsyncResult *operation_result)
+{
+  GoaKerberosProvider *self;
+  GCancellable        *cancellable;
+  GError              *error;
+  const char          *principal;
+  const char          *password;
+  GcrSecretExchange   *secret_exchange;
+
+  self = GOA_KERBEROS_PROVIDER (g_async_result_get_source_object (G_ASYNC_RESULT (operation_result)));
+  principal = g_object_get_data (G_OBJECT (operation_result), "principal");
+  cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
+
+  error = NULL;
+  password = gcr_prompt_password_finish (prompt, result, &error);
+
+  if (password == NULL)
+    {
+      gcr_system_prompt_close (GCR_SYSTEM_PROMPT (prompt), NULL, NULL);
+
+      if (error != NULL)
+        g_simple_async_result_take_error (operation_result, error);
+      else
+        g_cancellable_cancel (cancellable);
+
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  secret_exchange = gcr_system_prompt_get_secret_exchange (GCR_SYSTEM_PROMPT (prompt));
+  g_object_set_data_full (G_OBJECT (operation_result),
+                          "secret-exchange",
+                          g_object_ref (secret_exchange),
+                          (GDestroyNotify)
+                          g_object_unref);
+
+  g_object_set_data (G_OBJECT (operation_result),
+                     "remember-password",
+                     GINT_TO_POINTER (gcr_prompt_get_choice_chosen (prompt)));
+
+  gcr_system_prompt_close (GCR_SYSTEM_PROMPT (prompt), NULL, NULL);
+
+  sign_in_identity (self,
+                    principal,
+                    password,
+                    cancellable,
+                    (GAsyncReadyCallback)
+                    on_initial_sign_in_done,
+                    operation_result);
+}
+
+static void
+on_system_prompt_open_for_initial_sign_in (GcrSystemPrompt     *system_prompt,
+                                           GAsyncResult        *result,
+                                           GSimpleAsyncResult  *operation_result)
+{
+  GCancellable *cancellable;
+  GcrPrompt    *prompt;
+  GError       *error;
+
+  cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
+  error = NULL;
+  prompt = gcr_system_prompt_open_finish (result, &error);
+
+  if (prompt == NULL)
+    {
+      g_simple_async_result_take_error (operation_result, error);
+
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+
+      return;
+    }
+
+  gcr_prompt_set_title (prompt, _("Log In to Realm"));
+  gcr_prompt_set_description (prompt, _("Please enter your password below."));
+  gcr_prompt_set_choice_label (prompt, _("Remember this password"));
+
+  gcr_prompt_password_async (prompt,
+                             cancellable,
+                             (GAsyncReadyCallback)
+                             on_system_prompt_answered_for_initial_sign_in,
+                             operation_result);
+}
+
+static void
+perform_initial_sign_in (GoaKerberosProvider *self,
+                         GoaObject           *object,
+                         const char          *principal,
+                         SignInRequest       *request)
+{
+
+  GSimpleAsyncResult *operation_result;
+  GCancellable       *cancellable;
+
+  cancellable = g_cancellable_new ();
+
+  operation_result = g_simple_async_result_new (G_OBJECT (self),
+                                                (GAsyncReadyCallback)
+                                                on_account_signed_in ,
+                                                request,
+                                                object);
+  g_simple_async_result_set_check_cancellable (operation_result, cancellable);
+
+  g_object_set_data (G_OBJECT (operation_result),
+                     "cancellable",
+                     cancellable);
+  g_object_set_data (G_OBJECT (operation_result),
+                     "principal",
+                     (gpointer)
+                     principal);
+
+  gcr_system_prompt_open_async (-1,
+                                cancellable,
+                                (GAsyncReadyCallback)
+                                on_system_prompt_open_for_initial_sign_in,
+                                operation_result);
+}
+
+static GoaObject *
+add_account (GoaProvider    *provider,
+             GoaClient      *client,
+             GtkDialog      *dialog,
+             GtkBox         *vbox,
+             GError        **error)
+{
+  GoaKerberosProvider *self = GOA_KERBEROS_PROVIDER (provider);
+  SignInRequest request;
+  GVariantBuilder credentials;
+  GVariantBuilder details;
+  GoaObject   *object;
+  GoaAccount  *account;
+  const gchar *realm;
+  const gchar *username;
+  gchar *principal;
+  gchar *principal_for_display;
+  const gchar *provider_type;
+  gint response;
+
+  object = NULL;
+  principal = NULL;
+  principal_for_display = NULL;
+
+  memset (&request, 0, sizeof (SignInRequest));
+  request.loop = g_main_loop_new (NULL, FALSE);
+  request.dialog = dialog;
+  request.error = NULL;
+
+  create_account_details_ui (vbox, TRUE, &request);
+  gtk_widget_show_all (GTK_WIDGET (vbox));
+
+start_over:
+  response = gtk_dialog_run (dialog);
+
+  if (response != GTK_RESPONSE_OK)
+    {
+      g_set_error (&request.error,
+                   GOA_ERROR,
+                   GOA_ERROR_DIALOG_DISMISSED,
+                   _("Dialog was dismissed"));
+      goto out;
+    }
+
+  realm = gtk_entry_get_text (GTK_ENTRY (request.realm));
+  username = gtk_entry_get_text (GTK_ENTRY (request.username));
+
+  g_free (principal);
+  principal = g_strdup_printf ("%s %s", username, realm);
+
+  /* See if there's already an account of this type with the
+   * given identity
+   */
+  provider_type = goa_provider_get_provider_type (provider);
+
+  if (!goa_utils_check_duplicate (client,
+                                  principal,
+                                  provider_type,
+                                  (GoaPeekInterfaceFunc) goa_object_peek_account,
+                                  &request.error))
+    goto out;
+
+  /* If there isn't an account, then go ahead and create one
+   */
+  g_variant_builder_init (&credentials, G_VARIANT_TYPE_VARDICT);
+
+  g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
+  g_variant_builder_add (&details, "{ss}", "Realm", realm);
+  g_variant_builder_add (&details, "{ss}", "TicketingEnabled", "true");
+
+  g_free (principal_for_display);
+  principal_for_display = g_strdup_printf ("%s %s", username, realm);
+
+  goa_manager_call_add_account (goa_client_get_manager (client),
+                                goa_provider_get_provider_type (provider),
+                                principal,
+                                principal_for_display,
+                                g_variant_builder_end (&credentials),
+                                g_variant_builder_end (&details),
+                                NULL, /* GCancellable* */
+                                (GAsyncReadyCallback) add_account_cb,
+                                &request);
+  g_main_loop_run (request.loop);
+  if (request.error != NULL)
+    goto out;
+
+  object = GOA_OBJECT (g_dbus_object_manager_get_object (goa_client_get_object_manager (client),
+                                                         request.account_object_path));
+  account = goa_object_peek_account (object);
+
+  gtk_spinner_start (GTK_SPINNER (request.spinner));
+  gtk_widget_show (request.spinner);
+
+  /* After the account is created, try to sign it in
+   */
+  perform_initial_sign_in (self, object, principal, &request);
+
+  g_main_loop_run (request.loop);
+
+  if (request.error != NULL)
+    {
+      GtkWidget *button;
+      gchar *markup;
+
+      translate_error (&request.error);
+
+      if (!g_error_matches (request.error,
+                            G_IO_ERROR,
+                            G_IO_ERROR_CANCELLED))
+        {
+          markup = g_strdup_printf ("<b>%s:</b> %s",
+                                    _("Error connecting to enterperise identity server"),
+                                    request.error->message);
+          gtk_label_set_markup (GTK_LABEL (request.cluebar_label), markup);
+          g_free (markup);
+
+          button = gtk_dialog_get_widget_for_response (request.dialog, GTK_RESPONSE_OK);
+          gtk_button_set_label (GTK_BUTTON (button), _("_Try Again"));
+          gtk_expander_set_expanded (GTK_EXPANDER (request.expander), TRUE);
+          gtk_widget_set_no_show_all (request.cluebar, FALSE);
+          gtk_widget_show_all (request.cluebar);
+        }
+      g_clear_error (&request.error);
+
+      /* If it couldn't be signed in, then delete it and start over
+       */
+      goa_account_call_remove (account,
+                               NULL,
+                               (GAsyncReadyCallback)
+                               remove_account_cb,
+                               request.loop);
+      g_main_loop_run (request.loop);
+      g_clear_object (&object);
+      goto start_over;
+    }
+
+  gtk_widget_hide (GTK_WIDGET (dialog));
+
+ out:
+  /* We might have an object even when request.error is set.
+   * eg., if we failed to store the credentials in the keyring.
+   */
+  if (request.error != NULL)
+    {
+      translate_error (&request.error);
+      g_propagate_error (error, request.error);
+    }
+  else
+    g_assert (object != NULL);
+
+  g_free (request.account_object_path);
+  g_free (principal);
+  g_free (principal_for_display);
+  if (request.loop != NULL)
+    g_main_loop_unref (request.loop);
+  return object;
+}
+
+static void
+show_account (GoaProvider *provider,
+              GoaClient   *client,
+              GoaObject   *object,
+              GtkBox      *vbox,
+              GtkGrid     *left,
+              GtkGrid     *right)
+{
+  GOA_PROVIDER_CLASS (goa_kerberos_provider_parent_class)->show_account (provider,
+                                                                         client,
+                                                                         object,
+                                                                         vbox,
+                                                                         left,
+                                                                         right);
+  goa_util_add_row_switch_from_keyfile_with_blurb (left, right, object,
+                                                   _("Use for"),
+                                                   "ticketing-disabled",
+                                                   _("Network Resources"));
+}
+
+static void
+on_identity_looked_up (GoaKerberosProvider *provider,
+                       GAsyncResult        *result,
+                       GSimpleAsyncResult  *operation_result)
+{
+
+  GoaIdentityServiceIdentity *identity;
+  GError                     *error;
+
+  error = NULL;
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), &error))
+    {
+      g_simple_async_result_take_error (operation_result, error);
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  identity = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+  if (identity != NULL)
+    g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
+                                               g_object_ref (identity),
+                                               (GDestroyNotify)
+                                               g_object_unref);
+  else
+    g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
+                                               NULL,
+                                               NULL);
+
+  g_simple_async_result_complete_in_idle (operation_result);
+  g_object_unref (operation_result);
+}
+
+static void
+on_identity_looked_up_to_ensure_credentials (GoaKerberosProvider *self,
+                                             GAsyncResult        *result,
+                                             GSimpleAsyncResult  *operation_result)
+{
+
+  GoaIdentityServiceIdentity *identity;
+  GError                     *error;
+  GoaObject                  *object;
+  GoaAccount                 *account;
+  const char                 *identifier;
+  GCancellable               *cancellable;
+
+  error = NULL;
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), &error))
+    {
+      g_simple_async_result_take_error (operation_result, error);
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  identity = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+
+  if (identity != NULL && goa_identity_service_identity_get_is_signed_in (identity))
+    {
+      g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
+                                                 g_object_ref (identity),
+                                                 (GDestroyNotify)
+                                                 g_object_unref);
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  object = GOA_OBJECT (g_async_result_get_source_object (G_ASYNC_RESULT (operation_result)));
+  cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
+
+  if (!get_ticket_sync (self,
+                        object,
+                        FALSE /* Don't allow interaction */,
+                        cancellable,
+                        &error))
+    {
+      g_simple_async_result_take_error (operation_result, error);
+      g_simple_async_result_complete_in_idle (operation_result);
+      g_object_unref (operation_result);
+      return;
+    }
+
+  account = goa_object_peek_account (object);
+  identifier = goa_account_get_identity (account);
+
+  look_up_identity (self,
+                    identifier,
+                    cancellable,
+                    (GAsyncReadyCallback)
+                    on_identity_looked_up,
+                    operation_result);
+
+  g_simple_async_result_complete_in_idle (operation_result);
+  g_object_unref (operation_result);
+}
+
+static void
+on_credentials_ensured (GoaObject    *object,
+                        GAsyncResult *result,
+                        GMainLoop    *loop)
+{
+  g_main_loop_quit (loop);
+}
+
+static gboolean
+ensure_credentials_sync (GoaProvider    *provider,
+                         GoaObject      *object,
+                         gint           *out_expires_in,
+                         GCancellable   *cancellable,
+                         GError        **error)
+{
+  GoaIdentityServiceIdentity *identity;
+  GoaAccount                 *account;
+  const char                 *identifier;
+  GSimpleAsyncResult         *operation_result;
+  GMainLoop                  *loop;
+  GMainContext               *context;
+  gint64                      timestamp;
+  GDateTime                  *now, *expiration_time;
+  GTimeSpan                   time_span;
+
+  account = goa_object_peek_account (object);
+  identifier = goa_account_get_identity (account);
+
+  context = g_main_context_new ();
+  g_main_context_push_thread_default (context);
+  loop = g_main_loop_new (context, FALSE);
+  operation_result = g_simple_async_result_new (G_OBJECT (object),
+                                                (GAsyncReadyCallback)
+                                                on_credentials_ensured,
+                                                loop,
+                                                ensure_credentials_sync);
+  g_simple_async_result_set_check_cancellable (operation_result, cancellable);
+
+  g_object_set_data (G_OBJECT (operation_result),
+                     "cancellable",
+                     cancellable);
+
+  g_object_ref (operation_result);
+  look_up_identity (GOA_KERBEROS_PROVIDER (provider),
+                    identifier,
+                    cancellable,
+                    (GAsyncReadyCallback)
+                    on_identity_looked_up_to_ensure_credentials,
+                    operation_result);
+
+  g_main_loop_run (loop);
+  g_main_loop_unref (loop);
+
+  g_main_context_pop_thread_default (context);
+  g_main_context_unref (context);
+
+  if (g_simple_async_result_propagate_error (operation_result, error))
+    {
+      g_object_unref (operation_result);
+      return FALSE;
+    }
+
+  identity = g_simple_async_result_get_op_res_gpointer (operation_result);
+
+  now = g_date_time_new_now_local ();
+  timestamp = goa_identity_service_identity_get_expiration_timestamp (identity);
+  expiration_time = g_date_time_new_from_unix_local (timestamp);
+  time_span = g_date_time_difference (expiration_time, now);
+
+  time_span /= G_TIME_SPAN_SECOND;
+
+  if (time_span < 0 || time_span > G_MAXINT)
+    time_span = 0;
+
+  *out_expires_in = (int) time_span;
+
+  g_date_time_unref (now);
+  g_date_time_unref (expiration_time);
+  g_object_unref (operation_result);
+
+  return TRUE;
+}
+
+static void
+goa_kerberos_provider_init (GoaKerberosProvider *provider)
+{
+}
+
+static void
+goa_kerberos_provider_class_init (GoaKerberosProviderClass *kerberos_class)
+{
+  GoaProviderClass *provider_class;
+
+  provider_class = GOA_PROVIDER_CLASS (kerberos_class);
+  provider_class->get_provider_type          = get_provider_type;
+  provider_class->get_provider_name          = get_provider_name;
+  provider_class->build_object               = build_object;
+  provider_class->add_account                = add_account;
+  provider_class->refresh_account            = refresh_account;
+  provider_class->show_account               = show_account;
+  provider_class->ensure_credentials_sync    = ensure_credentials_sync;
+}
diff --git a/src/goabackend/goakerberosprovider.h b/src/goabackend/goakerberosprovider.h
new file mode 100644
index 0000000..385664c
--- /dev/null
+++ b/src/goabackend/goakerberosprovider.h
@@ -0,0 +1,43 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ray Strode <rstrode redhat com>
+ * Based on code from Debarshi Ray <debarshir gnome org>
+ */
+
+#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION)
+#error "Only <goabackend/goabackend.h> can be included directly."
+#endif
+
+#ifndef __GOA_KERBEROS_PROVIDER_H__
+#define __GOA_KERBEROS_PROVIDER_H__
+
+#include <goabackend/goabackendtypes.h>
+
+G_BEGIN_DECLS
+
+#define GOA_TYPE_KERBEROS_PROVIDER   (goa_kerberos_provider_get_type ())
+#define GOA_KERBEROS_PROVIDER(o)     (G_TYPE_CHECK_INSTANCE_CAST ((o), GOA_TYPE_KERBEROS_PROVIDER, GoaKerberosProvider))
+#define GOA_IS_KERBEROS_PROVIDER(o)  (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOA_TYPE_KERBEROS_PROVIDER))
+
+GType goa_kerberos_provider_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GOA_KERBEROS_PROVIDER_H__ */
diff --git a/src/goabackend/goaprovider.c b/src/goabackend/goaprovider.c
index 41ebbdb..140c115 100644
--- a/src/goabackend/goaprovider.c
+++ b/src/goabackend/goaprovider.c
@@ -28,6 +28,7 @@
 #include "goalogging.h"
 #include "goaprovider.h"
 #include "goaexchangeprovider.h"
+#include "goakerberosprovider.h"
 #include "goagoogleprovider.h"
 #include "goafacebookprovider.h"
 #include "goayahooprovider.h"
@@ -754,6 +755,9 @@ ensure_ep_and_builtins (void)
 #ifdef GOA_WINDOWS_LIVE_ENABLED
       type = GOA_TYPE_WINDOWS_LIVE_PROVIDER;
 #endif
+#ifdef GOA_KERBEROS_ENABLED
+      type = GOA_TYPE_KERBEROS_PROVIDER;
+#endif
 #ifdef GOA_EXCHANGE_ENABLED
       type = GOA_TYPE_EXCHANGE_PROVIDER;
 #endif



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