2 * empathy-auth-uoa.c - Source for Uoa SASL authentication
3 * Copyright (C) 2012 Collabora Ltd.
4 * @author Xavier Claessens <xavier.claessens@collabora.co.uk>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 #include <libaccounts-glib/ag-account.h>
24 #include <libaccounts-glib/ag-account-service.h>
25 #include <libaccounts-glib/ag-auth-data.h>
26 #include <libaccounts-glib/ag-manager.h>
27 #include <libaccounts-glib/ag-service.h>
29 #include <libsignon-glib/signon-identity.h>
30 #include <libsignon-glib/signon-auth-session.h>
32 #define DEBUG_FLAG EMPATHY_DEBUG_SASL
33 #include "empathy-debug.h"
34 #include "empathy-utils.h"
35 #include "empathy-uoa-auth-handler.h"
36 #include "empathy-uoa-utils.h"
37 #include "empathy-sasl-mechanisms.h"
39 struct _EmpathyUoaAuthHandlerPriv
44 G_DEFINE_TYPE (EmpathyUoaAuthHandler, empathy_uoa_auth_handler, G_TYPE_OBJECT);
47 empathy_uoa_auth_handler_init (EmpathyUoaAuthHandler *self)
49 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
50 EMPATHY_TYPE_UOA_AUTH_HANDLER, EmpathyUoaAuthHandlerPriv);
52 self->priv->manager = empathy_uoa_manager_dup ();
56 empathy_uoa_auth_handler_dispose (GObject *object)
58 EmpathyUoaAuthHandler *self = (EmpathyUoaAuthHandler *) object;
60 tp_clear_object (&self->priv->manager);
62 G_OBJECT_CLASS (empathy_uoa_auth_handler_parent_class)->dispose (object);
66 empathy_uoa_auth_handler_class_init (EmpathyUoaAuthHandlerClass *klass)
68 GObjectClass *oclass = G_OBJECT_CLASS (klass);
70 oclass->dispose = empathy_uoa_auth_handler_dispose;
72 g_type_class_add_private (klass, sizeof (EmpathyUoaAuthHandlerPriv));
75 EmpathyUoaAuthHandler *
76 empathy_uoa_auth_handler_new (void)
78 return g_object_new (EMPATHY_TYPE_UOA_AUTH_HANDLER, NULL);
84 AgAuthData *auth_data;
85 SignonAuthSession *session;
86 SignonIdentity *identity;
91 static QueryInfoData *
92 query_info_data_new (TpChannel *channel,
93 AgAuthData *auth_data,
94 SignonAuthSession *session,
95 SignonIdentity *identity)
99 data = g_slice_new0 (QueryInfoData);
100 data->channel = g_object_ref (channel);
101 data->auth_data = ag_auth_data_ref (auth_data);
102 data->session = g_object_ref (session);
103 data->identity = g_object_ref (identity);
109 query_info_data_free (QueryInfoData *data)
111 g_object_unref (data->channel);
112 ag_auth_data_unref (data->auth_data);
113 g_object_unref (data->session);
114 g_object_unref (data->identity);
115 g_free (data->username);
116 g_slice_free (QueryInfoData, data);
120 auth_cb (GObject *source,
121 GAsyncResult *result,
124 TpChannel *channel = (TpChannel *) source;
125 QueryInfoData *data = user_data;
126 GError *error = NULL;
128 if (!empathy_sasl_auth_finish (channel, result, &error))
130 GHashTable *extra_params;
132 DEBUG ("SASL Mechanism error: %s", error->message);
133 g_clear_error (&error);
135 /* Inform SSO that the access token didn't work and it should ask user
136 * to re-grant access. */
137 extra_params = tp_asv_new (
138 SIGNON_SESSION_DATA_UI_POLICY, G_TYPE_INT,
139 SIGNON_POLICY_REQUEST_PASSWORD,
142 ag_auth_data_insert_parameters (data->auth_data, extra_params);
144 signon_auth_session_process (data->session,
145 ag_auth_data_get_parameters (data->auth_data),
146 ag_auth_data_get_mechanism (data->auth_data),
149 g_hash_table_unref (extra_params);
153 DEBUG ("Auth on %s suceeded", tp_proxy_get_object_path (channel));
156 tp_channel_close_async (channel, NULL, NULL);
157 query_info_data_free (data);
161 session_process_cb (SignonAuthSession *session,
162 GHashTable *session_data,
166 QueryInfoData *data = user_data;
167 const gchar *access_token;
168 const gchar *client_id;
172 DEBUG ("Error processing the session: %s", error->message);
173 tp_channel_close_async (data->channel, NULL, NULL);
174 query_info_data_free (data);
178 access_token = tp_asv_get_string (session_data, "AccessToken");
179 client_id = tp_asv_get_string (ag_auth_data_get_parameters (data->auth_data),
182 switch (empathy_sasl_channel_select_mechanism (data->channel))
184 case EMPATHY_SASL_MECHANISM_FACEBOOK:
185 empathy_sasl_auth_facebook_async (data->channel,
186 client_id, access_token,
190 case EMPATHY_SASL_MECHANISM_WLM:
191 empathy_sasl_auth_wlm_async (data->channel,
196 case EMPATHY_SASL_MECHANISM_GOOGLE:
197 empathy_sasl_auth_google_async (data->channel,
198 data->username, access_token,
203 g_assert_not_reached ();
208 identity_query_info_cb (SignonIdentity *identity,
209 const SignonIdentityInfo *info,
213 QueryInfoData *data = user_data;
217 DEBUG ("Error querying info from identity: %s", error->message);
218 tp_channel_close_async (data->channel, NULL, NULL);
219 query_info_data_free (data);
223 data->username = g_strdup (signon_identity_info_get_username (info));
225 signon_auth_session_process (data->session,
226 ag_auth_data_get_parameters (data->auth_data),
227 ag_auth_data_get_mechanism (data->auth_data),
233 empathy_uoa_auth_handler_start (EmpathyUoaAuthHandler *self,
235 TpAccount *tp_account)
237 const GValue *id_value;
241 AgAccountService *service;
242 AgAuthData *auth_data;
244 SignonIdentity *identity;
245 SignonAuthSession *session;
246 GError *error = NULL;
248 g_return_if_fail (TP_IS_CHANNEL (channel));
249 g_return_if_fail (TP_IS_ACCOUNT (tp_account));
250 g_return_if_fail (empathy_uoa_auth_handler_supports (self, channel,
253 DEBUG ("Start UOA auth for account: %s",
254 tp_proxy_get_object_path (tp_account));
256 id_value = tp_account_get_storage_identifier (tp_account);
257 id = g_value_get_uint (id_value);
259 account = ag_manager_get_account (self->priv->manager, id);
261 l = ag_account_list_services_by_type (account, EMPATHY_UOA_SERVICE_TYPE);
264 DEBUG ("Couldn't find IM service for AgAccountId %u", id);
265 g_object_unref (account);
266 tp_channel_close_async (channel, NULL, NULL);
270 /* Assume there is only one IM service */
271 service = ag_account_service_new (account, l->data);
272 ag_service_list_free (l);
273 g_object_unref (account);
275 auth_data = ag_account_service_get_auth_data (service);
276 cred_id = ag_auth_data_get_credentials_id (auth_data);
277 identity = signon_identity_new_from_db (cred_id);
278 session = signon_identity_create_session (identity,
279 ag_auth_data_get_method (auth_data),
283 DEBUG ("Error creating a SignonAuthSession: %s", error->message);
284 tp_channel_close_async (channel, NULL, NULL);
288 /* Query UOA for more info */
289 signon_identity_query_info (identity,
290 identity_query_info_cb,
291 query_info_data_new (channel, auth_data, session, identity));
294 ag_auth_data_unref (auth_data);
295 g_object_unref (service);
296 g_object_unref (identity);
297 g_object_unref (session);
301 empathy_uoa_auth_handler_supports (EmpathyUoaAuthHandler *self,
305 const gchar *provider;
306 EmpathySaslMechanism mech;
308 g_return_val_if_fail (TP_IS_CHANNEL (channel), FALSE);
309 g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
311 provider = tp_account_get_storage_provider (account);
313 if (tp_strdiff (provider, EMPATHY_UOA_PROVIDER))
316 mech = empathy_sasl_channel_select_mechanism (channel);
317 return mech == EMPATHY_SASL_MECHANISM_FACEBOOK ||
318 mech == EMPATHY_SASL_MECHANISM_WLM ||
319 mech == EMPATHY_SASL_MECHANISM_GOOGLE;