[evolution-data-server] Add EGoaPasswordBased.
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Add EGoaPasswordBased.
- Date: Fri, 1 Mar 2013 00:35:16 +0000 (UTC)
commit a2c78375d1d9fec35954ff87d16a4b89c2e02dbe
Author: Matthew Barnes <mbarnes redhat com>
Date: Thu Feb 28 16:45:49 2013 -0500
Add EGoaPasswordBased.
This is the GOA-equivalent to ESignonSessionPassword for UOA: a custom
EAuthenticationSession subclass that obtains passwords from the Online
Accounts service. This class does not use a password prompt.
modules/gnome-online-accounts/Makefile.am | 2 +
.../gnome-online-accounts/e-goa-password-based.c | 272 ++++++++++++++++++++
.../gnome-online-accounts/e-goa-password-based.h | 65 +++++
.../module-gnome-online-accounts.c | 116 +--------
4 files changed, 350 insertions(+), 105 deletions(-)
---
diff --git a/modules/gnome-online-accounts/Makefile.am b/modules/gnome-online-accounts/Makefile.am
index 855c7c4..0960e31 100644
--- a/modules/gnome-online-accounts/Makefile.am
+++ b/modules/gnome-online-accounts/Makefile.am
@@ -19,6 +19,8 @@ module_gnome_online_accounts_la_CPPFLAGS = \
module_gnome_online_accounts_la_SOURCES = \
module-gnome-online-accounts.c \
+ e-goa-password-based.c \
+ e-goa-password-based.h \
goaewsclient.c \
goaewsclient.h \
$(NULL)
diff --git a/modules/gnome-online-accounts/e-goa-password-based.c
b/modules/gnome-online-accounts/e-goa-password-based.c
new file mode 100644
index 0000000..c007caa
--- /dev/null
+++ b/modules/gnome-online-accounts/e-goa-password-based.c
@@ -0,0 +1,272 @@
+/*
+ * e-goa-password-based.c
+ *
+ * This program 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) version 3.
+ *
+ * This program 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 the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-goa-password-based.h"
+
+/* XXX Yeah, yeah... */
+#define GOA_API_IS_SUBJECT_TO_CHANGE
+
+#include <config.h>
+#include <goa/goa.h>
+#include <glib/gi18n-lib.h>
+
+#define E_GOA_PASSWORD_BASED_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_GOA_PASSWORD_BASED, EGoaPasswordBasedPrivate))
+
+struct _EGoaPasswordBasedPrivate {
+ gint placeholder;
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+ EGoaPasswordBased,
+ e_goa_password_based,
+ E_TYPE_AUTHENTICATION_SESSION)
+
+static GoaObject *
+e_goa_password_based_ref_account (ESourceRegistryServer *server,
+ ESource *source,
+ GoaClient *goa_client)
+{
+ GoaObject *match = NULL;
+ GList *list, *link;
+ const gchar *extension_name;
+ gchar *account_id = NULL;
+
+ extension_name = E_SOURCE_EXTENSION_GOA;
+
+ source = e_source_registry_server_find_extension (
+ server, source, extension_name);
+
+ if (source != NULL) {
+ ESourceGoa *extension;
+
+ extension = e_source_get_extension (source, extension_name);
+ account_id = e_source_goa_dup_account_id (extension);
+
+ g_object_unref (source);
+ }
+
+ if (account_id == NULL)
+ return NULL;
+
+ /* FIXME Use goa_client_lookup_by_id() once we require GOA 3.6. */
+ list = goa_client_get_accounts (goa_client);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ GoaObject *goa_object;
+ GoaAccount *goa_account;
+ const gchar *candidate_id;
+
+ goa_object = GOA_OBJECT (link->data);
+ goa_account = goa_object_get_account (goa_object);
+ candidate_id = goa_account_get_id (goa_account);
+
+ if (g_strcmp0 (account_id, candidate_id) == 0)
+ match = g_object_ref (goa_object);
+
+ g_object_unref (goa_account);
+
+ if (match != NULL)
+ break;
+ }
+
+ g_list_free_full (list, (GDestroyNotify) g_object_unref);
+
+ return match;
+}
+
+static EAuthenticationSessionResult
+e_goa_password_based_execute_sync (EAuthenticationSession *session,
+ GCancellable *cancellable,
+ GError **error)
+{
+#ifdef HAVE_GOA_PASSWORD_BASED
+ EAuthenticationSessionResult session_result;
+ ESourceAuthenticationResult auth_result;
+ ESourceAuthenticator *authenticator;
+ ESourceRegistryServer *server;
+ ESource *source = NULL;
+ GoaClient *goa_client = NULL;
+ GoaObject *goa_object = NULL;
+ GoaAccount *goa_account = NULL;
+ GoaPasswordBased *goa_password_based = NULL;
+ GString *password_string;
+ const gchar *extension_name;
+ const gchar *source_uid;
+ gchar *password = NULL;
+ gboolean use_imap_password;
+ gboolean use_smtp_password;
+ gboolean success;
+
+ goa_client = goa_client_new_sync (cancellable, error);
+ if (goa_client == NULL) {
+ session_result = E_AUTHENTICATION_SESSION_ERROR;
+ goto exit;
+ }
+
+ server = e_authentication_session_get_server (session);
+ source_uid = e_authentication_session_get_source_uid (session);
+ source = e_source_registry_server_ref_source (server, source_uid);
+
+ if (source == NULL) {
+ g_set_error (
+ error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("No such data source for UID '%s'"),
+ source_uid);
+ session_result = E_AUTHENTICATION_SESSION_ERROR;
+ goto exit;
+ }
+
+ goa_object = e_goa_password_based_ref_account (
+ server, source, goa_client);
+
+ if (goa_object == NULL) {
+ g_set_error (
+ error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("Cannot find a corresponding account in "
+ "the org.gnome.OnlineAccounts service from "
+ "which to obtain a password for '%s'"),
+ e_source_get_display_name (source));
+ session_result = E_AUTHENTICATION_SESSION_ERROR;
+ goto exit;
+ }
+
+ goa_account = goa_object_get_account (goa_object);
+ goa_password_based = goa_object_get_password_based (goa_object);
+
+ /* XXX We should only be here if the account is password based. */
+ g_return_val_if_fail (
+ goa_password_based != NULL,
+ E_AUTHENTICATION_SESSION_ERROR);
+
+ success = goa_account_call_ensure_credentials_sync (
+ goa_account, NULL, cancellable, error);
+ if (!success) {
+ session_result = E_AUTHENTICATION_SESSION_ERROR;
+ goto exit;
+ }
+
+ extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
+ use_imap_password = e_source_has_extension (source, extension_name);
+
+ extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
+ use_smtp_password = e_source_has_extension (source, extension_name);
+
+ /* Use a suitable password ID for the ESource. */
+ if (use_imap_password) {
+ goa_password_based_call_get_password_sync (
+ goa_password_based, "imap-password",
+ &password, cancellable, error);
+ } else if (use_smtp_password) {
+ goa_password_based_call_get_password_sync (
+ goa_password_based, "smtp-password",
+ &password, cancellable, error);
+ } else {
+ /* Generic fallback - password ID is not used. */
+ goa_password_based_call_get_password_sync (
+ goa_password_based, "",
+ &password, cancellable, error);
+ }
+
+ if (password == NULL) {
+ session_result = E_AUTHENTICATION_SESSION_ERROR;
+ goto exit;
+ }
+
+ authenticator = e_authentication_session_get_authenticator (session);
+ password_string = g_string_new (password);
+ auth_result = e_source_authenticator_try_password_sync (
+ authenticator, password_string, cancellable, error);
+ g_string_free (password_string, TRUE);
+
+ switch (auth_result) {
+ case E_SOURCE_AUTHENTICATION_ERROR:
+ session_result = E_AUTHENTICATION_SESSION_ERROR;
+ break;
+
+ case E_SOURCE_AUTHENTICATION_ACCEPTED:
+ session_result = E_AUTHENTICATION_SESSION_SUCCESS;
+ break;
+
+ case E_SOURCE_AUTHENTICATION_REJECTED:
+ /* FIXME Apparently applications are expected to post
+ * a desktop-wide notification about the failed
+ * authentication attempt. */
+ g_set_error (
+ error, G_IO_ERROR,
+ G_IO_ERROR_PERMISSION_DENIED,
+ _("Invalid password for '%s'"),
+ e_source_get_display_name (source));
+ session_result = E_AUTHENTICATION_SESSION_ERROR;
+ break;
+
+ default:
+ g_warn_if_reached ();
+ session_result = E_AUTHENTICATION_SESSION_DISMISSED;
+ break;
+ }
+
+exit:
+ g_clear_object (&source);
+ g_clear_object (&goa_client);
+ g_clear_object (&goa_object);
+ g_clear_object (&goa_account);
+ g_clear_object (&goa_password_based);
+
+ g_free (password);
+
+ return session_result;
+#else
+ g_return_val_if_reached (E_AUTHENTICATION_SESSION_ERROR);
+#endif /* HAVE_GOA_PASSWORD_BASED */
+}
+
+static void
+e_goa_password_based_class_init (EGoaPasswordBasedClass *class)
+{
+ EAuthenticationSessionClass *authentication_session_class;
+
+ g_type_class_add_private (class, sizeof (EGoaPasswordBasedPrivate));
+
+ authentication_session_class =
+ E_AUTHENTICATION_SESSION_CLASS (class);
+ authentication_session_class->execute_sync =
+ e_goa_password_based_execute_sync;
+}
+
+static void
+e_goa_password_based_class_finalize (EGoaPasswordBasedClass *class)
+{
+}
+
+static void
+e_goa_password_based_init (EGoaPasswordBased *session)
+{
+ session->priv = E_GOA_PASSWORD_BASED_GET_PRIVATE (session);
+}
+
+void
+e_goa_password_based_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_goa_password_based_register_type (type_module);
+}
+
diff --git a/modules/gnome-online-accounts/e-goa-password-based.h
b/modules/gnome-online-accounts/e-goa-password-based.h
new file mode 100644
index 0000000..4fd3d01
--- /dev/null
+++ b/modules/gnome-online-accounts/e-goa-password-based.h
@@ -0,0 +1,65 @@
+/*
+ * e-goa-password-based.h
+ *
+ * This program 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) version 3.
+ *
+ * This program 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 the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_GOA_PASSWORD_BASED_H
+#define E_GOA_PASSWORD_BASED_H
+
+#include <libebackend/libebackend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_GOA_PASSWORD_BASED \
+ (e_goa_password_based_get_type ())
+#define E_GOA_PASSWORD_BASED(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_GOA_PASSWORD_BASED, EGoaPasswordBased))
+#define E_GOA_PASSWORD_BASED_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_GOA_PASSWORD_BASED, EGoaPasswordBasedClass))
+#define E_IS_GOA_PASSWORD_BASED(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_GOA_PASSWORD_BASED))
+#define E_IS_GOA_PASSWORD_BASED_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_GOA_PASSWORD_BASED))
+#define E_GOA_PASSWORD_BASED_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_GOA_PASSWORD_BASED, EGoaPasswordBasedClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EGoaPasswordBased EGoaPasswordBased;
+typedef struct _EGoaPasswordBasedClass EGoaPasswordBasedClass;
+typedef struct _EGoaPasswordBasedPrivate EGoaPasswordBasedPrivate;
+
+struct _EGoaPasswordBased {
+ EAuthenticationSession parent;
+ EGoaPasswordBasedPrivate *priv;
+};
+
+struct _EGoaPasswordBasedClass {
+ EAuthenticationSessionClass parent_class;
+};
+
+GType e_goa_password_based_get_type (void) G_GNUC_CONST;
+void e_goa_password_based_type_register
+ (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_GOA_PASSWORD_BASED_H */
+
diff --git a/modules/gnome-online-accounts/module-gnome-online-accounts.c
b/modules/gnome-online-accounts/module-gnome-online-accounts.c
index 0e211c2..45e6f39 100644
--- a/modules/gnome-online-accounts/module-gnome-online-accounts.c
+++ b/modules/gnome-online-accounts/module-gnome-online-accounts.c
@@ -22,12 +22,12 @@
#include <config.h>
#include <goa/goa.h>
#include <glib/gi18n-lib.h>
-#include <libsecret/secret.h>
#include <libsoup/soup.h>
#include <libebackend/libebackend.h>
#include "goaewsclient.h"
+#include "e-goa-password-based.h"
/* Standard GObject macros */
#define E_TYPE_GNOME_ONLINE_ACCOUNTS \
@@ -59,25 +59,6 @@ struct _EGnomeOnlineAccountsClass {
EExtensionClass parent_class;
};
-/* The keyring definintions are copied from e-authentication-session.c */
-
-#define KEYRING_ITEM_ATTRIBUTE_NAME "e-source-uid"
-#define KEYRING_ITEM_DISPLAY_FORMAT "Evolution Data Source %s"
-
-#ifdef HAVE_GOA_PASSWORD_BASED
-/* XXX Probably want to share this with
- * evolution-source-registry-migrate-sources.c */
-static SecretSchema schema = {
- "org.gnome.Evolution.DataSource",
- SECRET_SCHEMA_DONT_MATCH_NAME,
- {
- { KEYRING_ITEM_ATTRIBUTE_NAME,
- SECRET_SCHEMA_ATTRIBUTE_STRING },
- { NULL, 0 }
- }
-};
-#endif /* HAVE_GOA_PASSWORD_BASED */
-
/* Module Entry Points */
void e_module_load (GTypeModule *type_module);
void e_module_unload (GTypeModule *type_module);
@@ -582,90 +563,6 @@ gnome_online_accounts_config_oauth2 (EGnomeOnlineAccounts *extension,
}
static void
-gnome_online_accounts_config_password (EGnomeOnlineAccounts *extension,
- ESource *source,
- GoaObject *goa_object)
-{
-#ifdef HAVE_GOA_PASSWORD_BASED
- GoaAccount *goa_account;
- GoaPasswordBased *goa_password_based;
- EAsyncClosure *closure;
- GAsyncResult *result;
- const gchar *uid;
- gchar *arg_id;
- gchar *display_name;
- gchar *password = NULL;
- GError *error = NULL;
-
- /* If the GNOME Online Account is password-based, we use its
- * password to seed our own keyring entry for the collection
- * source which avoids having to special-case authentication
- * like we do for OAuth. Plus, if the stored password is no
- * good we'll prompt for a new one instead of just giving up. */
-
- goa_password_based = goa_object_get_password_based (goa_object);
-
- if (goa_password_based == NULL)
- return;
-
- closure = e_async_closure_new ();
-
- /* XXX The GOA documentation doesn't explain the string
- * argument in goa_password_based_get_password() so
- * we'll pass in the identity and hope for the best. */
- goa_account = goa_object_get_account (goa_object);
- arg_id = goa_account_dup_identity (goa_account);
- g_object_unref (goa_account);
-
- goa_password_based_call_get_password (
- goa_password_based, arg_id, NULL,
- e_async_closure_callback, closure);
-
- g_free (arg_id);
-
- result = e_async_closure_wait (closure);
-
- goa_password_based_call_get_password_finish (
- goa_password_based, &password, result, &error);
-
- if (error != NULL) {
- g_warning ("%s: %s", G_STRFUNC, error->message);
- g_error_free (error);
- goto exit;
- }
-
- uid = e_source_get_uid (source);
- display_name = g_strdup_printf (KEYRING_ITEM_DISPLAY_FORMAT, uid);
-
- secret_password_store (
- &schema, SECRET_COLLECTION_DEFAULT,
- display_name, password, NULL,
- e_async_closure_callback, closure,
- KEYRING_ITEM_ATTRIBUTE_NAME, uid,
- NULL);
-
- result = e_async_closure_wait (closure);
-
- secret_password_store_finish (result, &error);
-
- g_free (display_name);
- g_free (password);
-
- /* If we fail to store the password, we'll just end up prompting
- * for a password like normal. Annoying, maybe, but not the end
- * of the world. Still leave a breadcrumb for debugging though. */
- if (error != NULL) {
- g_warning ("%s: %s", G_STRFUNC, error->message);
- g_error_free (error);
- }
-
-exit:
- e_async_closure_free (closure);
- g_object_unref (goa_password_based);
-#endif /* HAVE_GOA_PASSWORD_BASED */
-}
-
-static void
gnome_online_accounts_config_collection (EGnomeOnlineAccounts *extension,
ESource *source,
GoaObject *goa_object)
@@ -764,12 +661,20 @@ gnome_online_accounts_config_collection (EGnomeOnlineAccounts *extension,
/* Handle optional GOA interfaces. */
gnome_online_accounts_config_exchange (extension, source, goa_object);
- gnome_online_accounts_config_password (extension, source, goa_object);
/* The data source should not be removable by clients. */
e_server_side_source_set_removable (
E_SERVER_SIDE_SOURCE (source), FALSE);
+#ifdef HAVE_GOA_PASSWORD_BASED
+ if (goa_object_peek_password_based (goa_object) != NULL) {
+ /* Obtain passwords from the OnlineAccounts service. */
+ e_server_side_source_set_auth_session_type (
+ E_SERVER_SIDE_SOURCE (source),
+ E_TYPE_GOA_PASSWORD_BASED);
+ }
+#endif /* HAVE_GOA_PASSWORD_BASED */
+
if (goa_object_peek_oauth2_based (goa_object) != NULL) {
/* This module provides OAuth 2.0 support to the collection.
* Note, children of the collection source will automatically
@@ -1406,6 +1311,7 @@ e_gnome_online_accounts_init (EGnomeOnlineAccounts *extension)
G_MODULE_EXPORT void
e_module_load (GTypeModule *type_module)
{
+ e_goa_password_based_type_register (type_module);
e_gnome_online_accounts_register_type (type_module);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]