[gnome-online-accounts/wip/kerberos: 1/5] Allow for transient, "non-permanent" accounts
- From: Ray Strode <halfline src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-online-accounts/wip/kerberos: 1/5] Allow for transient, "non-permanent" accounts
- Date: Fri, 17 Aug 2012 04:43:56 +0000 (UTC)
commit 73d2953abec61f1391eca48a067246195a6bfe35
Author: Ray Strode <rstrode redhat com>
Date: Sun Aug 12 20:41:42 2012 -0400
Allow for transient, "non-permanent" accounts
One prerequisite for adding kerberos support to online accounts
is for it to allowr accounts to show up that weren't explicitly
previously added by the user from control-center. For instance,
if a user runs "kinit" they should still be able to see their
kerberos tickets in the dialog, and even destroy the credentials
and remove the account.
Of course these accounts have a lifetime limited to the current
session. We don't want a user to unintentionally trigger permanent
behavior by just doing a one off kinit.
data/dbus-interfaces.xml | 22 +++++
src/daemon/goadaemon.c | 141 ++++++++++++++++++++++++++++---
src/goabackend/goaprovider.c | 194 ++++++++++++++++++++++++++++++++++++++++++
src/goabackend/goaprovider.h | 18 ++++-
4 files changed, 362 insertions(+), 13 deletions(-)
---
diff --git a/data/dbus-interfaces.xml b/data/dbus-interfaces.xml
index 48ad569..9881d81 100644
--- a/data/dbus-interfaces.xml
+++ b/data/dbus-interfaces.xml
@@ -69,6 +69,20 @@
-->
<property name="Id" type="s" access="read"/>
+ <!-- IsPermanent:
+
+ Whether or not the account is remembered from session to session.
+
+ Non-permanent accounts are added implicitly when the user is granted credentials
+ from some mechanism other than Online Accounts, but that Online Accounts
+ still knows how to deal with.
+
+ They are specific to the machine/session and are silently disregarded after logout.
+
+ Accounts are permanant by default unless created with "IsPermanent" "false" detail.
+ -->
+ <property name="IsPermanent" type="b" access="read"/>
+
<!-- AttentionNeeded: Set to %TRUE if the account is in need of attention.
This is used when a human operator is needed to service the
@@ -177,6 +191,14 @@
<arg name="expires_in" type="i" direction="out"/>
</method>
+ <!--
+ EnsurePermanent:
+
+ Ensures an account is permanent. See the
+ #org.gnome.OnlineAccounts.Account:IsPermanent property
+ for more information on what that details.
+ -->
+ <method name="EnsurePermanent"/>
</interface>
<!--
diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c
index e2cca23..e2aa37a 100644
--- a/src/daemon/goadaemon.c
+++ b/src/daemon/goadaemon.c
@@ -78,6 +78,10 @@ static gboolean on_account_handle_ensure_credentials (GoaAccount *acc
GDBusMethodInvocation *invocation,
gpointer user_data);
+static gboolean on_account_handle_ensure_permanent (GoaAccount *account,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data);
+
static void goa_daemon_reload_configuration (GoaDaemon *daemon);
static void on_notification_closed (NotifyNotification *notification,
@@ -330,7 +334,8 @@ key_file_data_new (GKeyFile *key_file,
/* ---------------------------------------------------------------------------------------------------- */
static void
-add_config_file (const gchar *path,
+add_config_file (GoaDaemon *daemon,
+ const gchar *path,
GHashTable *group_name_to_key_file_data,
GList **key_files_to_free)
{
@@ -357,14 +362,48 @@ add_config_file (const gchar *path,
else
{
gchar **groups;
+ const char *guid;
gsize num_groups;
guint n;
+ guid = g_dbus_connection_get_guid (daemon->connection);
groups = g_key_file_get_groups (key_file, &num_groups);
for (n = 0; n < num_groups; n++)
{
if (g_str_has_prefix (groups[n], "Account "))
{
+ gboolean is_permanent;
+ char *session_id;
+
+ is_permanent = g_key_file_get_boolean (key_file,
+ groups[n],
+ "IsPermanent",
+ NULL);
+
+ if (!is_permanent)
+ {
+ session_id = g_key_file_get_string (key_file,
+ groups[n],
+ "SessionId",
+ NULL);
+
+ /* discard non-permanent accounts from older sessions */
+ if (session_id != NULL &&
+ g_strcmp0 (session_id, guid) != 0)
+ {
+ goa_debug ("ignoring account \"%s\" in file %s because it's stale",
+ groups[n], path);
+ g_free (groups[n]);
+ g_free (session_id);
+ continue;
+ }
+ g_free (session_id);
+ }
+ else
+ {
+ g_key_file_remove_key (key_file, groups[n], "SessionId", NULL);
+ }
+
g_hash_table_insert (group_name_to_key_file_data,
groups[n], /* steals string */
key_file_data_new (key_file, path));
@@ -585,6 +624,10 @@ process_config_entries (GoaDaemon *daemon,
"handle-ensure-credentials",
G_CALLBACK (on_account_handle_ensure_credentials),
daemon);
+ g_signal_connect (goa_object_peek_account (GOA_OBJECT (object)),
+ "handle-ensure-permanent",
+ G_CALLBACK (on_account_handle_ensure_permanent),
+ daemon);
}
g_object_unref (object);
g_free (group);
@@ -619,6 +662,9 @@ process_config_entries (GoaDaemon *daemon,
g_signal_handlers_disconnect_by_func (goa_object_peek_account (object),
G_CALLBACK (on_account_handle_ensure_credentials),
daemon);
+ g_signal_handlers_disconnect_by_func (goa_object_peek_account (object),
+ G_CALLBACK (on_account_handle_ensure_permanent),
+ daemon);
g_warn_if_fail (g_dbus_object_manager_server_unexport (daemon->object_manager, object_path));
}
g_object_unref (object);
@@ -657,7 +703,7 @@ goa_daemon_reload_configuration (GoaDaemon *daemon)
/* Read the main user config file at $HOME/.config/goa-1.0/accounts.conf */
path = g_strdup_printf ("%s/goa-1.0/accounts.conf", g_get_user_config_dir ());
- add_config_file (path, group_name_to_key_file_data, &key_files_to_free);
+ add_config_file (daemon, path, group_name_to_key_file_data, &key_files_to_free);
g_free (path);
/* now process the group_name_to_key_file_data hash table */
@@ -788,6 +834,21 @@ on_manager_handle_add_account (GoaManager *manager,
g_variant_iter_init (&iter, details);
while (g_variant_iter_next (&iter, "{&s&s}", &key, &value))
{
+ /* We treat IsPermanent special. If it's false we add in
+ * the current session guid, so it can be ignored after
+ * the session is over.
+ */
+ if (g_strcmp0 (key, "IsPermanent") == 0)
+ {
+ if (g_strcmp0 (value, "false") == 0)
+ {
+ const char *guid;
+
+ guid = g_dbus_connection_get_guid (daemon->connection);
+ g_key_file_set_string (key_file, group, "SessionId", guid);
+ }
+ }
+
g_key_file_set_string (key_file, group, key, value);
}
@@ -1105,15 +1166,15 @@ typedef struct
GoaDaemon *daemon;
GoaObject *object;
GDBusMethodInvocation *invocation;
-} EnsureCredentialsData;
+} EnsureData;
-static EnsureCredentialsData *
-ensure_credentials_data_new (GoaDaemon *daemon,
+static EnsureData *
+ensure_data_new (GoaDaemon *daemon,
GoaObject *object,
GDBusMethodInvocation *invocation)
{
- EnsureCredentialsData *data;
- data = g_slice_new0 (EnsureCredentialsData);
+ EnsureData *data;
+ data = g_slice_new0 (EnsureData);
data->daemon = g_object_ref (daemon);
data->object = g_object_ref (object);
data->invocation = invocation;
@@ -1121,11 +1182,11 @@ ensure_credentials_data_new (GoaDaemon *daemon,
}
static void
-ensure_credentials_data_unref (EnsureCredentialsData *data)
+ensure_data_unref (EnsureData *data)
{
g_object_unref (data->daemon);
g_object_unref (data->object);
- g_slice_free (EnsureCredentialsData, data);
+ g_slice_free (EnsureData, data);
}
static gboolean
@@ -1154,7 +1215,7 @@ ensure_credentials_cb (GoaProvider *provider,
GAsyncResult *res,
gpointer user_data)
{
- EnsureCredentialsData *data = user_data;
+ EnsureData *data = user_data;
gint expires_in;
GError *error;
@@ -1195,7 +1256,7 @@ ensure_credentials_cb (GoaProvider *provider,
data->invocation,
expires_in);
}
- ensure_credentials_data_unref (data);
+ ensure_data_unref (data);
}
static gboolean
@@ -1224,7 +1285,63 @@ on_account_handle_ensure_credentials (GoaAccount *account,
object,
NULL, /* GCancellable */
(GAsyncReadyCallback) ensure_credentials_cb,
- ensure_credentials_data_new (daemon, object, invocation));
+ ensure_data_new (daemon, object, invocation));
+
+ out:
+ return TRUE; /* invocation was handled */
+}
+
+static void
+ensure_permanent_cb (GoaProvider *provider,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EnsureData *data = user_data;
+ GError *error;
+
+ error= NULL;
+ if (!goa_provider_ensure_permanent_finish (provider, res, &error))
+ {
+ g_dbus_method_invocation_return_gerror (data->invocation, error);
+ g_error_free (error);
+ }
+ else
+ {
+ GoaAccount *account;
+ account = goa_object_peek_account (data->object);
+
+ goa_account_complete_ensure_permanent (account, data->invocation);
+ }
+ ensure_data_unref (data);
+}
+static gboolean
+on_account_handle_ensure_permanent (GoaAccount *account,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ GoaDaemon *daemon = GOA_DAEMON (user_data);
+ GoaProvider *provider;
+ GoaObject *object;
+
+ object = GOA_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (account)));
+ provider = goa_provider_get_for_provider_type (goa_account_get_provider_type (account));
+ if (provider == NULL)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ GOA_ERROR,
+ GOA_ERROR_FAILED,
+ "Unsupported account type %s for id %s (no provider)",
+ goa_account_get_provider_type (account),
+ goa_account_get_id (account));
+ goto out;
+ }
+
+ goa_provider_ensure_permanent (provider,
+ object,
+ NULL, /* GCancellable */
+ (GAsyncReadyCallback)
+ ensure_permanent_cb,
+ ensure_data_new (daemon, object, invocation));
out:
return TRUE; /* invocation was handled */
diff --git a/src/goabackend/goaprovider.c b/src/goabackend/goaprovider.c
index fc92d7f..41ebbdb 100644
--- a/src/goabackend/goaprovider.c
+++ b/src/goabackend/goaprovider.c
@@ -50,6 +50,11 @@ static gboolean goa_provider_ensure_credentials_sync_real (GoaProvider *provid
GCancellable *cancellable,
GError **error);
+static gboolean goa_provider_ensure_permanent_sync_real (GoaProvider *provider,
+ GoaObject *object,
+ GCancellable *cancellable,
+ GError **error);
+
static gboolean goa_provider_build_object_real (GoaProvider *provider,
GoaObjectSkeleton *object,
GKeyFile *key_file,
@@ -64,6 +69,7 @@ static void goa_provider_show_account_real (GoaProvider *provider,
GtkGrid *left,
GtkGrid *right);
+static void goa_util_remove_keyfile_key (GoaAccount *account, const gchar *key);
static guint goa_provider_get_credentials_generation_real (GoaProvider *provider);
static GIcon *goa_provider_get_provider_icon_default (GoaProvider *provider,
@@ -81,6 +87,7 @@ goa_provider_class_init (GoaProviderClass *klass)
{
klass->build_object = goa_provider_build_object_real;
klass->ensure_credentials_sync = goa_provider_ensure_credentials_sync_real;
+ klass->ensure_permanent_sync = goa_provider_ensure_permanent_sync_real;
klass->show_account = goa_provider_show_account_real;
klass->get_credentials_generation = goa_provider_get_credentials_generation_real;
klass->get_provider_icon = goa_provider_get_provider_icon_default;
@@ -521,6 +528,129 @@ goa_provider_ensure_credentials_sync (GoaProvider *provider,
return GOA_PROVIDER_GET_CLASS (provider)->ensure_credentials_sync (provider, object, out_expires_in, cancellable, error);
}
+static void
+ensure_permanent_in_thread_func (GSimpleAsyncResult *simple,
+ GoaProvider *provider,
+ GCancellable *cancellable)
+{
+ GoaObject *object;
+ GError *error;
+
+ object = g_simple_async_result_get_op_res_gpointer (simple);
+
+ error = NULL;
+ if (!goa_provider_ensure_permanent_sync (provider,
+ object,
+ cancellable,
+ &error))
+ g_simple_async_result_take_error (simple, error);
+}
+
+
+/**
+ * goa_provider_ensure_permanent:
+ * @provider: A #GoaProvider.
+ * @object: A #GoaObject with a #GoaAccount interface.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: The function to call when the request is satisfied.
+ * @user_data: Pointer to pass to @callback.
+ *
+ * Ensures that credentials for @object will be reacquired on login.
+ *
+ * When the result is ready, @callback will be called in the the <link
+ * linkend="g-main-context-push-thread-default">thread-default main
+ * loop</link> this function was called from. You can then call
+ * goa_provider_ensure_permanent_finish() to get the result
+ * of the operation.
+ *
+ * This is a virtual method where the default implementation does
+ * all the necessary work. A subclass may chain up to this default
+ * implementation.
+ */
+void
+goa_provider_ensure_permanent (GoaProvider *provider,
+ GoaObject *object,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (GOA_IS_PROVIDER (provider));
+ g_return_if_fail (GOA_IS_OBJECT (object));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ simple = g_simple_async_result_new (G_OBJECT (provider),
+ callback,
+ user_data,
+ goa_provider_ensure_permanent);
+ g_simple_async_result_set_op_res_gpointer (simple,
+ g_object_ref (object),
+ (GDestroyNotify)
+ g_object_unref);
+ g_simple_async_result_run_in_thread (simple,
+ (GSimpleAsyncThreadFunc)
+ ensure_permanent_in_thread_func,
+ G_PRIORITY_DEFAULT,
+ cancellable);
+ g_object_unref (simple);
+}
+
+/**
+ * goa_provider_ensure_permanent_finish:
+ * @provider: A #GoaProvider.
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to goa_provider_ensure_credentials().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an operation started with goa_provider_ensure_permanent().
+ *
+ * Returns: %TRUE if the account for the passed #GoaObject is now permanent, %FALSE if @error is set.
+ */
+gboolean
+goa_provider_ensure_permanent_finish (GoaProvider *provider,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+
+ g_return_val_if_fail (GOA_IS_PROVIDER (provider), FALSE);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == goa_provider_ensure_permanent);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * goa_provider_ensure_permanent_sync:
+ * @provider: A #GoaProvider.
+ * @object: A #GoaObject with a #GoaAccount interface.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like goa_provider_ensure_permanent() but blocks the
+ * calling thread until an answer is received.
+ *
+ * Returns: %TRUE if the credentials for the passed #GoaObject are valid, %FALSE if @error is set.
+ */
+gboolean
+goa_provider_ensure_permanent_sync (GoaProvider *provider,
+ GoaObject *object,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (GOA_IS_PROVIDER (provider), FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ return GOA_PROVIDER_GET_CLASS (provider)->ensure_permanent_sync (provider, object, cancellable, error);
+}
+
static gboolean
goa_provider_ensure_credentials_sync_real (GoaProvider *provider,
GoaObject *object,
@@ -537,6 +667,20 @@ goa_provider_ensure_credentials_sync_real (GoaProvider *provider,
}
static gboolean
+goa_provider_ensure_permanent_sync_real (GoaProvider *provider,
+ GoaObject *object,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GoaAccount *account;
+
+ account = goa_object_peek_account (object);
+ goa_util_remove_keyfile_key (account, "SessionId");
+
+ return TRUE;
+}
+
+static gboolean
goa_provider_build_object_real (GoaProvider *provider,
GoaObjectSkeleton *object,
GKeyFile *key_file,
@@ -852,6 +996,56 @@ goa_util_lookup_keyfile_boolean (GoaObject *object,
/* ---------------------------------------------------------------------------------------------------- */
static void
+goa_util_remove_keyfile_key (GoaAccount *account, const gchar *key)
+{
+ GError *error;
+ GKeyFile *key_file;
+ gchar *contents;
+ gchar *group;
+ gchar *path;
+ gsize length;
+
+ contents = NULL;
+
+ path = g_strdup_printf ("%s/goa-1.0/accounts.conf", g_get_user_config_dir ());
+ group = g_strdup_printf ("Account %s", goa_account_get_id (account));
+
+ key_file = g_key_file_new ();
+ error = NULL;
+ if (!g_key_file_load_from_file (key_file,
+ path,
+ G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS,
+ &error))
+ {
+ goa_warning ("Error loading keyfile %s: %s (%s, %d)",
+ path,
+ error->message,
+ g_quark_to_string (error->domain),
+ error->code);
+ g_error_free (error);
+ goto out;
+ }
+
+ g_key_file_remove_key (key_file, group, key, NULL);
+ contents = g_key_file_to_data (key_file, &length, NULL);
+
+ error = NULL;
+ if (!g_file_set_contents (path, contents, length, &error))
+ {
+ g_prefix_error (&error, "Error writing key-value-file %s: ", path);
+ goa_warning ("%s (%s, %d)", error->message, g_quark_to_string (error->domain), error->code);
+ g_error_free (error);
+ goto out;
+ }
+
+ out:
+ g_free (contents);
+ g_key_file_free (key_file);
+ g_free (group);
+ g_free (path);
+}
+
+static void
goa_util_set_keyfile_boolean (GoaAccount *account, const gchar *key, gboolean value)
{
GError *error;
diff --git a/src/goabackend/goaprovider.h b/src/goabackend/goaprovider.h
index b5e186e..0dcee5e 100644
--- a/src/goabackend/goaprovider.h
+++ b/src/goabackend/goaprovider.h
@@ -95,13 +95,16 @@ struct _GoaProviderClass
const gchar *group,
gboolean just_added,
GError **error);
-
/* virtual but with default implementation */
gboolean (*ensure_credentials_sync) (GoaProvider *provider,
GoaObject *object,
gint *out_expires_in,
GCancellable *cancellable,
GError **error);
+ gboolean (*ensure_permanent_sync) (GoaProvider *provider,
+ GoaObject *object,
+ GCancellable *cancellable,
+ GError **error);
void (*show_account) (GoaProvider *provider,
GoaClient *client,
GoaObject *object,
@@ -143,6 +146,19 @@ gboolean goa_provider_build_object (GoaProvider *provid
const gchar *group,
gboolean just_added,
GError **error);
+
+void goa_provider_ensure_permanent (GoaProvider *provider,
+ GoaObject *object,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean goa_provider_ensure_permanent_finish (GoaProvider *provider,
+ GAsyncResult *res,
+ GError **error);
+gboolean goa_provider_ensure_permanent_sync (GoaProvider *provider,
+ GoaObject *object,
+ GCancellable *cancellable,
+ GError **error);
void goa_provider_ensure_credentials (GoaProvider *provider,
GoaObject *object,
GCancellable *cancellable,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]