]> git.0d.be Git - empathy.git/blob - libempathy/empathy-uoa-auth-handler.c
UOA: Use an AgManager singleton
[empathy.git] / libempathy / empathy-uoa-auth-handler.c
1 /*
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>
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22
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>
28
29 #include <libsignon-glib/signon-identity.h>
30 #include <libsignon-glib/signon-auth-session.h>
31
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"
38
39 struct _EmpathyUoaAuthHandlerPriv
40 {
41   AgManager *manager;
42 };
43
44 G_DEFINE_TYPE (EmpathyUoaAuthHandler, empathy_uoa_auth_handler, G_TYPE_OBJECT);
45
46 static void
47 empathy_uoa_auth_handler_init (EmpathyUoaAuthHandler *self)
48 {
49   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
50       EMPATHY_TYPE_UOA_AUTH_HANDLER, EmpathyUoaAuthHandlerPriv);
51
52   self->priv->manager = empathy_uoa_manager_dup ();
53 }
54
55 static void
56 empathy_uoa_auth_handler_dispose (GObject *object)
57 {
58   EmpathyUoaAuthHandler *self = (EmpathyUoaAuthHandler *) object;
59
60   tp_clear_object (&self->priv->manager);
61
62   G_OBJECT_CLASS (empathy_uoa_auth_handler_parent_class)->dispose (object);
63 }
64
65 static void
66 empathy_uoa_auth_handler_class_init (EmpathyUoaAuthHandlerClass *klass)
67 {
68   GObjectClass *oclass = G_OBJECT_CLASS (klass);
69
70   oclass->dispose = empathy_uoa_auth_handler_dispose;
71
72   g_type_class_add_private (klass, sizeof (EmpathyUoaAuthHandlerPriv));
73 }
74
75 EmpathyUoaAuthHandler *
76 empathy_uoa_auth_handler_new (void)
77 {
78   return g_object_new (EMPATHY_TYPE_UOA_AUTH_HANDLER, NULL);
79 }
80
81 typedef struct
82 {
83   TpChannel *channel;
84   AgAuthData *auth_data;
85   SignonAuthSession *session;
86   SignonIdentity *identity;
87
88   gchar *username;
89 } QueryInfoData;
90
91 static QueryInfoData *
92 query_info_data_new (TpChannel *channel,
93     AgAuthData *auth_data,
94     SignonAuthSession *session,
95     SignonIdentity *identity)
96 {
97   QueryInfoData *data;
98
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);
104
105   return data;
106 }
107
108 static void
109 query_info_data_free (QueryInfoData *data)
110 {
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);
117 }
118
119 static void
120 auth_cb (GObject *source,
121     GAsyncResult *result,
122     gpointer user_data)
123 {
124   TpChannel *channel = (TpChannel *) source;
125   QueryInfoData *data = user_data;
126   GError *error = NULL;
127
128   if (!empathy_sasl_auth_finish (channel, result, &error))
129     {
130       GHashTable *extra_params;
131
132       DEBUG ("SASL Mechanism error: %s", error->message);
133       g_clear_error (&error);
134
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,
140           NULL);
141
142       ag_auth_data_insert_parameters (data->auth_data, extra_params);
143
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),
147           NULL, NULL);
148
149       g_hash_table_unref (extra_params);
150     }
151   else
152     {
153       DEBUG ("Auth on %s suceeded", tp_proxy_get_object_path (channel));
154     }
155
156   tp_channel_close_async (channel, NULL, NULL);
157   query_info_data_free (data);
158 }
159
160 static void
161 session_process_cb (SignonAuthSession *session,
162     GHashTable *session_data,
163     const GError *error,
164     gpointer user_data)
165 {
166   QueryInfoData *data = user_data;
167   const gchar *access_token;
168   const gchar *client_id;
169
170   if (error != NULL)
171     {
172       DEBUG ("Error processing the session: %s", error->message);
173       tp_channel_close_async (data->channel, NULL, NULL);
174       query_info_data_free (data);
175       return;
176     }
177
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),
180       "ClientId");
181
182   switch (empathy_sasl_channel_select_mechanism (data->channel))
183     {
184       case EMPATHY_SASL_MECHANISM_FACEBOOK:
185         empathy_sasl_auth_facebook_async (data->channel,
186             client_id, access_token,
187             auth_cb, data);
188         break;
189
190       case EMPATHY_SASL_MECHANISM_WLM:
191         empathy_sasl_auth_wlm_async (data->channel,
192             access_token,
193             auth_cb, data);
194         break;
195
196       case EMPATHY_SASL_MECHANISM_GOOGLE:
197         empathy_sasl_auth_google_async (data->channel,
198             data->username, access_token,
199             auth_cb, data);
200         break;
201
202       default:
203         g_assert_not_reached ();
204     }
205 }
206
207 static void
208 identity_query_info_cb (SignonIdentity *identity,
209     const SignonIdentityInfo *info,
210     const GError *error,
211     gpointer user_data)
212 {
213   QueryInfoData *data = user_data;
214
215   if (error != NULL)
216     {
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);
220       return;
221     }
222
223   data->username = g_strdup (signon_identity_info_get_username (info));
224
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),
228       session_process_cb,
229       data);
230 }
231
232 void
233 empathy_uoa_auth_handler_start (EmpathyUoaAuthHandler *self,
234     TpChannel *channel,
235     TpAccount *tp_account)
236 {
237   const GValue *id_value;
238   AgAccountId id;
239   AgAccount *account;
240   GList *l = NULL;
241   AgAccountService *service;
242   AgAuthData *auth_data;
243   guint cred_id;
244   SignonIdentity *identity;
245   SignonAuthSession *session;
246   GError *error = NULL;
247
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,
251       tp_account));
252
253   DEBUG ("Start UOA auth for account: %s",
254       tp_proxy_get_object_path (tp_account));
255
256   id_value = tp_account_get_storage_identifier (tp_account);
257   id = g_value_get_uint (id_value);
258
259   account = ag_manager_get_account (self->priv->manager, id);
260   if (account != NULL)
261     l = ag_account_list_services_by_type (account, EMPATHY_UOA_SERVICE_TYPE);
262   if (l == NULL)
263     {
264       DEBUG ("Couldn't find IM service for AgAccountId %u", id);
265       g_object_unref (account);
266       tp_channel_close_async (channel, NULL, NULL);
267       return;
268     }
269
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);
274
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),
280       &error);
281   if (session == NULL)
282     {
283       DEBUG ("Error creating a SignonAuthSession: %s", error->message);
284       tp_channel_close_async (channel, NULL, NULL);
285       goto cleanup;
286     }
287
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));
292
293 cleanup:
294   ag_auth_data_unref (auth_data);
295   g_object_unref (service);
296   g_object_unref (identity);
297   g_object_unref (session);
298 }
299
300 gboolean
301 empathy_uoa_auth_handler_supports (EmpathyUoaAuthHandler *self,
302     TpChannel *channel,
303     TpAccount *account)
304 {
305   const gchar *provider;
306   EmpathySaslMechanism mech;
307
308   g_return_val_if_fail (TP_IS_CHANNEL (channel), FALSE);
309   g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
310
311   provider = tp_account_get_storage_provider (account);
312
313   if (tp_strdiff (provider, EMPATHY_UOA_PROVIDER))
314     return FALSE;
315
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;
320 }