Commit 922006f8 authored by John Brooks's avatar John Brooks

Add UOA auth handler and minor cleanups

parent 99d19de2
/*
* Copyright (C) 2012 Jolla Ltd.
* Contact: John Brooks <john.brooks@jollamobile.com>
*
* Based on Empathy,
* Copyright (C) 2010 Collabora Ltd.
*
* This program is free software; you can redistribute it and/or
......@@ -29,23 +33,6 @@
#include <empathy-auth-factory.h>
#include <empathy-server-sasl-handler.h>
#include <empathy-server-tls-handler.h>
#if 0
#include <empathy-tls-verifier.h>
#define DEBUG_FLAG EMPATHY_DEBUG_TLS
#include <libempathy/empathy-debug.h>
#include <libempathy/empathy-utils.h>
#include <libempathy-gtk/empathy-bad-password-dialog.h>
#include <libempathy-gtk/empathy-password-dialog.h>
#include <libempathy-gtk/empathy-tls-dialog.h>
#include <libempathy-gtk/empathy-ui-utils.h>
#include "empathy-sanity-cleaning.h"
#include <gnutls/gnutls.h>
#include <extensions/extensions.h>
#endif
#define TIMEOUT 60
......@@ -303,9 +290,9 @@ main (int argc,
return EXIT_FAILURE;
}
DEBUG ("Empathy auth client started.");
DEBUG ("SASL signon auth client started.");
if (g_getenv ("EMPATHY_PERSIST") != NULL)
if (g_getenv ("SASL_SIGNON_PERSIST") != NULL)
{
DEBUG ("Timed-exit disabled");
......
......@@ -22,13 +22,11 @@
#include "empathy-debug.h"
#include "empathy-utils.h"
//#include "empathy-keyring.h"
//#include "empathy-sasl-mechanisms.h"
#include "empathy-keyring.h"
#include "empathy-sasl-mechanisms.h"
#include "empathy-server-sasl-handler.h"
#include "empathy-server-tls-handler.h"
//#include "empathy-utils.h"
// XXX
#ifdef HAVE_UOA
#include "empathy-uoa-auth-handler.h"
#endif /* HAVE_UOA */
......@@ -648,6 +646,7 @@ empathy_auth_factory_constructed (GObject *obj)
tp_base_client_set_handler_bypass_approval (client, FALSE);
/* Handle ServerTLSConnection and ServerAuthentication channels */
/* TLS channels are disabled for now due to redundant functionality. */
#if 0
tp_base_client_take_handler_filter (client, tp_asv_new (
/* ChannelType */
......
......@@ -30,9 +30,6 @@
#include <libsignon-glib/signon-identity.h>
#include "empathy-uoa-utils.h"
#define EMPATHY_UOA_SERVICE_TYPE "IM"
#define EMPATHY_UOA_PROVIDER "im.telepathy.Account.Storage.UOA"
static AgAccountService *
uoa_password_common (TpAccount *tp_account,
GSimpleAsyncResult *result,
......
/*
* 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 <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-keyring.h"
#include "empathy-utils.h"
#include "empathy-uoa-auth-handler.h"
#include "empathy-uoa-utils.h"
#include "empathy-sasl-mechanisms.h"
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 = empathy_uoa_manager_dup ();
}
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);
}
typedef struct
{
TpChannel *channel;
AgAccountService *service;
AgAuthData *auth_data;
SignonIdentity *identity;
SignonAuthSession *session;
gchar *username;
} AuthContext;
static AuthContext *
auth_context_new (TpChannel *channel,
AgAccountService *service)
{
AuthContext *ctx;
guint cred_id;
ctx = g_slice_new0 (AuthContext);
ctx->channel = g_object_ref (channel);
ctx->service = g_object_ref (service);
ctx->auth_data = ag_account_service_get_auth_data (service);
if (ctx->auth_data == NULL)
goto out;
cred_id = ag_auth_data_get_credentials_id (ctx->auth_data);
if (cred_id == 0)
goto out;
ctx->identity = signon_identity_new_from_db (cred_id);
if (ctx->identity == NULL)
goto out;
ctx->session = signon_identity_create_session (ctx->identity,
ag_auth_data_get_method (ctx->auth_data), NULL);
if (ctx->session == NULL)
goto out;
out:
return ctx;
}
static void
auth_context_free (AuthContext *ctx)
{
g_clear_object (&ctx->channel);
g_clear_object (&ctx->service);
tp_clear_pointer (&ctx->auth_data, ag_auth_data_unref);
g_clear_object (&ctx->session);
g_clear_object (&ctx->identity);
g_free (ctx->username);
g_slice_free (AuthContext, ctx);
}
static void
auth_context_done (AuthContext *ctx)
{
tp_channel_close_async (ctx->channel, NULL, NULL);
auth_context_free (ctx);
}
static void
request_password_session_process_cb (SignonAuthSession *session,
GHashTable *session_data,
const GError *error,
gpointer user_data)
{
AuthContext *ctx = user_data;
if (error != NULL)
{
DEBUG ("Error processing the session to request user's attention: %s",
error->message);
}
auth_context_done (ctx);
}
static void
request_password (AuthContext *ctx)
{
GHashTable *extra_params;
DEBUG ("Invalid credentials, request user action");
/* Inform SSO that the access token (or password) didn't work and it should
* ask user to re-grant access (or retype password). */
extra_params = tp_asv_new (
SIGNON_SESSION_DATA_UI_POLICY, G_TYPE_INT,
SIGNON_POLICY_REQUEST_PASSWORD,
NULL);
ag_auth_data_insert_parameters (ctx->auth_data, extra_params);
signon_auth_session_process (ctx->session,
ag_auth_data_get_parameters (ctx->auth_data),
ag_auth_data_get_mechanism (ctx->auth_data),
request_password_session_process_cb, ctx);
g_hash_table_unref (extra_params);
}
static void
auth_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
TpChannel *channel = (TpChannel *) source;
AuthContext *ctx = user_data;
GError *error = NULL;
if (!empathy_sasl_auth_finish (channel, result, &error))
{
DEBUG ("SASL Mechanism error: %s", error->message);
g_clear_error (&error);
request_password (ctx);
}
else
{
DEBUG ("Auth on %s suceeded", tp_proxy_get_object_path (channel));
auth_context_done (ctx);
}
}
static void
session_process_cb (SignonAuthSession *session,
GHashTable *session_data,
const GError *error,
gpointer user_data)
{
AuthContext *ctx = user_data;
const gchar *access_token;
const gchar *client_id;
if (error != NULL)
{
DEBUG ("Error processing the session: %s", error->message);
auth_context_done (ctx);
return;
}
access_token = tp_asv_get_string (session_data, "AccessToken");
client_id = tp_asv_get_string (ag_auth_data_get_parameters (ctx->auth_data),
"ClientId");
switch (empathy_sasl_channel_select_mechanism (ctx->channel))
{
case EMPATHY_SASL_MECHANISM_FACEBOOK:
empathy_sasl_auth_facebook_async (ctx->channel,
client_id, access_token,
auth_cb, ctx);
break;
case EMPATHY_SASL_MECHANISM_WLM:
empathy_sasl_auth_wlm_async (ctx->channel,
access_token,
auth_cb, ctx);
break;
case EMPATHY_SASL_MECHANISM_GOOGLE:
empathy_sasl_auth_google_async (ctx->channel,
ctx->username, access_token,
auth_cb, ctx);
break;
case EMPATHY_SASL_MECHANISM_PASSWORD:
empathy_sasl_auth_password_async (ctx->channel,
tp_asv_get_string (session_data, "Secret"),
auth_cb, ctx);
break;
default:
g_assert_not_reached ();
}
}
static void
identity_query_info_cb (SignonIdentity *identity,
const SignonIdentityInfo *info,
const GError *error,
gpointer user_data)
{
AuthContext *ctx = user_data;
if (error != NULL)
{
DEBUG ("Error querying info from identity: %s", error->message);
auth_context_done (ctx);
return;
}
ctx->username = g_strdup (signon_identity_info_get_username (info));
signon_auth_session_process (ctx->session,
ag_auth_data_get_parameters (ctx->auth_data),
ag_auth_data_get_mechanism (ctx->auth_data),
session_process_cb,
ctx);
}
static void
set_account_password_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
TpAccount *tp_account = (TpAccount *) source;
AuthContext *ctx = user_data;
AuthContext *new_ctx;
GError *error = NULL;
if (!empathy_keyring_set_account_password_finish (tp_account, result, &error))
{
DEBUG ("Failed to set empty password on UOA account: %s", error->message);
auth_context_done (ctx);
return;
}
new_ctx = auth_context_new (ctx->channel, ctx->service);
auth_context_free (ctx);
if (new_ctx->session != NULL)
{
/* The trick worked! */
request_password (new_ctx);
return;
}
DEBUG ("Still can't get a signon session, even after setting empty pwd");
auth_context_done (new_ctx);
}
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;
AuthContext *ctx;
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, EMPATHY_UOA_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);
ctx = auth_context_new (channel, service);
if (ctx->session == NULL)
{
/* This (usually?) means we never stored credentials for this account.
* To ask user to type his password SSO needs a SignonIdentity bound to
* our account. Let's store an empty password. */
DEBUG ("Couldn't create a signon session");
empathy_keyring_set_account_password_async (tp_account, "", FALSE,
set_account_password_cb, ctx);
}
else
{
/* All is fine! Query UOA for more info */
signon_identity_query_info (ctx->identity,
identity_query_info_cb, ctx);
}
g_object_unref (service);
}
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 ||
mech == EMPATHY_SASL_MECHANISM_PASSWORD;
}
/*
* 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__*/
......@@ -4,6 +4,8 @@ CONFIG += link_pkgconfig
PKGCONFIG += libsignon-glib telepathy-glib libaccounts-glib libsoup-2.4
INCLUDEPATH += src
DEFINES += HAVE_UOA \
EMPATHY_UOA_PROVIDER=\\\"im.telepathy.Account.Storage.UOA\\\"
SOURCES += src/empathy-auth-client.c \
src/empathy-auth-factory.c \
......@@ -11,7 +13,8 @@ SOURCES += src/empathy-auth-client.c \
src/empathy-server-tls-handler.c \
src/empathy-keyring.c \
src/empathy-uoa-utils.c \
src/empathy-sasl-mechanisms.c
src/empathy-sasl-mechanisms.c \
src/empathy-uoa-auth-handler.c
HEADERS += src/empathy-auth-factory.h \
src/empathy-debug.h \
......@@ -20,7 +23,8 @@ HEADERS += src/empathy-auth-factory.h \
src/empathy-server-sasl-handler.h \
src/empathy-server-tls-handler.h \
src/empathy-uoa-utils.h \
src/empathy-utils.h
src/empathy-utils.h \
src/empathy-uoa-auth-handler.h
OTHER_FILES += org.freedesktop.Telepathy.Client.SaslSignonAuth.service \
SaslSignonAuth.client
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment