[gnome-online-accounts/wip/rishi/fedora-provider] Add Fedora Account System
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-online-accounts/wip/rishi/fedora-provider] Add Fedora Account System
- Date: Mon, 5 Aug 2019 18:47:41 +0000 (UTC)
commit aded9508ec3bfa7a26aa0b81b0428c741e91f495
Author: Debarshi Ray <debarshir gnome org>
Date: Wed Jul 31 19:15:45 2019 +0200
Add Fedora Account System
https://gitlab.gnome.org/GNOME/gnome-online-accounts/issues/26
configure.ac | 41 +-
data/icons/meson.build | 1 +
data/icons/scalable/Makefile.am | 1 +
data/icons/scalable/goa-account-fedora.svg | 1 +
meson.build | 14 +
meson_options.txt | 2 +
src/goabackend/Makefile.am | 5 +
src/goabackend/goafedoraprovider.c | 1302 ++++++++++++++++++++++++++++
src/goabackend/goafedoraprovider.h | 37 +
src/goabackend/goaprovider.c | 9 +-
src/goabackend/meson.build | 10 +-
src/goaidentity/goaidentityservice.c | 170 +++-
src/meson.build | 2 +-
13 files changed, 1583 insertions(+), 12 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 3361c554..37d8ddee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -167,6 +167,44 @@ if test "$enable_exchange" != "no"; then
AC_DEFINE(GOA_EXCHANGE_ENABLED, 1, [Enable Microsoft Exchange data provider])
fi
+# Fedora
+AC_DEFINE(GOA_FEDORA_NAME, ["fedora"], [ProviderType and extension point name])
+AC_DEFINE(GOA_FEDORA_REALM, ["FEDORAPROJECT.ORG"], [Kerberos realm used by the Fedora Account System])
+AC_ARG_ENABLE([fedora],
+ [AS_HELP_STRING([--enable-fedora], [Enable Fedora Account System support])],
+ [enable_fedora=$enableval],
+ [enable_fedora=auto])
+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`"
+ PKG_CHECK_MODULES(GCR, gcr-3, [have_fedora=yes], [have_fedora=no])
+else
+ KRB5_LIBS=""
+ KRB5_CFLAGS=""
+ have_fedora=no
+fi
+AC_SUBST(KRB5_CFLAGS)
+AC_SUBST(KRB5_LIBS)
+
+if test "$enable_fedora" != "no"; then
+ if test "$enable_fedora" == "yes" &&
+ test "$have_fedora" == "no" ; then
+ AC_MSG_ERROR([Fedora Account System support requested, but not available])
+ fi
+
+ enable_fedora=$have_fedora
+
+ if test "$enable_fedora" == "yes"; then
+ AC_DEFINE(GCR_API_SUBJECT_TO_CHANGE, 1, [Define to use the GCR API])
+ AC_DEFINE(GOA_FEDORA_ENABLED, 1, [Enable Fedora Account System provider])
+ fi
+else
+ enable_fedora=no
+fi
+AM_CONDITIONAL(BUILD_FEDORA, [test x$enable_fedora != xno])
+
# Flickr
AC_DEFINE(GOA_FLICKR_NAME, ["flickr"], [ProviderType and extension point name])
AC_ARG_ENABLE([flickr],
@@ -387,7 +425,7 @@ fi
# Identity service
#
-AM_CONDITIONAL(BUILD_IDENTITY_SERVICE, [test x$enable_kerberos != xno])
+AM_CONDITIONAL(BUILD_IDENTITY_SERVICE, [test x$enable_fedora != xno || test x$enable_kerberos != xno])
# Optional timerfd support
AC_MSG_CHECKING([for timerfd support])
@@ -543,6 +581,7 @@ echo "
introspection: ${found_introspection}
template file: ${with_template_file}
+ Fedora Account System provider: ${enable_fedora}
Flickr provider: ${enable_flickr} (OAuth 1.0, key:${with_flickr_consumer_key}
secret:${with_flickr_consumer_secret})
Foursquare provider: ${enable_foursquare} (id:${with_foursquare_client_id})
Google provider: ${enable_google} (OAuth 2.0, id:${with_google_client_id}
secret:${with_google_client_secret})
diff --git a/data/icons/meson.build b/data/icons/meson.build
index ba7edbe1..eb5f47e9 100644
--- a/data/icons/meson.build
+++ b/data/icons/meson.build
@@ -1,5 +1,6 @@
icon_scalable_data = [
'goa-account-facebook.svg',
+ 'goa-account-fedora.svg',
'goa-account-flickr.svg',
'goa-account-foursquare.svg',
'goa-account-google.svg',
diff --git a/data/icons/scalable/Makefile.am b/data/icons/scalable/Makefile.am
index 210b1c31..d3c0519c 100644
--- a/data/icons/scalable/Makefile.am
+++ b/data/icons/scalable/Makefile.am
@@ -3,6 +3,7 @@ NULL =
icondir = $(datadir)/icons/hicolor/scalable/apps
icon_DATA = \
goa-account-facebook.svg \
+ goa-account-fedora.svg \
goa-account-flickr.svg \
goa-account-google.svg \
goa-account-msn.svg \
diff --git a/data/icons/scalable/goa-account-fedora.svg b/data/icons/scalable/goa-account-fedora.svg
new file mode 100644
index 00000000..e4b8ef31
--- /dev/null
+++ b/data/icons/scalable/goa-account-fedora.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><g
transform="translate(1.978 1.979) scale(.22488)"><path d="M266.626
133.506c0-73.525-59.604-133.13-133.128-133.13C60.007.376.426 59.93.374 133.412v103.021c.04 16.685 13.571
30.191 30.266 30.191h102.912c73.5-.029 133.074-59.613 133.074-133.118" fill="#294172"/><path id="a"
d="M77.126 142.098h47.845v47.844c0 26.41-21.434 47.845-47.845 47.845-26.41 0-47.844-21.434-47.844-47.845
0-26.41 21.434-47.844 47.844-47.844z" fill="none" stroke="#3c6eb4" stroke-width="29.21"/><use xlink:href="#a"
transform="rotate(180 124.856 142.144)" width="1" height="1"/><path id="b" d="M139.607 127.53v62.345c0
34.504-27.975 62.48-62.48 62.48-5.235 0-8.957-.59-13.803-1.857-7.066-1.85-12.84-7.643-12.842-14.381 0-8.146
5.912-14.07 14.75-14.07 4.206 0 5.733.807 11.895.807 18.191 0 32.947-14.735 32.98-32.926V161.27a4.654 4.654 0
0 0-4.66-4.648l-21.665-.004c-8.072 0-14.594-6.439-14.594-14.533-.004-8.1
44 6.59-
14.556 14.749-14.556" fill="#fff"/><use xlink:href="#b" transform="rotate(180 124.856 142.144)" width="1"
height="1"/><path d="M243.655 243.584v-5.531l-2.529 5.798-2.461-5.798v5.531h-1.418v-8.735h1.487l2.434 5.58
2.397-5.58h1.505v8.735zm-10.333-7.272v7.272h-1.483v-7.272h-2.484v-1.463h6.449v1.463"
fill="#3c6eb4"/></g></svg>
\ No newline at end of file
diff --git a/meson.build b/meson.build
index fafea515..0213c190 100644
--- a/meson.build
+++ b/meson.build
@@ -133,6 +133,19 @@ config_h.set_quoted('GOA_FACEBOOK_CLIENT_ID', facebook_client_id)
enable_facebook = get_option('facebook')
config_h.set('GOA_FACEBOOK_ENABLED', enable_facebook)
+# Fedora
+config_h.set_quoted('GOA_FEDORA_NAME', 'fedora')
+config_h.set_quoted('GOA_FEDORA_REALM', 'FEDORAPROJECT.ORG')
+
+enable_fedora = get_option('fedora')
+if enable_fedora
+ gcr_dep = dependency('gcr-3')
+ krb5_dep = dependency('krb5')
+
+ config_h.set('GCR_API_SUBJECT_TO_CHANGE', true)
+endif
+config_h.set('GOA_FEDORA_ENABLED', enable_fedora)
+
# Flickr
config_h.set_quoted('GOA_FLICKR_NAME', 'flickr')
@@ -313,6 +326,7 @@ if enable_facebook
output += ' (OAuth 2.0, id:@0@)'.format(facebook_client_id)
endif
output += '\n'
+output += ' Fedora Account System provider: ' + enable_fedora.to_string() + '\n'
output += ' Flickr provider: ' + enable_flickr.to_string()
if enable_flickr
output += ' (OAuth 1.0, key:@0@)'.format(flickr_consumer_key)
diff --git a/meson_options.txt b/meson_options.txt
index 5e40150b..e75d4892 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -6,6 +6,8 @@ option('exchange', type: 'boolean', value: true, description: 'Enable Microsoft
option('facebook', type: 'boolean', value: true, description: 'Enable Facebook provider')
option('facebook_client_id', type: 'string', value: '297654143624603', description: 'Facebook OAuth 2.0
client id')
+option('fedora', type: 'boolean', value: true, description: 'Enable Fedora Account System provider')
+
option('flickr', type: 'boolean', value: true, description: 'Enable Flickr provider')
option('flickr_consumer_key', type: 'string', value: 'ed00ad7e0869897506e23c0d18e34d01', description:
'Flickr OAuth 1.0 consumer key')
option('flickr_consumer_secret', type: 'string', value: 'ebd556dd187188b1', description: 'Flickr OAuth 1.0
consumer secret')
diff --git a/src/goabackend/Makefile.am b/src/goabackend/Makefile.am
index f9517e12..327ba9be 100644
--- a/src/goabackend/Makefile.am
+++ b/src/goabackend/Makefile.am
@@ -102,6 +102,11 @@ libgoa_backend_1_0_la_SOURCES = \
$(top_srcdir)/src/goaidentity/goaidentitymanagererror.c \
$(NULL)
+if BUILD_FEDORA
+libgoa_backend_1_0_la_SOURCES += \
+ goafedoraprovider.h goafedoraprovider.c
+endif
+
if BUILD_KERBEROS
libgoa_backend_1_0_la_SOURCES += \
goakerberosprovider.h goakerberosprovider.c
diff --git a/src/goabackend/goafedoraprovider.c b/src/goabackend/goafedoraprovider.c
new file mode 100644
index 00000000..8dd9912b
--- /dev/null
+++ b/src/goabackend/goafedoraprovider.c
@@ -0,0 +1,1302 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright © 2019 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include "goaprovider.h"
+#include "goaprovider-priv.h"
+#include "goafedoraprovider.h"
+#include "goautils.h"
+#include "goaidentity.h"
+#include "goaidentitymanagererror.h"
+
+#include <gcr/gcr.h>
+
+#include "org.gnome.Identity.h"
+
+struct _GoaFedoraProvider
+{
+ GoaProvider parent_instance;
+};
+
+static GoaIdentityServiceManager *identity_manager;
+static GMutex identity_manager_mutex;
+static GCond identity_manager_condition;
+
+static GDBusObjectManager *object_manager;
+static GMutex object_manager_mutex;
+static GCond object_manager_condition;
+
+static void ensure_identity_manager (void);
+static void ensure_object_manager (void);
+
+static char *sign_in_identity_sync (GoaFedoraProvider *self,
+ const char *identifier,
+ const char *password,
+ const char *preauth_source,
+ GCancellable *cancellable,
+ GError **error);
+static void sign_in_thread (GTask *result,
+ GoaFedoraProvider *self,
+ gpointer task_data,
+ GCancellable *cancellable);
+static GoaIdentityServiceIdentity *get_identity_from_object_manager (GoaFedoraProvider *self,
+ const char *identifier);
+static gboolean dbus_proxy_reload_properties_sync (GDBusProxy *proxy,
+ GCancellable *cancellable);
+
+static void goa_fedora_provider_module_init (void);
+static void create_object_manager (void);
+static void create_identity_manager (void);
+
+G_DEFINE_TYPE_WITH_CODE (GoaFedoraProvider, goa_fedora_provider, GOA_TYPE_PROVIDER,
+ goa_fedora_provider_module_init ();
+ goa_provider_ensure_extension_points_registered ();
+ g_io_extension_point_implement (GOA_PROVIDER_EXTENSION_POINT_NAME,
+ g_define_type_id,
+ GOA_FEDORA_NAME,
+ 0));
+
+static void
+goa_fedora_provider_module_init (void)
+{
+ create_object_manager ();
+ create_identity_manager ();
+ g_debug ("activated Fedora provider");
+}
+
+static const gchar *
+get_provider_type (GoaProvider *provider)
+{
+ return GOA_FEDORA_NAME;
+}
+
+static gchar *
+get_provider_name (GoaProvider *provider, GoaObject *object)
+{
+ return g_strdup(_("Fedora"));
+}
+
+static GoaProviderGroup
+get_provider_group (GoaProvider *_provider)
+{
+ return GOA_PROVIDER_GROUP_BRANDED;
+}
+
+static GoaProviderFeatures
+get_provider_features (GoaProvider *_provider)
+{
+ return GOA_PROVIDER_FEATURE_BRANDED | GOA_PROVIDER_FEATURE_TICKETING;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+translate_error (GError **error)
+{
+ if (!g_dbus_error_is_remote_error (*error))
+ return;
+
+ g_dbus_error_strip_remote_error (*error);
+}
+
+static void
+sign_in_identity (GoaFedoraProvider *self,
+ const char *identifier,
+ const char *password,
+ const char *preauth_source,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *operation_result;
+
+ operation_result = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (operation_result, (gpointer) identifier);
+
+ g_object_set_data (G_OBJECT (operation_result),
+ "password",
+ (gpointer)
+ password);
+ g_object_set_data_full (G_OBJECT (operation_result),
+ "preauthentication-source",
+ g_strdup (preauth_source),
+ g_free);
+ g_task_run_in_thread (operation_result, (GTaskThreadFunc) sign_in_thread);
+
+ g_object_unref (operation_result);
+}
+
+static gchar *
+sign_in_identity_finish (GoaFedoraProvider *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ GTask *task;
+
+ g_return_val_if_fail (GOA_IS_FEDORA_PROVIDER (self), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ g_return_val_if_fail (g_task_is_valid (result, self), NULL);
+ task = G_TASK (result);
+
+ return g_task_propagate_pointer (task, error);
+}
+
+static gboolean
+get_ticket_sync (GoaFedoraProvider *self,
+ GoaObject *object,
+ gboolean is_interactive,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVariant *credentials = NULL;
+ GError *lookup_error;
+ GError *sign_in_error;
+ GoaAccount *account;
+ GoaTicketing *ticketing;
+ GVariant *details;
+ const char *identifier;
+ const char *password;
+ const char *preauth_source;
+ char *object_path = NULL;
+ gboolean ret = FALSE;
+
+ account = goa_object_get_account (object);
+ identifier = goa_account_get_identity (account);
+
+ ticketing = goa_object_get_ticketing (object);
+ if (ticketing == NULL)
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_NOT_SUPPORTED,
+ _("Ticketing is disabled for account"));
+ goto out;
+ }
+
+ details = goa_ticketing_get_details (ticketing);
+
+ preauth_source = NULL;
+ g_variant_lookup (details, "preauthentication-source", "&s", &preauth_source);
+
+ 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;
+ }
+ else if (credentials != NULL)
+ {
+ gboolean has_password;
+
+ 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;
+ }
+ }
+
+ sign_in_error = NULL;
+ object_path = sign_in_identity_sync (self,
+ identifier,
+ password,
+ preauth_source,
+ cancellable,
+ &sign_in_error);
+
+ if (sign_in_error != NULL)
+ {
+ g_propagate_error (error, sign_in_error);
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ g_clear_object (&account);
+ g_clear_object (&ticketing);
+ g_free (object_path);
+ g_clear_pointer (&credentials, g_variant_unref);
+ return ret;
+}
+
+static void
+notify_is_temporary_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+ GoaAccount *account;
+ gboolean is_temporary;
+
+ account = GOA_ACCOUNT (object);
+ is_temporary = goa_account_get_is_temporary (account);
+
+ /* Toggle IsTemporary */
+ goa_utils_keyfile_set_boolean (account, "IsTemporary", is_temporary);
+
+ /* Set/unset SessionId */
+ if (is_temporary)
+ {
+ GDBusConnection *connection;
+ const gchar *guid;
+
+ connection = G_DBUS_CONNECTION (user_data);
+ guid = g_dbus_connection_get_guid (connection);
+ goa_utils_keyfile_set_string (account, "SessionId", guid);
+ }
+ else
+ goa_utils_keyfile_remove_key (account, "SessionId");
+}
+
+static gboolean
+on_handle_get_ticket (GoaTicketing *interface,
+ GDBusMethodInvocation *invocation)
+{
+ GoaObject *object;
+ GoaAccount *account;
+ GoaProvider *provider;
+ GError *error;
+ gboolean got_ticket;
+ const gchar *id;
+ const gchar *method_name;
+ const gchar *provider_type;
+
+ object = GOA_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (interface)));
+ account = goa_object_peek_account (object);
+
+ id = goa_account_get_id (account);
+ provider_type = goa_account_get_provider_type (account);
+ method_name = g_dbus_method_invocation_get_method_name (invocation);
+ g_debug ("Handling %s for account (%s, %s)", method_name, provider_type, id);
+
+ provider = goa_provider_get_for_provider_type (provider_type);
+ error = NULL;
+ got_ticket = get_ticket_sync (GOA_FEDORA_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,
+ GDBusConnection *connection,
+ gboolean just_added,
+ GError **error)
+{
+ GoaAccount *account;
+ GoaTicketing *ticketing = NULL;
+ gboolean ticketing_enabled;
+ gboolean ret = FALSE;
+
+ if (!GOA_PROVIDER_CLASS (goa_fedora_provider_parent_class)->build_object (provider,
+ object,
+ key_file,
+ group,
+ connection,
+ 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)
+ {
+ char *preauthentication_source;
+ GVariantBuilder details;
+
+ 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);
+
+ g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
+
+ preauthentication_source = g_key_file_get_string (key_file, group, "PreauthenticationSource", NULL);
+ if (preauthentication_source)
+ g_variant_builder_add (&details, "{ss}", "preauthentication-source", preauthentication_source);
+
+ g_object_set (G_OBJECT (ticketing), "details", g_variant_builder_end (&details), NULL);
+ }
+ }
+ 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::is-temporary",
+ G_CALLBACK (notify_is_temporary_cb),
+ connection);
+
+ g_signal_connect (account,
+ "notify::ticketing-disabled",
+ G_CALLBACK (goa_util_account_notify_property_cb),
+ (gpointer) "TicketingEnabled");
+ }
+
+ ret = TRUE;
+
+ out:
+ g_clear_object (&ticketing);
+
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+ GCancellable *cancellable;
+
+ GtkDialog *dialog;
+ GMainLoop *loop;
+
+ GtkWidget *cluebar;
+ GtkWidget *cluebar_label;
+ GtkWidget *connect_button;
+ GtkWidget *progress_grid;
+
+ GtkWidget *username;
+ GtkWidget *password;
+
+ gchar *account_object_path;
+
+ GError *error;
+} AddAccountData;
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+add_entry (GtkWidget *grid,
+ gint row,
+ 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_halign (label, GTK_ALIGN_END);
+ gtk_widget_set_hexpand (label, TRUE);
+ gtk_grid_attach (GTK_GRID (grid), label, 0, row, 1, 1);
+
+ entry = gtk_entry_new ();
+ gtk_widget_set_hexpand (entry, TRUE);
+ 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;
+}
+
+static gchar *
+normalize_principal (const gchar *principal)
+{
+ gchar *domain = NULL;
+ gchar *realm = NULL;
+ gchar *ret = NULL;
+ gchar *username = NULL;
+
+ if (principal == 0 || principal[0] == '\0')
+ goto out;
+
+ if (!goa_utils_parse_email_address (principal, &username, &domain))
+ {
+ gchar *at;
+
+ at = strchr (principal, '@');
+ if (at != NULL)
+ goto out;
+
+ username = g_strdup (principal);
+ domain = g_strdup (GOA_FEDORA_REALM);
+ }
+
+ realm = g_utf8_strup (domain, -1);
+ if (g_strcmp0 (realm, GOA_FEDORA_REALM) != 0)
+ goto out;
+
+ ret = g_strconcat (username, "@", realm, NULL);
+
+ out:
+ g_free (domain);
+ g_free (realm);
+ g_free (username);
+ return ret;
+}
+
+static void
+on_username_or_password_changed (GtkEditable *editable, gpointer user_data)
+{
+ AddAccountData *data = (AddAccountData *) user_data;
+ gboolean can_add = FALSE;
+ const gchar *username;
+ gchar *principal = NULL;
+
+ username = gtk_entry_get_text (GTK_ENTRY (data->username));
+ principal = normalize_principal (username);
+ if (principal == NULL)
+ goto out;
+
+ can_add = 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 (principal);
+}
+
+static void
+create_account_details_ui (GoaProvider *provider,
+ GtkDialog *dialog,
+ GtkWidget *vbox,
+ gboolean new_account,
+ AddAccountData *data)
+{
+ GtkWidget *grid0;
+ GtkWidget *grid1;
+ GtkWidget *label;
+ GtkWidget *spinner;
+ gint row;
+ gint width;
+
+ goa_utils_set_dialog_title (provider, dialog, new_account);
+
+ grid0 = gtk_grid_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (grid0), 5);
+ gtk_widget_set_margin_bottom (grid0, 6);
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (grid0), GTK_ORIENTATION_VERTICAL);
+ gtk_grid_set_row_spacing (GTK_GRID (grid0), 12);
+ gtk_container_add (GTK_CONTAINER (vbox), grid0);
+
+ data->cluebar = gtk_info_bar_new ();
+ gtk_info_bar_set_message_type (GTK_INFO_BAR (data->cluebar), GTK_MESSAGE_ERROR);
+ gtk_widget_set_hexpand (data->cluebar, TRUE);
+ gtk_widget_set_no_show_all (data->cluebar, TRUE);
+ gtk_container_add (GTK_CONTAINER (grid0), data->cluebar);
+
+ data->cluebar_label = gtk_label_new ("");
+ gtk_label_set_line_wrap (GTK_LABEL (data->cluebar_label), TRUE);
+ gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (data->cluebar))),
+ data->cluebar_label);
+
+ grid1 = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (grid1), 12);
+ gtk_grid_set_row_spacing (GTK_GRID (grid1), 12);
+ gtk_container_add (GTK_CONTAINER (grid0), grid1);
+
+ row = 0;
+ add_entry (grid1, row++, _("User_name"), &data->username);
+ add_entry (grid1, row++, _("_Password"), &data->password);
+ gtk_entry_set_visibility (GTK_ENTRY (data->password), FALSE);
+
+ gtk_widget_grab_focus (data->username);
+ 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);
+ gtk_dialog_set_default_response (data->dialog, GTK_RESPONSE_OK);
+ gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, FALSE);
+
+ data->progress_grid = gtk_grid_new ();
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (data->progress_grid), GTK_ORIENTATION_HORIZONTAL);
+ gtk_grid_set_column_spacing (GTK_GRID (data->progress_grid), 3);
+ gtk_container_add (GTK_CONTAINER (grid0), data->progress_grid);
+
+ spinner = gtk_spinner_new ();
+ gtk_widget_set_opacity (spinner, 0.0);
+ gtk_widget_set_size_request (spinner, 20, 20);
+ gtk_spinner_start (GTK_SPINNER (spinner));
+ gtk_container_add (GTK_CONTAINER (data->progress_grid), spinner);
+
+ label = gtk_label_new (_("Connecting…"));
+ gtk_widget_set_opacity (label, 0.0);
+ gtk_container_add (GTK_CONTAINER (data->progress_grid), label);
+
+ gtk_window_get_size (GTK_WINDOW (data->dialog), &width, NULL);
+ gtk_window_set_default_size (GTK_WINDOW (data->dialog), width, -1);
+}
+
+static void
+show_progress_ui (GtkContainer *container, gboolean progress)
+{
+ GList *children;
+ GList *l;
+
+ children = gtk_container_get_children (container);
+ for (l = children; l != NULL; l = l->next)
+ {
+ GtkWidget *widget = GTK_WIDGET (l->data);
+ gdouble opacity;
+
+ opacity = progress ? 1.0 : 0.0;
+ gtk_widget_set_opacity (widget, opacity);
+ }
+
+ g_list_free (children);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+add_account_cb (GoaManager *manager, GAsyncResult *res, gpointer user_data)
+{
+ AddAccountData *data = (AddAccountData *) user_data;
+
+ goa_manager_call_add_account_finish (manager, &data->account_object_path, res, &data->error);
+ if (data->error != NULL)
+ g_dbus_error_strip_remote_error (data->error);
+
+ g_main_loop_quit (data->loop);
+}
+
+static void
+dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data)
+{
+ AddAccountData *data = (AddAccountData *) user_data;
+
+ if (response_id == GTK_RESPONSE_CANCEL || response_id == GTK_RESPONSE_DELETE_EVENT)
+ g_cancellable_cancel (data->cancellable);
+}
+
+static void
+sign_in_identity_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GoaFedoraProvider *self = GOA_FEDORA_PROVIDER (source_object);
+ AddAccountData *data = (AddAccountData *) user_data;
+ gchar *object_path = NULL;
+
+ object_path = sign_in_identity_finish (self, res, &data->error);
+ if (data->error != NULL)
+ g_dbus_error_strip_remote_error (data->error);
+
+ g_main_loop_quit (data->loop);
+ gtk_widget_set_sensitive (data->connect_button, TRUE);
+ show_progress_ui (GTK_CONTAINER (data->progress_grid), FALSE);
+
+ g_free (object_path);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GoaObject *
+add_account (GoaProvider *provider,
+ GoaClient *client,
+ GtkDialog *dialog,
+ GtkBox *vbox,
+ GError **error)
+{
+ GoaFedoraProvider *self = GOA_FEDORA_PROVIDER (provider);
+ AddAccountData data;
+ GVariantBuilder credentials;
+ GVariantBuilder details;
+ GoaObject *ret = NULL;
+ const gchar *password;
+ const gchar *provider_type;
+ const gchar *username;
+ gchar *principal = NULL;
+ gint response;
+
+ memset (&data, 0, sizeof (AddAccountData));
+ data.cancellable = g_cancellable_new ();
+ data.loop = g_main_loop_new (NULL, FALSE);
+ data.dialog = dialog;
+ data.error = NULL;
+
+ create_account_details_ui (provider, dialog, GTK_WIDGET (vbox), TRUE, &data);
+ gtk_widget_show_all (GTK_WIDGET (vbox));
+ g_signal_connect (dialog, "response", G_CALLBACK (dialog_response_cb), &data);
+
+ sign_in_again:
+ response = gtk_dialog_run (dialog);
+ if (response != GTK_RESPONSE_OK)
+ {
+ g_set_error (&data.error, GOA_ERROR, GOA_ERROR_DIALOG_DISMISSED, _("Dialog was dismissed"));
+ goto out;
+ }
+
+ username = gtk_entry_get_text (GTK_ENTRY (data.username));
+ password = gtk_entry_get_text (GTK_ENTRY (data.password));
+
+ principal = normalize_principal (username);
+
+ /* 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,
+ principal,
+ provider_type,
+ (GoaPeekInterfaceFunc) goa_object_peek_account,
+ &data.error))
+ goto out;
+
+ g_clear_object (&data.cancellable);
+ data.cancellable = g_cancellable_new ();
+
+ /* We currently don't prompt the user to choose a preauthentication
+ * source during initial sign in so we assume there's no
+ * preauthentication source
+ */
+ sign_in_identity (self, principal, password, NULL, data.cancellable, sign_in_identity_cb, &data);
+
+ gtk_widget_set_sensitive (data.connect_button, FALSE);
+ show_progress_ui (GTK_CONTAINER (data.progress_grid), TRUE);
+ g_main_loop_run (data.loop);
+
+ if (g_cancellable_is_cancelled (data.cancellable))
+ {
+ g_prefix_error (&data.error,
+ _("Dialog was dismissed (%s, %d): "),
+ g_quark_to_string (data.error->domain),
+ data.error->code);
+ data.error->domain = GOA_ERROR;
+ data.error->code = GOA_ERROR_DIALOG_DISMISSED;
+ goto out;
+ }
+ else if (data.error != NULL)
+ {
+ gchar *markup = NULL;
+
+ gtk_button_set_label (GTK_BUTTON (data.connect_button), _("_Try Again"));
+
+ markup = g_strdup_printf ("<b>%s:</b>\n%s", _("Error connecting to Fedora"), data.error->message);
+ g_clear_error (&data.error);
+
+ 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);
+
+ g_clear_pointer (&principal, g_free);
+ goto sign_in_again;
+ }
+
+ gtk_widget_hide (GTK_WIDGET (dialog));
+
+ g_variant_builder_init (&credentials, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add (&credentials, "{sv}", "password", g_variant_new_string (password));
+
+ g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
+ g_variant_builder_add (&details, "{ss}", "IsTemporary", "false");
+ g_variant_builder_add (&details, "{ss}", "TicketingEnabled", "true");
+
+ /* OK, everything is dandy, add the account */
+ /* we want the GoaClient to update before this method returns (so it
+ * can create a proxy for the new object) so run the mainloop while
+ * waiting for this to complete
+ */
+ goa_manager_call_add_account (goa_client_get_manager (client),
+ goa_provider_get_provider_type (provider),
+ principal,
+ principal,
+ g_variant_builder_end (&credentials),
+ g_variant_builder_end (&details),
+ NULL, /* GCancellable* */
+ (GAsyncReadyCallback) add_account_cb,
+ &data);
+ g_main_loop_run (data.loop);
+ if (data.error != NULL)
+ goto out;
+
+ ret = GOA_OBJECT (g_dbus_object_manager_get_object (goa_client_get_object_manager (client),
+ data.account_object_path));
+
+ out:
+ /* We might have an object even when data.error is set.
+ * eg., if we failed to store the credentials in the keyring.
+ */
+ if (data.error != NULL)
+ g_propagate_error (error, data.error);
+ else
+ g_assert (ret != NULL);
+
+ g_signal_handlers_disconnect_by_func (dialog, dialog_response_cb, &data);
+
+ g_free (data.account_object_path);
+ g_free (principal);
+ g_clear_pointer (&data.loop, g_main_loop_unref);
+ g_clear_object (&data.cancellable);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+refresh_account (GoaProvider *provider,
+ GoaClient *client,
+ GoaObject *object,
+ GtkWindow *parent,
+ GError **error)
+{
+ GoaFedoraProvider *self = GOA_FEDORA_PROVIDER (provider);
+ gboolean got_ticket;
+ GError *ticket_error = NULL;
+
+ g_return_val_if_fail (GOA_IS_FEDORA_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,
+ &ticket_error);
+
+ if (ticket_error != NULL)
+ {
+ translate_error (&ticket_error);
+ g_propagate_error (error, ticket_error);
+ }
+
+ return got_ticket;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+dbus_proxy_reload_properties_sync (GDBusProxy *proxy,
+ GCancellable *cancellable)
+{
+ GVariant *result = NULL;
+ char *name;
+ char *name_owner = NULL;
+ GVariant *value;
+ GVariantIter *iter = NULL;
+ gboolean ret = FALSE;
+
+ name_owner = g_dbus_proxy_get_name_owner (proxy);
+ result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (proxy),
+ name_owner,
+ g_dbus_proxy_get_object_path (proxy),
+ "org.freedesktop.DBus.Properties",
+ "GetAll",
+ g_variant_new ("(s)", g_dbus_proxy_get_interface_name (proxy)),
+ G_VARIANT_TYPE ("(a{sv})"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ NULL);
+ if (result == NULL)
+ goto out;
+
+ g_variant_get (result, "(a{sv})", &iter);
+ while (g_variant_iter_next (iter, "{sv}", &name, &value))
+ {
+ g_dbus_proxy_set_cached_property (proxy, name, value);
+
+ g_free (name);
+ g_variant_unref (value);
+ }
+
+ ret = TRUE;
+
+ out:
+ g_clear_pointer (&iter, g_variant_iter_free);
+ g_clear_pointer (&result, g_variant_unref);
+ g_free (name_owner);
+ return ret;
+}
+
+static gboolean
+ensure_credentials_sync (GoaProvider *provider,
+ GoaObject *object,
+ gint *out_expires_in,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GoaIdentityServiceIdentity *identity = NULL;
+ GoaAccount *account = NULL;
+ const char *identifier;
+ gint64 timestamp;
+ GDateTime *now, *expiration_time;
+ GTimeSpan time_span;
+ gboolean credentials_ensured = FALSE;
+
+ account = goa_object_get_account (object);
+ identifier = goa_account_get_identity (account);
+
+ ensure_identity_manager ();
+
+ g_mutex_lock (&identity_manager_mutex);
+ identity = get_identity_from_object_manager (GOA_FEDORA_PROVIDER (provider),
+ identifier);
+
+ if (identity != NULL)
+ {
+ if (!dbus_proxy_reload_properties_sync (G_DBUS_PROXY (identity), cancellable))
+ g_clear_object (&identity);
+ }
+
+ if (identity == NULL || !goa_identity_service_identity_get_is_signed_in (identity))
+ {
+ GError *lookup_error;
+ gboolean ticket_synced;
+
+ lookup_error = NULL;
+
+ g_mutex_unlock (&identity_manager_mutex);
+ ticket_synced = get_ticket_sync (GOA_FEDORA_PROVIDER (provider),
+ object,
+ FALSE /* Don't allow interaction */,
+ cancellable,
+ &lookup_error);
+ g_mutex_lock (&identity_manager_mutex);
+
+ if (!ticket_synced)
+ {
+ translate_error (&lookup_error);
+ g_set_error_literal (error,
+ GOA_ERROR,
+ GOA_ERROR_NOT_AUTHORIZED,
+ lookup_error->message);
+ g_error_free (lookup_error);
+ goto out;
+ }
+
+ if (identity == NULL)
+ identity = get_identity_from_object_manager (GOA_FEDORA_PROVIDER (provider),
+ identifier);
+ }
+
+ if (identity == NULL)
+ goto out;
+
+ dbus_proxy_reload_properties_sync (G_DBUS_PROXY (identity), cancellable);
+
+ 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;
+
+ if (out_expires_in != NULL)
+ *out_expires_in = (int) time_span;
+
+ credentials_ensured = TRUE;
+
+ g_date_time_unref (now);
+ g_date_time_unref (expiration_time);
+
+ out:
+ g_clear_object (&account);
+ g_clear_object (&identity);
+ g_mutex_unlock (&identity_manager_mutex);
+ return credentials_ensured;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+remove_account_in_thread_func (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GError *error;
+ GoaAccount *account = NULL;
+ GoaObject *object = GOA_OBJECT (task_data);
+ const gchar *identifier;
+
+ ensure_identity_manager ();
+
+ account = goa_object_get_account (object);
+ identifier = goa_account_get_identity (account);
+
+ g_debug ("Fedora account %s removed and should now be signed out", identifier);
+
+ error = NULL;
+ if (!goa_identity_service_manager_call_sign_out_sync (identity_manager, identifier, cancellable, &error))
+ {
+ g_task_return_error (task, error);
+ goto out;
+ }
+
+ g_task_return_boolean (task, TRUE);
+
+ out:
+ g_clear_object (&account);
+}
+
+static void
+remove_account (GoaProvider *provider,
+ GoaObject *object,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GoaFedoraProvider *self = GOA_FEDORA_PROVIDER (provider);
+ GTask *task;
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, remove_account);
+
+ g_task_set_task_data (task, g_object_ref (object), g_object_unref);
+ g_task_run_in_thread (task, remove_account_in_thread_func);
+
+ g_object_unref (task);
+}
+
+static gboolean
+remove_account_finish (GoaProvider *provider,
+ GAsyncResult *res,
+ GError **error)
+{
+ GoaFedoraProvider *self = GOA_FEDORA_PROVIDER (provider);
+ GTask *task;
+
+ g_return_val_if_fail (g_task_is_valid (res, self), FALSE);
+ task = G_TASK (res);
+
+ g_return_val_if_fail (g_task_get_source_tag (task) == remove_account, FALSE);
+
+ return g_task_propagate_boolean (task, error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GoaIdentityServiceIdentity *
+get_identity_from_object_manager (GoaFedoraProvider *self,
+ const char *identifier)
+{
+ GoaIdentityServiceIdentity *identity = NULL;
+ GList *objects, *node;
+
+ ensure_object_manager ();
+
+ g_mutex_lock (&object_manager_mutex);
+ objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (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)
+ {
+ identity = candidate_identity;
+ break;
+ }
+
+ g_object_unref (candidate_identity);
+ }
+
+ g_list_free_full (objects, (GDestroyNotify) g_object_unref);
+ g_mutex_unlock (&object_manager_mutex);
+
+ return identity;
+}
+
+static char *
+sign_in_identity_sync (GoaFedoraProvider *self,
+ const char *identifier,
+ const char *password,
+ const char *preauth_source,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GcrSecretExchange *secret_exchange;
+ char *secret_key;
+ char *return_key = NULL;
+ char *concealed_secret;
+ char *identity_object_path = NULL;
+ gboolean keys_exchanged;
+ GError *local_error;
+ GVariantBuilder details;
+
+ secret_exchange = gcr_secret_exchange_new (NULL);
+
+ secret_key = gcr_secret_exchange_begin (secret_exchange);
+ ensure_identity_manager ();
+
+ g_mutex_lock (&identity_manager_mutex);
+ keys_exchanged = goa_identity_service_manager_call_exchange_secret_keys_sync (identity_manager,
+ identifier,
+ secret_key,
+ &return_key,
+ cancellable,
+ error);
+ g_mutex_unlock (&identity_manager_mutex);
+ g_free (secret_key);
+
+ if (!keys_exchanged)
+ goto out;
+
+ if (!gcr_secret_exchange_receive (secret_exchange, return_key))
+ {
+ g_set_error (error,
+ GCR_ERROR,
+ GCR_ERROR_UNRECOGNIZED,
+ _("Identity service returned invalid key"));
+ goto out;
+ }
+
+ g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
+
+ concealed_secret = gcr_secret_exchange_send (secret_exchange, password, -1);
+ g_variant_builder_add (&details, "{ss}", "initial-password", concealed_secret);
+ g_free (concealed_secret);
+
+ if (preauth_source != NULL)
+ {
+ g_variant_builder_add (&details, "{ss}", "preauthentication-source", preauth_source);
+ }
+
+ g_mutex_lock (&identity_manager_mutex);
+
+ local_error = NULL;
+ goa_identity_service_manager_call_sign_in_sync (identity_manager,
+ identifier,
+ g_variant_builder_end (&details),
+ &identity_object_path,
+ cancellable,
+ &local_error);
+
+ if (local_error != NULL)
+ {
+ if (g_error_matches (local_error,
+ GOA_IDENTITY_MANAGER_ERROR,
+ GOA_IDENTITY_MANAGER_ERROR_ACCESSING_CREDENTIALS))
+ {
+ g_assert_not_reached ();
+ }
+
+ g_propagate_error (error, local_error);
+ }
+
+ g_mutex_unlock (&identity_manager_mutex);
+
+ out:
+ g_free (return_key);
+ g_object_unref (secret_exchange);
+ return identity_object_path;
+}
+
+static void
+sign_in_thread (GTask *task,
+ GoaFedoraProvider *self,
+ gpointer task_data G_GNUC_UNUSED,
+ GCancellable *cancellable)
+{
+ const char *identifier;
+ const char *password;
+ const char *preauth_source;
+ char *object_path;
+ GError *error;
+
+ identifier = g_task_get_source_tag (task);
+ password = g_object_get_data (G_OBJECT (task), "password");
+ preauth_source = g_object_get_data (G_OBJECT (task), "preauth-source");
+
+ error = NULL;
+ object_path = sign_in_identity_sync (self, identifier, password, preauth_source, cancellable, &error);
+ if (object_path == NULL)
+ g_task_return_error (task, error);
+ else
+ g_task_return_pointer (task, object_path, NULL);
+}
+
+
+static void
+on_object_manager_created (gpointer object,
+ GAsyncResult *result,
+ gpointer unused G_GNUC_UNUSED)
+{
+ GDBusObjectManager *manager;
+ GError *error;
+
+ error = NULL;
+ manager = goa_identity_service_object_manager_client_new_for_bus_finish (result, &error);
+ if (manager == NULL)
+ {
+ g_warning ("GoaFedoraProvider: Could not connect to identity service: %s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ g_mutex_lock (&object_manager_mutex);
+ object_manager = manager;
+ g_cond_signal (&object_manager_condition);
+ g_mutex_unlock (&object_manager_mutex);
+}
+
+static void
+create_object_manager (void)
+{
+ 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",
+ NULL,
+ (GAsyncReadyCallback)
+ on_object_manager_created,
+ NULL);
+}
+
+static void
+ensure_object_manager (void)
+{
+ g_mutex_lock (&object_manager_mutex);
+ while (object_manager == NULL)
+ g_cond_wait (&object_manager_condition, &object_manager_mutex);
+ g_mutex_unlock (&object_manager_mutex);
+}
+
+static void
+on_identity_manager_created (gpointer identity,
+ GAsyncResult *result,
+ gpointer unused G_GNUC_UNUSED)
+{
+ GoaIdentityServiceManager *manager;
+ GError *error;
+
+ error = NULL;
+ manager = goa_identity_service_manager_proxy_new_for_bus_finish (result, &error);
+ if (manager == NULL)
+ {
+ g_warning ("GoaFedoraProvider: Could not connect to identity service manager: %s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ g_mutex_lock (&identity_manager_mutex);
+ identity_manager = manager;
+ g_cond_signal (&identity_manager_condition);
+ g_mutex_unlock (&identity_manager_mutex);
+}
+
+static void
+create_identity_manager (void)
+{
+ goa_identity_service_manager_proxy_new_for_bus (G_BUS_TYPE_SESSION,
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+ "org.gnome.Identity",
+ "/org/gnome/Identity/Manager",
+ NULL,
+ (GAsyncReadyCallback)
+ on_identity_manager_created,
+ NULL);
+}
+
+static void
+ensure_identity_manager (void)
+{
+ g_mutex_lock (&identity_manager_mutex);
+ while (identity_manager == NULL)
+ g_cond_wait (&identity_manager_condition, &identity_manager_mutex);
+ g_mutex_unlock (&identity_manager_mutex);
+}
+
+static void
+goa_fedora_provider_init (GoaFedoraProvider *provider)
+{
+}
+
+static void
+goa_fedora_provider_class_init (GoaFedoraProviderClass *fedora_class)
+{
+ static volatile GQuark goa_identity_manager_error_domain = 0;
+ GoaProviderClass *provider_class;
+
+ provider_class = GOA_PROVIDER_CLASS (fedora_class);
+ provider_class->get_provider_type = get_provider_type;
+ provider_class->get_provider_name = get_provider_name;
+ provider_class->get_provider_group = get_provider_group;
+ provider_class->get_provider_features = get_provider_features;
+ provider_class->build_object = build_object;
+ provider_class->add_account = add_account;
+ provider_class->refresh_account = refresh_account;
+ provider_class->ensure_credentials_sync = ensure_credentials_sync;
+ provider_class->remove_account = remove_account;
+ provider_class->remove_account_finish = remove_account_finish;
+
+ /* this will force associating errors in the
+ * GOA_IDENTITY_MANAGER_ERROR error domain with
+ * org.gnome.Identity.Manager.Error.* errors via
+ * g_dbus_error_register_error_domain().
+ */
+ goa_identity_manager_error_domain = GOA_IDENTITY_MANAGER_ERROR;
+ goa_identity_manager_error_domain; /* shut up -Wunused-but-set-variable */
+}
diff --git a/src/goabackend/goafedoraprovider.h b/src/goabackend/goafedoraprovider.h
new file mode 100644
index 00000000..a00d4bca
--- /dev/null
+++ b/src/goabackend/goafedoraprovider.h
@@ -0,0 +1,37 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright © 2019 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION)
+#error "Only <goabackend/goabackend.h> can be included directly."
+#endif
+
+#ifndef __GOA_FEDORA_PROVIDER_H__
+#define __GOA_FEDORA_PROVIDER_H__
+
+#include <glib-object.h>
+
+#include "goaprovider-priv.h"
+
+G_BEGIN_DECLS
+
+#define GOA_TYPE_FEDORA_PROVIDER (goa_fedora_provider_get_type ())
+G_DECLARE_FINAL_TYPE (GoaFedoraProvider, goa_fedora_provider, GOA, FEDORA_PROVIDER, GoaProvider);
+
+G_END_DECLS
+
+#endif /* __GOA_FEDORA_PROVIDER_H__ */
diff --git a/src/goabackend/goaprovider.c b/src/goabackend/goaprovider.c
index f1122791..74433b58 100644
--- a/src/goabackend/goaprovider.c
+++ b/src/goabackend/goaprovider.c
@@ -1,6 +1,6 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
- * Copyright © 2011 – 2017 Red Hat, Inc.
+ * Copyright © 2011 – 2019 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
@@ -34,6 +34,10 @@
#include "goamediaserverprovider.h"
#include "goalastfmprovider.h"
+#ifdef GOA_FEDORA_ENABLED
+#include "goafedoraprovider.h"
+#endif
+
#ifdef GOA_KERBEROS_ENABLED
#include "goakerberosprovider.h"
#endif
@@ -959,6 +963,9 @@ static struct
#ifdef GOA_LASTFM_ENABLED
{ GOA_LASTFM_NAME, goa_lastfm_provider_get_type },
#endif
+#ifdef GOA_FEDORA_ENABLED
+ { GOA_FEDORA_NAME, goa_fedora_provider_get_type },
+#endif
#ifdef GOA_IMAP_SMTP_ENABLED
{ GOA_IMAP_SMTP_NAME, goa_imap_smtp_provider_get_type },
#endif
diff --git a/src/goabackend/meson.build b/src/goabackend/meson.build
index 2c3a9cff..cd1049be 100644
--- a/src/goabackend/meson.build
+++ b/src/goabackend/meson.build
@@ -93,11 +93,17 @@ cflags = [
'-DPACKAGE_WEB_EXTENSIONS_DIR="@0@"'.format(join_paths(goa_pkglibdir, 'web-extensions'))
]
+if enable_fedora
+ sources += files('goafedoraprovider.c')
+endif
+
if enable_kerberos
- sources += identity_dbus_sources + identity_manager_error_src + files('goakerberosprovider.c')
+ sources += files('goakerberosprovider.c')
+endif
+if enable_fedora or enable_kerberos
+ sources += identity_dbus_sources + identity_manager_error_src
incs += goaidentity_inc
-
deps += [gcr_dep]
endif
diff --git a/src/goaidentity/goaidentityservice.c b/src/goaidentity/goaidentityservice.c
index aa86fa95..f70dcf63 100644
--- a/src/goaidentity/goaidentityservice.c
+++ b/src/goaidentity/goaidentityservice.c
@@ -189,7 +189,7 @@ find_object_with_principal (GoaIdentityService *self,
provider_type = goa_account_get_provider_type (account);
- if (g_strcmp0 (provider_type, GOA_KERBEROS_NAME) != 0)
+ if (g_strcmp0 (provider_type, GOA_FEDORA_NAME) != 0 && g_strcmp0 (provider_type, GOA_KERBEROS_NAME) !=
0)
continue;
if (must_be_enabled)
@@ -774,6 +774,110 @@ on_identity_signed_in (GoaIdentityManager *manager,
/* ---------------------------------------------------------------------------------------------------- */
+static void
+add_temporary_account_as_fedora_add_account (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GoaIdentityService *self;
+ GDBusObjectManager *object_manager;
+ GError *error;
+ GTask *task = G_TASK (user_data);
+ GoaManager *manager = GOA_MANAGER (source_object);
+ GoaObject *object = NULL;
+ gchar *object_path = NULL;
+
+ self = GOA_IDENTITY_SERVICE (g_task_get_source_object (task));
+
+ error = NULL;
+ if (!goa_manager_call_add_account_finish (manager, &object_path, res, &error))
+ {
+ g_task_return_error (task, error);
+ goto out;
+ }
+
+ g_debug ("Created account for identity with object path %s", object_path);
+
+ object_manager = goa_client_get_object_manager (self->priv->client);
+ object = GOA_OBJECT (g_dbus_object_manager_get_object (object_manager, object_path));
+ if (object == NULL)
+ {
+ g_task_return_new_error (task,
+ GOA_ERROR,
+ GOA_ERROR_FAILED, /* TODO: more specific */
+ _("Couldn't get GoaObject for object path %s"),
+ object_path);
+ goto out;
+ }
+
+ g_task_return_pointer (task, g_object_ref (object), g_object_unref);
+
+ out:
+ g_free (object_path);
+ g_clear_object (&object);
+ g_object_unref (task);
+}
+
+static void
+add_temporary_account_as_fedora (GoaIdentityService *self,
+ GoaIdentity *identity,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task = NULL;
+ GVariantBuilder credentials;
+ GVariantBuilder details;
+ GoaManager *manager;
+ const gchar *principal;
+ gchar *preauth_source = NULL;
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, add_temporary_account_as_fedora);
+ g_task_set_task_data (task, g_object_ref (identity), g_object_unref);
+
+ principal = goa_identity_get_identifier (identity);
+
+ 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}", "IsTemporary", "true");
+
+ preauth_source = goa_kerberos_identity_get_preauthentication_source (GOA_KERBEROS_IDENTITY (identity));
+ if (preauth_source != NULL)
+ g_variant_builder_add (&details, "{ss}", "PreauthenticationSource", preauth_source);
+
+ g_variant_builder_add (&details, "{ss}", "TicketingEnabled", "true");
+
+ manager = goa_client_get_manager (self->priv->client);
+ goa_manager_call_add_account (manager,
+ GOA_FEDORA_NAME,
+ principal,
+ principal,
+ g_variant_builder_end (&credentials),
+ g_variant_builder_end (&details),
+ NULL,
+ add_temporary_account_as_fedora_add_account,
+ g_object_ref (task));
+
+ g_free (preauth_source);
+ g_object_unref (task);
+}
+
+static GoaObject *
+add_temporary_account_as_fedora_finish (GoaIdentityService *self, GAsyncResult *res, GError **error)
+{
+ GTask *task;
+
+ g_return_val_if_fail (g_task_is_valid (res, self), NULL);
+ task = G_TASK (res);
+
+ g_return_val_if_fail (g_task_get_source_tag (task) == add_temporary_account_as_fedora, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ return g_task_propagate_pointer (task, error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
add_temporary_account_as_kerberos_add_account (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
@@ -911,7 +1015,44 @@ on_temporary_account_added_as_kerberos (GObject *source_object, GAsyncResult *re
ensure_account_credentials (self, object);
out:
- g_free (object_path);
+ g_clear_object (&object);
+ g_object_unref (identity);
+}
+
+static void
+on_temporary_account_added_as_fedora (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+ GoaIdentityService *self = GOA_IDENTITY_SERVICE (source_object);
+ GError *error;
+ GoaIdentity *identity = GOA_IDENTITY (user_data);
+ GoaObject *object = NULL;
+ const gchar *principal;
+
+ error = NULL;
+ object = add_temporary_account_as_fedora_finish (self, result, &error);
+ if (error != NULL)
+ {
+ const char *identifier;
+
+ identifier = goa_identity_get_identifier (identity);
+ g_debug ("Could not add temporary Fedora account for identity %s: %s", identifier, error->message);
+
+ add_temporary_account_as_kerberos (self,
+ identity,
+ NULL,
+ on_temporary_account_added_as_kerberos,
+ g_object_ref (identity));
+
+ g_error_free (error);
+ goto out;
+ }
+
+ principal = goa_identity_get_identifier (identity);
+ g_hash_table_remove (self->priv->pending_temporary_account_results, principal);
+
+ ensure_account_credentials (self, object);
+
+ out:
g_clear_object (&object);
g_object_unref (identity);
}
@@ -921,6 +1062,7 @@ add_temporary_account (GoaIdentityService *self,
GoaIdentity *identity)
{
const char *principal;
+ gchar *realm = NULL;
principal = goa_identity_get_identifier (identity);
if (g_hash_table_contains (self->priv->pending_temporary_account_results, principal))
@@ -940,11 +1082,25 @@ add_temporary_account (GoaIdentityService *self,
g_strdup (principal),
g_object_ref (identity));
- add_temporary_account_as_kerberos (self,
- identity,
- NULL,
- on_temporary_account_added_as_kerberos,
- g_object_ref (identity));
+ realm = goa_kerberos_identity_get_realm_name (GOA_KERBEROS_IDENTITY (identity));
+ if (g_strcmp0 (realm, GOA_FEDORA_REALM) == 0)
+ {
+ add_temporary_account_as_fedora (self,
+ identity,
+ NULL,
+ on_temporary_account_added_as_fedora,
+ g_object_ref (identity));
+ }
+ else
+ {
+ add_temporary_account_as_kerberos (self,
+ identity,
+ NULL,
+ on_temporary_account_added_as_kerberos,
+ g_object_ref (identity));
+ }
+
+ g_free (realm);
}
/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/meson.build b/src/meson.build
index 3181c66f..d9a5d656 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -5,7 +5,7 @@ common_incs = [top_inc, src_inc]
subdir('goa')
if enable_goabackend
- if enable_kerberos
+ if enable_fedora or enable_kerberos
subdir('goaidentity')
endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]