]> git.0d.be Git - empathy.git/commitdiff
Add Ubuntu Online Accounts auth handler
authorXavier Claessens <xavier.claessens@collabora.co.uk>
Mon, 16 Jul 2012 12:15:45 +0000 (14:15 +0200)
committerXavier Claessens <xavier.claessens@collabora.co.uk>
Mon, 23 Jul 2012 12:34:17 +0000 (14:34 +0200)
configure.ac
libempathy/Makefile.am
libempathy/empathy-auth-factory.c
libempathy/empathy-uoa-auth-handler.c [new file with mode: 0644]
libempathy/empathy-uoa-auth-handler.h [new file with mode: 0644]

index 290280d1c2488230ec344acd73c51c69f5af9853..ed9b560ec0a77a3531bb51e8d2ce29895027d12d 100644 (file)
@@ -76,6 +76,7 @@ NETWORK_MANAGER_REQUIRED=0.7.0
 CHAMPLAIN_REQUIRED=0.12.1
 CHEESE_GTK_REQUIRED=3.4.0
 LIBACCOUNTS_REQUIRED=1.1
+LIBSIGNON_REQUIRED=1.1
 MC_PLUGINS_REQUIRED=5.13.0
 
 # Use --enable-maintainer-mode to disable deprecated symbols,
@@ -514,6 +515,7 @@ if test "x$enable_ubuntu_online_accounts" != "xno"; then
        account-plugin
        mission-control-plugins >= $MC_PLUGINS_REQUIRED
        libaccounts-glib >= $LIBACCOUNTS_REQUIRED
+       libsignon-glib >= $LIBSIGNON_REQUIRED
     ], have_uoa="yes", have_uoa="no")
 
    # MC plugins dir
index 67e64a9f60a5dc82f752afc534328df7f9adb31a..2274b99ed9daff2c86c1b9614e396d7376bac659 100644 (file)
@@ -16,6 +16,7 @@ AM_CPPFLAGS =                                           \
        $(CONNMAN_CFLAGS)                               \
        $(UDEV_CFLAGS)                                  \
        $(GOA_CFLAGS)                                   \
+       $(UOA_CFLAGS)                                   \
        $(WARN_CFLAGS)                                  \
        $(DISABLE_DEPRECATED)
 
@@ -99,6 +100,12 @@ goa_sources = \
        empathy-goa-auth-handler.h \
        $(NULL)
 
+# these are sources that depend on Ubuntu Online Accounts
+uoa_sources = \
+       empathy-uoa-auth-handler.c \
+       empathy-uoa-auth-handler.h \
+       $(NULL)
+
 pkglib_LTLIBRARIES = libempathy.la
 
 # libempathy's API is not stable and will never be, so use -release to make the
@@ -122,6 +129,7 @@ libempathy_la_LIBADD =              \
        $(CONNMAN_LIBS) \
        $(UDEV_LIBS) \
        $(GOA_LIBS) \
+       $(UOA_LIBS) \
        $(LIBM)
 
 dtddir = $(datadir)/empathy
@@ -149,6 +157,12 @@ else
 EXTRA_DIST += $(goa_sources)
 endif
 
+if HAVE_UOA
+libempathy_la_SOURCES += $(uoa_sources)
+else
+EXTRA_DIST += $(uoa_sources)
+endif
+
 # do not distribute generated files
 nodist_libempathy_la_SOURCES =\
        $(BUILT_SOURCES)
@@ -156,6 +170,7 @@ nodist_libempathy_la_SOURCES =\
 check_c_sources = \
     $(libempathy_handwritten_source) \
     $(goa_sources) \
+    $(uoa_sources) \
     $(NULL)
 
 include $(top_srcdir)/tools/check-coding-style.mk
index 9225285773871b916606290c8b01441007ac7478..a4bc15a62030e0af0a9e3749862fc1d7b1b16ef9 100644 (file)
 #include "empathy-goa-auth-handler.h"
 #endif /* HAVE_GOA */
 
+#ifdef HAVE_UOA
+#include "empathy-uoa-auth-handler.h"
+#endif /* HAVE_UOA */
+
 #include "extensions/extensions.h"
 
 G_DEFINE_TYPE (EmpathyAuthFactory, empathy_auth_factory, TP_TYPE_BASE_CLIENT);
@@ -54,6 +58,10 @@ struct _EmpathyAuthFactoryPriv {
   EmpathyGoaAuthHandler *goa_handler;
 #endif /* HAVE_GOA */
 
+#ifdef HAVE_UOA
+  EmpathyUoaAuthHandler *uoa_handler;
+#endif /* HAVE_UOA */
+
   /* If an account failed to connect and user enters a new password to try, we
    * store it in this hash table and will try to use it next time the account
    * attemps to connect.
@@ -474,6 +482,32 @@ goa_claim_cb (GObject *source,
 }
 #endif /* HAVE_GOA */
 
+#ifdef HAVE_UOA
+static void
+uoa_claim_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  ObserveChannelsData *data = user_data;
+  EmpathyAuthFactory *self = data->self;
+  GError *error = NULL;
+
+  if (!tp_channel_dispatch_operation_claim_with_finish (data->dispatch_operation,
+          result, &error))
+    {
+      DEBUG ("Failed to claim: %s", error->message);
+      g_clear_error (&error);
+    }
+  else
+    {
+      empathy_uoa_auth_handler_start (self->priv->uoa_handler,
+          data->channel, data->account);
+    }
+
+  observe_channels_data_free (data);
+}
+#endif /* HAVE_UOA */
+
 static void
 observe_channels (TpBaseClient *client,
     TpAccount *account,
@@ -522,6 +556,20 @@ observe_channels (TpBaseClient *client,
     }
 #endif /* HAVE_GOA */
 
+#ifdef HAVE_UOA
+  /* UOA auth? */
+  if (empathy_uoa_auth_handler_supports (self->priv->uoa_handler, channel, account))
+    {
+      DEBUG ("Supported UOA account (%s), claim SASL channel",
+          tp_proxy_get_object_path (account));
+
+      tp_channel_dispatch_operation_claim_with_async (dispatch_operation,
+          client, uoa_claim_cb, data);
+      tp_observe_channels_context_accept (context);
+      return;
+    }
+#endif /* HAVE_UOA */
+
   /* Password auth? */
   if (empathy_sasl_channel_supports_mechanism (data->channel,
           "X-TELEPATHY-PASSWORD"))
@@ -589,6 +637,10 @@ empathy_auth_factory_init (EmpathyAuthFactory *self)
   self->priv->goa_handler = empathy_goa_auth_handler_new ();
 #endif /* HAVE_GOA */
 
+#ifdef HAVE_UOA
+  self->priv->uoa_handler = empathy_uoa_auth_handler_new ();
+#endif /* HAVE_UOA */
+
   self->priv->retry_passwords = g_hash_table_new_full (NULL, NULL,
       g_object_unref, g_free);
 }
@@ -657,6 +709,10 @@ empathy_auth_factory_dispose (GObject *object)
   g_object_unref (priv->goa_handler);
 #endif /* HAVE_GOA */
 
+#ifdef HAVE_UOA
+  g_object_unref (priv->uoa_handler);
+#endif /* HAVE_UOA */
+
   g_hash_table_unref (priv->retry_passwords);
 
   G_OBJECT_CLASS (empathy_auth_factory_parent_class)->dispose (object);
