[evolution-data-server] Add EGoaPasswordBased.



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]