diff --git a/libempathy/empathy-uoa-auth-handler.c b/libempathy/empathy-uoa-auth-handler.c
new file mode 100644 (file)
index 0000000..1bfd6e1
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * empathy-auth-uoa.c - Source for Uoa SASL authentication
+ * Copyright (C) 2012 Collabora Ltd.
+ * @author Xavier Claessens <xavier.claessens@collabora.co.uk>
+ *
+ * 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+
+#include <libaccounts-glib/ag-account.h>
+#include <libaccounts-glib/ag-account-service.h>
+#include <libaccounts-glib/ag-auth-data.h>
+#include <libaccounts-glib/ag-manager.h>
+#include <libaccounts-glib/ag-service.h>
+
+#include <libsignon-glib/signon-identity.h>
+#include <libsignon-glib/signon-auth-session.h>
+
+#define DEBUG_FLAG EMPATHY_DEBUG_SASL
+#include "empathy-debug.h"
+#include "empathy-utils.h"
+#include "empathy-uoa-auth-handler.h"
+#include "empathy-sasl-mechanisms.h"
+
+#define SERVICE_TYPE "IM"
+
+struct _EmpathyUoaAuthHandlerPriv
+{
+  AgManager *manager;
+};
+
+G_DEFINE_TYPE (EmpathyUoaAuthHandler, empathy_uoa_auth_handler, G_TYPE_OBJECT);
+
+static void
+empathy_uoa_auth_handler_init (EmpathyUoaAuthHandler *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+      EMPATHY_TYPE_UOA_AUTH_HANDLER, EmpathyUoaAuthHandlerPriv);
+
+  self->priv->manager = ag_manager_new_for_service_type (SERVICE_TYPE);
+}
+
+static void
+empathy_uoa_auth_handler_dispose (GObject *object)
+{
+  EmpathyUoaAuthHandler *self = (EmpathyUoaAuthHandler *) object;
+
+  tp_clear_object (&self->priv->manager);
+
+  G_OBJECT_CLASS (empathy_uoa_auth_handler_parent_class)->dispose (object);
+}
+
+static void
+empathy_uoa_auth_handler_class_init (EmpathyUoaAuthHandlerClass *klass)
+{
+  GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+  oclass->dispose = empathy_uoa_auth_handler_dispose;
+
+  g_type_class_add_private (klass, sizeof (EmpathyUoaAuthHandlerPriv));
+}
+
+EmpathyUoaAuthHandler *
+empathy_uoa_auth_handler_new (void)
+{
+  return g_object_new (EMPATHY_TYPE_UOA_AUTH_HANDLER, NULL);
+}
+
+static void
+auth_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  TpChannel *channel = (TpChannel *) source;
+  GError *error = NULL;
+
+  if (!empathy_sasl_auth_finish (channel, result, &error))
+    {
+      DEBUG ("SASL Mechanism error: %s", error->message);
+      g_clear_error (&error);
+    }
+
+  tp_channel_close_async (channel, NULL, NULL);
+}
+
+typedef struct
+{
+  TpChannel *channel;
+  AgAuthData *auth_data;
+  SignonAuthSession *session;
+  SignonIdentity *identity;
+
+  gchar *username;
+} QueryInfoData;
+
+static QueryInfoData *
+query_info_data_new (TpChannel *channel,
+    AgAuthData *auth_data,
+    SignonAuthSession *session,
+    SignonIdentity *identity)
+{
+  QueryInfoData *data;
+
+  data = g_slice_new0 (QueryInfoData);
+  data->channel = g_object_ref (channel);
+  data->auth_data = ag_auth_data_ref (auth_data);
+  data->session = g_object_ref (session);
+  data->identity = g_object_ref (identity);
+
+  return data;
+}
+
+static void
+query_info_data_free (QueryInfoData *data)
+{
+  g_object_unref (data->channel);
+  ag_auth_data_unref (data->auth_data);
+  g_object_unref (data->session);
+  g_object_unref (data->identity);
+  g_free (data->username);
+  g_slice_free (QueryInfoData, data);
+}
+
+static void
+session_process_cb (SignonAuthSession *session,
+    GHashTable *session_data,
+    const GError *error,
+    gpointer user_data)
+{
+  QueryInfoData *data = user_data;
+  const gchar *access_token;
+  const gchar *client_id;
+
+  if (error != NULL)
+    {
+      DEBUG ("Error processing the session: %s", error->message);
+      tp_channel_close_async (data->channel, NULL, NULL);
+      query_info_data_free (data);
+      return;
+    }
+
+  access_token = tp_asv_get_string (session_data, "AccessToken");
+  client_id = tp_asv_get_string (ag_auth_data_get_parameters (data->auth_data),
+      "ClientId");
+
+  switch (empathy_sasl_channel_select_mechanism (data->channel))
+    {
+      case EMPATHY_SASL_MECHANISM_FACEBOOK:
+        empathy_sasl_auth_facebook_async (data->channel,
+            client_id, access_token,
+            auth_cb, NULL);
+        break;
+
+      case EMPATHY_SASL_MECHANISM_WLM:
+        empathy_sasl_auth_wlm_async (data->channel,
+            access_token,
+            auth_cb, NULL);
+        break;
+
+      case EMPATHY_SASL_MECHANISM_GOOGLE:
+        empathy_sasl_auth_google_async (data->channel,
+            data->username, access_token,
+            auth_cb, NULL);
+        break;
+
+      default:
+        g_assert_not_reached ();
+    }
+
+  query_info_data_free (data);
+}
+
+static void
+identity_query_info_cb (SignonIdentity *identity,
+    const SignonIdentityInfo *info,
+    const GError *error,
+    gpointer user_data)
+{
+  QueryInfoData *data = user_data;
+
+  if (error != NULL)
+    {
+      DEBUG ("Error querying info from identity: %s", error->message);
+      tp_channel_close_async (data->channel, NULL, NULL);
+      query_info_data_free (data);
+      return;
+    }
+
+  data->username = g_strdup (signon_identity_info_get_username (info));
+
+  signon_auth_session_process (data->session,
+      ag_auth_data_get_parameters (data->auth_data),
+      ag_auth_data_get_mechanism (data->auth_data),
+      session_process_cb,
+      data);
+}
+
+void
+empathy_uoa_auth_handler_start (EmpathyUoaAuthHandler *self,
+    TpChannel *channel,
+    TpAccount *tp_account)
+{
+  const GValue *id_value;
+  AgAccountId id;
+  AgAccount *account;
+  GList *l = NULL;
+  AgAccountService *service;
+  AgAuthData *auth_data;
+  guint cred_id;
+  SignonIdentity *identity;
+  SignonAuthSession *session;
+  GError *error = NULL;
+
+  g_return_if_fail (TP_IS_CHANNEL (channel));
+  g_return_if_fail (TP_IS_ACCOUNT (tp_account));
+  g_return_if_fail (empathy_uoa_auth_handler_supports (self, channel,
+      tp_account));
+
+  DEBUG ("Start UOA auth for account: %s",
+      tp_proxy_get_object_path (tp_account));
+
+  id_value = tp_account_get_storage_identifier (tp_account);
+  id = g_value_get_uint (id_value);
+
+  account = ag_manager_get_account (self->priv->manager, id);
+  if (account != NULL)
+    l = ag_account_list_services_by_type (account, SERVICE_TYPE);
+  if (l == NULL)
+    {
+      DEBUG ("Couldn't find IM service for AgAccountId %u", id);
+      g_object_unref (account);
+      tp_channel_close_async (channel, NULL, NULL);
+      return;
+    }
+
+  /* Assume there is only one IM service */
+  service = ag_account_service_new (account, l->data);
+  ag_service_list_free (l);
+  g_object_unref (account);
+
+  auth_data = ag_account_service_get_auth_data (service);
+  cred_id = ag_auth_data_get_credentials_id (auth_data);
+  identity = signon_identity_new_from_db (cred_id);
+  session = signon_identity_create_session (identity,
+      ag_auth_data_get_method (auth_data),
+      &error);
+  if (session == NULL)
+    {
+      DEBUG ("Error creating a SignonAuthSession: %s", error->message);
+      tp_channel_close_async (channel, NULL, NULL);
+      goto cleanup;
+    }
+
+  /* Query UOA for more info */
+  signon_identity_query_info (identity,
+      identity_query_info_cb,
+      query_info_data_new (channel, auth_data, session, identity));
+
+cleanup:
+  ag_auth_data_unref (auth_data);
+  g_object_unref (service);
+  g_object_unref (identity);
+  g_object_unref (session);
+}
+
+gboolean
+empathy_uoa_auth_handler_supports (EmpathyUoaAuthHandler *self,
+    TpChannel *channel,
+    TpAccount *account)
+{
+  const gchar *provider;
+  EmpathySaslMechanism mech;
+
+  g_return_val_if_fail (TP_IS_CHANNEL (channel), FALSE);
+  g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+
+  provider = tp_account_get_storage_provider (account);
+
+  if (tp_strdiff (provider, EMPATHY_UOA_PROVIDER))
+    return FALSE;
+
+  mech = empathy_sasl_channel_select_mechanism (channel);
+  return mech == EMPATHY_SASL_MECHANISM_FACEBOOK ||
+      mech == EMPATHY_SASL_MECHANISM_WLM ||
+      mech == EMPATHY_SASL_MECHANISM_GOOGLE;
+}
diff --git a/libempathy/empathy-uoa-auth-handler.h b/libempathy/empathy-uoa-auth-handler.h
new file mode 100644 (file)
index 0000000..2c61a76
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * empathy-auth-uoa.h - Header for Uoa SASL authentication
+ * Copyright (C) 2012 Collabora Ltd.
+ * @author Xavier Claessens <xavier.claessens@collabora.co.uk>
+ *
+ * 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __EMPATHY_UOA_AUTH_HANDLER_H__
+#define __EMPATHY_UOA_AUTH_HANDLER_H__
+
+#include <telepathy-glib/telepathy-glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _EmpathyUoaAuthHandler EmpathyUoaAuthHandler;
+typedef struct _EmpathyUoaAuthHandlerClass EmpathyUoaAuthHandlerClass;
+typedef struct _EmpathyUoaAuthHandlerPriv EmpathyUoaAuthHandlerPriv;
+
+struct _EmpathyUoaAuthHandlerClass {
+    GObjectClass parent_class;
+};
+
+struct _EmpathyUoaAuthHandler {
+    GObject parent;
+    EmpathyUoaAuthHandlerPriv *priv;
+};
+
+GType empathy_uoa_auth_handler_get_type (void);
+
+/* TYPE MACROS */
+#define EMPATHY_TYPE_UOA_AUTH_HANDLER \
+  (empathy_uoa_auth_handler_get_type ())
+#define EMPATHY_UOA_AUTH_HANDLER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), EMPATHY_TYPE_UOA_AUTH_HANDLER, \
+    EmpathyUoaAuthHandler))
+#define EMPATHY_UOA_AUTH_HANDLER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), EMPATHY_TYPE_UOA_AUTH_HANDLER, \
+    EmpathyUoaAuthHandlerClass))
+#define EMPATHY_IS_UOA_AUTH_HANDLER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), EMPATHY_TYPE_UOA_AUTH_HANDLER))
+#define EMPATHY_IS_UOA_AUTH_HANDLER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), EMPATHY_TYPE_UOA_AUTH_HANDLER))
+#define EMPATHY_UOA_AUTH_HANDLER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_UOA_AUTH_HANDLER, \
+    EmpathyUoaAuthHandlerClass))
+
+EmpathyUoaAuthHandler *empathy_uoa_auth_handler_new (void);
+
+void empathy_uoa_auth_handler_start (EmpathyUoaAuthHandler *self,
+    TpChannel *channel,
+    TpAccount *account);
+
+gboolean empathy_uoa_auth_handler_supports (EmpathyUoaAuthHandler *self,
+    TpChannel *channel,
+    TpAccount *account);
+
+G_END_DECLS
+
+#endif /* #ifndef __EMPATHY_UOA_AUTH_HANDLER_H__*/