Refresh upstream 2.1.0 release
[profile/ivi/libgsignon-glib.git] / libgsignon-glib / signon-auth-session.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of libgsignon-glib
5  *
6  * Copyright (C) 2009-2010 Nokia Corporation.
7  * Copyright (C) 2012 Canonical Ltd.
8  * Copyright (C) 2012-2014 Intel Corporation.
9  *
10  * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
11  * Contact: Jussi Laako <jussi.laako@linux.intel.com>
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public License
15  * version 2.1 as published by the Free Software Foundation.
16  *
17  * This library is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
25  * 02110-1301 USA
26  */
27
28 /**
29  * SECTION:signon-auth-session
30  * @title: SignonAuthSession
31  * @short_description: the authentication session object
32  *
33  * The #SignonAuthSession object is responsible for handling the client
34  * authentication. #SignonAuthSession objects should be created from existing
35  * identities (via signon_identity_create_session() or by passing a non-NULL identity
36  * to signon_auth_session_new()).
37  */
38
39 #include "signon-internals.h"
40 #include "signon-auth-session.h"
41 #include "signon-dbus-queue.h"
42 #include "signon-errors.h"
43 #include "signon-marshal.h"
44 #include "signon-utils.h"
45 #include "signon-identity.h"
46 #include "sso-auth-service.h"
47 #include "sso-auth-session-gen.h"
48
49
50 G_DEFINE_TYPE (SignonAuthSession, signon_auth_session, G_TYPE_OBJECT);
51
52 enum
53 {
54     PROP_0,
55     PROP_IDENTITY,
56     PROP_APPCTX
57 };
58
59 /* Signals */
60 enum
61 {
62     STATE_CHANGED,
63     LAST_SIGNAL
64 };
65
66 static guint auth_session_signals[LAST_SIGNAL] = { 0 };
67 static const gchar auth_session_process_pending_message[] =
68     "The request is added to queue.";
69 static const gchar data_key_process[] = "signon-process";
70
71 struct _SignonAuthSessionPrivate
72 {
73     SsoAuthSession *proxy;
74     SignonIdentity *identity;
75     GCancellable *cancellable;
76
77     guint id;
78     gchar *method_name;
79
80     gboolean registering;
81     gboolean busy;
82     gboolean canceled;
83     gboolean dispose_has_run;
84
85     guint signal_state_changed;
86     guint signal_unregistered;
87 };
88
89 typedef struct _AuthSessionQueryAvailableMechanismsData
90 {
91     gchar **wanted_mechanisms;
92     gpointer cb_data;
93 } AuthSessionQueryAvailableMechanismsData;
94
95 typedef struct _AuthSessionProcessData
96 {
97     GVariant *session_data;
98     gchar *mechanism;
99     GCancellable *cancellable;
100 } AuthSessionProcessData;
101
102 typedef struct _AuthSessionQueryAvailableMechanismsCbData
103 {
104     SignonAuthSession *self;
105     SignonAuthSessionQueryAvailableMechanismsCb cb;
106     gpointer user_data;
107 } AuthSessionQueryAvailableMechanismsCbData;
108
109 typedef struct _AuthSessionProcessCbData
110 {
111     SignonAuthSessionProcessCb cb;
112     gpointer user_data;
113 } AuthSessionProcessCbData;
114
115 #define SIGNON_AUTH_SESSION_PRIV(obj) (SIGNON_AUTH_SESSION(obj)->priv)
116 #define SIGNON_AUTH_SESSION_GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), SIGNON_TYPE_AUTH_SESSION, SignonAuthSessionPrivate))
117
118
119 static void auth_session_state_changed_cb (GDBusProxy *proxy, gint state, gchar *message, gpointer user_data);
120 static void auth_session_remote_object_destroyed_cb (GDBusProxy *proxy, gpointer user_data);
121
122 static gboolean auth_session_priv_init (SignonAuthSession *self, const gchar *method_name, GError **err);
123
124 static void auth_session_query_available_mechanisms_ready_cb (gpointer object, const GError *error, gpointer user_data);
125 static void auth_session_cancel_ready_cb (gpointer object, const GError *error, gpointer user_data);
126
127 static void auth_session_check_remote_object(SignonAuthSession *self);
128
129 static void
130 auth_session_process_data_free (AuthSessionProcessData *process_data)
131 {
132     g_free (process_data->mechanism);
133     g_variant_unref (process_data->session_data);
134     g_slice_free (AuthSessionProcessData, process_data);
135 }
136
137 static void
138 auth_session_process_reply (GObject *object, GAsyncResult *res,
139                             gpointer userdata)
140 {
141     SignonAuthSession *self;
142     SsoAuthSession *proxy = SSO_AUTH_SESSION (object);
143     GSimpleAsyncResult *res_process = (GSimpleAsyncResult *)userdata;
144     GVariant *reply;
145     GError *error = NULL;
146
147     g_return_if_fail (res_process != NULL);
148     DEBUG ("%s %d", G_STRFUNC, __LINE__);
149
150     sso_auth_session_call_process_finish (proxy, &reply, res, &error);
151
152     self = SIGNON_AUTH_SESSION (g_async_result_get_source_object (
153         (GAsyncResult *)res_process));
154     self->priv->busy = FALSE;
155
156     if (G_LIKELY (error == NULL))
157     {
158         g_simple_async_result_set_op_res_gpointer (res_process, reply,
159                                                    (GDestroyNotify)
160                                                    g_variant_unref);
161     }
162     else
163     {
164         g_simple_async_result_take_error (res_process, error);
165     }
166
167     /* We use the idle variant in order to avoid the following critical
168      * message:
169      * g_main_context_pop_thread_default: assertion `g_queue_peek_head (stack) == context' failed
170      */
171     g_simple_async_result_complete_in_idle (res_process);
172     g_object_unref (res_process);
173     g_object_unref (self);
174 }
175
176 static void
177 auth_session_process_ready_cb (gpointer object, const GError *error, gpointer user_data)
178 {
179     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
180     SignonAuthSessionPrivate *priv;
181     GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
182     AuthSessionProcessData *process_data;
183
184     g_return_if_fail (self != NULL);
185     priv = self->priv;
186
187     if (error != NULL)
188     {
189         DEBUG ("AuthSessionError: %s", error->message);
190         g_simple_async_result_set_from_error (res, error);
191         g_simple_async_result_complete (res);
192         g_object_unref (res);
193         return;
194     }
195
196     if (priv->canceled)
197     {
198         priv->busy = FALSE;
199         priv->canceled = FALSE;
200         g_simple_async_result_set_error (res,
201                                          signon_error_quark (),
202                                          SIGNON_ERROR_SESSION_CANCELED,
203                                          "Authentication session was canceled");
204         g_simple_async_result_complete (res);
205         g_object_unref (res);
206         return;
207     }
208
209     DEBUG ("%s %d", G_STRFUNC, __LINE__);
210
211     process_data = g_object_get_data ((GObject *)res, data_key_process);
212     g_return_if_fail (process_data != NULL);
213
214     sso_auth_session_call_process (priv->proxy,
215                                    process_data->session_data,
216                                    process_data->mechanism,
217                                    process_data->cancellable,
218                                    auth_session_process_reply,
219                                    res);
220 }
221
222 static void
223 process_async_cb_wrapper (GObject *object, GAsyncResult *res,
224                           gpointer user_data)
225 {
226     AuthSessionProcessCbData *cb_data = user_data;
227     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
228     GVariant *v_reply;
229     GHashTable *reply = NULL;
230     GError *error = NULL;
231     gboolean cancelled;
232
233     DEBUG ("%s %d", G_STRFUNC, __LINE__);
234
235     v_reply = signon_auth_session_process_finish (self, res, &error);
236
237     cancelled = error != NULL &&
238         error->domain == G_IO_ERROR &&
239         error->code == G_IO_ERROR_CANCELLED;
240
241     /* Do not invoke the callback if the operation was cancelled */
242     if (cb_data->cb != NULL && !cancelled)
243     {
244         if (v_reply != NULL)
245             reply = signon_hash_table_from_variant (v_reply);
246
247         cb_data->cb (self, reply, error, cb_data->user_data);
248     }
249     g_variant_unref (v_reply);
250
251     g_slice_free (AuthSessionProcessCbData, cb_data);
252     g_clear_error (&error);
253 }
254
255 static GQuark
256 auth_session_object_quark ()
257 {
258   static GQuark quark = 0;
259
260   if (!quark)
261     quark = g_quark_from_static_string ("auth_session_object_quark");
262
263   return quark;
264 }
265
266 static void
267 signon_auth_session_set_property (GObject *object,
268                                   guint property_id,
269                                   const GValue *value,
270                                   GParamSpec *pspec)
271 {
272     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
273
274     switch (property_id)
275     {
276         case PROP_IDENTITY:
277             self->priv->identity = g_value_dup_object (value);
278             break;
279         default:
280             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
281     }
282 }
283
284 static void
285 signon_auth_session_get_property (GObject *object,
286                                   guint property_id,
287                                   GValue *value,
288                                   GParamSpec *pspec)
289 {
290     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
291
292     switch (property_id)
293     {
294         case PROP_IDENTITY:
295             g_value_set_object (value, self->priv->identity);
296             break;
297         default:
298             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
299     }
300 }
301
302 static void
303 signon_auth_session_init (SignonAuthSession *self)
304 {
305     self->priv = SIGNON_AUTH_SESSION_GET_PRIV (self);
306     self->priv->cancellable = g_cancellable_new ();
307 }
308
309 static void
310 signon_auth_session_dispose (GObject *object)
311 {
312     g_return_if_fail (SIGNON_IS_AUTH_SESSION (object));
313     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
314     SignonAuthSessionPrivate *priv = self->priv;
315     g_return_if_fail (priv != NULL);
316
317     if (priv->dispose_has_run)
318         return;
319
320     if (priv->cancellable)
321     {
322         g_cancellable_cancel (priv->cancellable);
323         g_object_unref (priv->cancellable);
324         priv->cancellable = NULL;
325     }
326
327     if (priv->proxy)
328     {
329         g_signal_handler_disconnect (priv->proxy, priv->signal_state_changed);
330         g_signal_handler_disconnect (priv->proxy, priv->signal_unregistered);
331         g_object_unref (priv->proxy);
332
333         priv->proxy = NULL;
334     }
335
336     G_OBJECT_CLASS (signon_auth_session_parent_class)->dispose (object);
337
338     priv->dispose_has_run = TRUE;
339 }
340
341 static void
342 signon_auth_session_finalize (GObject *object)
343 {
344     g_return_if_fail (SIGNON_IS_AUTH_SESSION(object));
345
346     SignonAuthSession *self = SIGNON_AUTH_SESSION(object);
347     SignonAuthSessionPrivate *priv = self->priv;
348     g_return_if_fail (priv != NULL);
349
350     g_free (priv->method_name);
351     g_object_unref (priv->identity);
352
353     G_OBJECT_CLASS (signon_auth_session_parent_class)->finalize (object);
354 }
355
356 static void
357 signon_auth_session_class_init (SignonAuthSessionClass *klass)
358 {
359     GObjectClass *object_class = G_OBJECT_CLASS (klass);
360     GParamSpec *pspec;
361
362     object_class->set_property = signon_auth_session_set_property;
363     object_class->get_property = signon_auth_session_get_property;
364
365     pspec = g_param_spec_object ("identity",
366                                  "Identity Object",
367                                  "Identity Object construct parameter",
368                                  SIGNON_TYPE_IDENTITY,
369                                  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
370     g_object_class_install_property (object_class,
371                                      PROP_IDENTITY,
372                                      pspec);
373
374     g_type_class_add_private (object_class, sizeof (SignonAuthSessionPrivate));
375
376     /**
377      * SignonAuthSession::state-changed:
378      * @auth_session: the #SignonAuthSession
379      * @state: the current state of the #SignonAuthSession
380      * @message: the message associated with the state change
381      *
382      * Emitted when the state of the #SignonAuthSession changes. The state change
383      * is initiated by #GSignondPlugin via #GSignondPlugin::status-changed signal.
384      */
385     /* FIXME: @state should be registered as a GLib type (or use one from
386      * libgsignond-common)
387      */
388     auth_session_signals[STATE_CHANGED] =
389             g_signal_new ("state-changed",
390                           G_TYPE_FROM_CLASS (klass),
391                           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
392                           0,
393                           NULL,
394                           NULL,
395                           _signon_marshal_VOID__INT_STRING,
396                           G_TYPE_NONE, 2,
397                           G_TYPE_INT,
398                           G_TYPE_STRING);
399
400     object_class->dispose = signon_auth_session_dispose;
401     object_class->finalize = signon_auth_session_finalize;
402 }
403
404 /**
405  * signon_auth_session_new:
406  * @id: the id of the #SignonIdentity to be used. Can be 0, if this session is
407  * not bound to any stored identity.
408  * @method_name: the name of the authentication method to be used.
409  * @err: a pointer to a location which will contain the error, in case this
410  * function fails.
411  *
412  * Creates a new #SignonAuthSession, which can be used to authenticate using
413  * the specified method.
414  *
415  * Returns: a new #SignonAuthSession.
416  */
417 SignonAuthSession *
418 signon_auth_session_new (gint id,
419                          const gchar *method_name,
420                          GError **err)
421 {
422     DEBUG ("%s %d", G_STRFUNC, __LINE__);
423
424     SignonIdentity *identity = (id == 0) ?
425         signon_identity_new () : signon_identity_new_from_db (id);
426     g_return_val_if_fail (identity, NULL);
427
428     SignonAuthSession *self =
429         signon_auth_session_new_for_identity (identity, method_name, err);
430     g_object_unref (identity);
431
432     return self;
433 }
434
435 /**
436  * signon_auth_session_new_for_identity:
437  * @identity: #SignonIdentity parent object.
438  * @method_name: the name of the authentication method to be used.
439  * @err: a pointer to a location which will contain the error, in case this
440  * function fails.
441  *
442  * Creates a new #SignonAuthSession, which can be used to authenticate using
443  * the specified method.
444  *
445  * Returns: a new #SignonAuthSession.
446  */
447 SignonAuthSession *
448 signon_auth_session_new_for_identity (SignonIdentity *identity,
449                                       const gchar *method_name,
450                                       GError **err)
451 {
452     g_return_val_if_fail (SIGNON_IS_IDENTITY (identity), NULL);
453
454     DEBUG ("%s %d", G_STRFUNC, __LINE__);
455
456     SignonAuthSession *self = SIGNON_AUTH_SESSION(g_object_new (
457                                      SIGNON_TYPE_AUTH_SESSION,
458                                      "identity", identity,
459                                      NULL));
460     g_return_val_if_fail (self != NULL, NULL);
461
462     if (!auth_session_priv_init(self, method_name, err))
463     {
464         if (*err)
465             g_warning ("%s returned error: %s", G_STRFUNC, (*err)->message);
466
467         g_object_unref (self);
468         return NULL;
469     }
470
471     return self;
472 }
473
474 /**
475  * signon_auth_session_get_method:
476  * @self: the #SignonAuthSession.
477  *
478  * Get the current authentication method.
479  *
480  * Returns: the authentication method being used, or %NULL on failure.
481  */
482 const gchar *
483 signon_auth_session_get_method (SignonAuthSession *self)
484 {
485     g_return_val_if_fail (SIGNON_IS_AUTH_SESSION (self), NULL);
486     SignonAuthSessionPrivate *priv = self->priv;
487
488     g_return_val_if_fail (priv != NULL, NULL);
489
490     return priv->method_name;
491 }
492
493 /**
494  * SignonAuthSessionQueryAvailableMechanismsCb:
495  * @self: the #SignonAuthSession.
496  * @mechanisms: (transfer full) (type GStrv): list of available mechanisms.
497  * @error: a #GError if an error occurred, %NULL otherwise.
498  * @user_data: the user data that was passed when installing this callback.
499  *
500  * Callback to be passed to signon_auth_session_query_available_mechanisms().
501  */
502
503 /**
504  * signon_auth_session_query_available_mechanisms:
505  * @self: the #SignonAuthSession.
506  * @wanted_mechanisms: a %NULL-terminated list of mechanisms supported by the client.
507  * @cb: (scope async): a callback which will be called with the result.
508  * @user_data: user data to be passed to the callback.
509  *
510  * Queries the mechanisms available for this authentication session. The result
511  * will be the intersection between @wanted_mechanisms and the mechanisms
512  * supported by the authentication plugin (and allowed by the #SignonIdentity that this
513  * session belongs to).
514  */
515 void
516 signon_auth_session_query_available_mechanisms (SignonAuthSession *self,
517                                                 const gchar **wanted_mechanisms,
518                                                 SignonAuthSessionQueryAvailableMechanismsCb cb,
519                                                 gpointer user_data)
520 {
521     g_return_if_fail (SIGNON_IS_AUTH_SESSION (self));
522     SignonAuthSessionPrivate* priv = self->priv;
523
524     g_return_if_fail (priv != NULL);
525
526     AuthSessionQueryAvailableMechanismsCbData *cb_data = g_slice_new0 (AuthSessionQueryAvailableMechanismsCbData);
527     cb_data->self = self;
528     cb_data->cb = cb;
529     cb_data->user_data = user_data;
530
531     AuthSessionQueryAvailableMechanismsData *operation_data = g_slice_new0 (AuthSessionQueryAvailableMechanismsData);
532     operation_data->wanted_mechanisms = g_strdupv ((gchar **)wanted_mechanisms);
533     operation_data->cb_data = cb_data;
534
535     auth_session_check_remote_object(self);
536     _signon_object_call_when_ready (self,
537                                     auth_session_object_quark(),
538                                     auth_session_query_available_mechanisms_ready_cb,
539                                     operation_data);
540 }
541
542 /**
543  * SignonAuthSessionProcessCb:
544  * @self: the #SignonAuthSession.
545  * @session_data: (transfer full) (element-type utf8 GValue): a dictionary with
546  * the response.
547  * @error: a #GError if an error occurred, %NULL otherwise.
548  * @user_data: the user data that was passed when installing this callback.
549  *
550  * This callback is invoked when the authentication plugin delivers the result
551  * of the signon_auth_session_process() operation.
552  */
553
554 /**
555  * signon_auth_session_process:
556  * @self: the #SignonAuthSession.
557  * @session_data: (transfer none) (element-type utf8 GValue): a dictionary of parameters.
558  * @mechanism: the authentication mechanism to be used.
559  * @cb: (scope async): a callback which will be called with the result.
560  * @user_data: user data to be passed to the callback.
561  *
562  * Performs one step of the authentication process. If the #SignonIdentity that
563  * this session belongs to contains a username and a password, they will be also 
564  * passed to the authentication plugin, otherwise they should be set directly in
565  * @session_data.
566  * @session_data should be used to add additional authentication parameters to the
567  * session, or to override the parameters otherwise taken from the identity.
568  *
569  * Deprecated: 1.8: Use signon_auth_session_process_async() instead.
570  */
571 void
572 signon_auth_session_process (SignonAuthSession *self,
573                              GHashTable *session_data,
574                              const gchar* mechanism,
575                              SignonAuthSessionProcessCb cb,
576                              gpointer user_data)
577 {
578     GVariant *v_session_data;
579
580     g_return_if_fail (SIGNON_IS_AUTH_SESSION (self));
581     DEBUG ("%s %d", G_STRFUNC, __LINE__);
582
583     AuthSessionProcessCbData *cb_data = g_slice_new0 (AuthSessionProcessCbData);
584     cb_data->cb = cb;
585     cb_data->user_data = user_data;
586
587     v_session_data = signon_hash_table_to_variant (session_data);
588
589     signon_auth_session_process_async (self, v_session_data, mechanism, NULL,
590                                        process_async_cb_wrapper, cb_data);
591 }
592
593 /**
594  * signon_auth_session_process_async:
595  * @self: the #SignonAuthSession.
596  * @session_data: (transfer full): a dictionary of parameters.
597  * @mechanism: the authentication mechanism to be used.
598  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore.
599  * @callback: (scope async): a callback which will be called when the
600  * authentication reply is available.
601  * @user_data: user data to be passed to the callback.
602  *
603  * Performs one step of the authentication process.
604  * @session_data should be used to add additional authentication parameters to the
605  * session.
606  * 
607  * What specific parameters should be used can be found from authentication plugins'
608  * documentation (look for parameters that are expected in gsignond_plugin_request_initial()
609  * for the first step, and parameters that are expected in gsignond_plugin_request() for
610  * the subsequent steps). See, for example, #GSignondPasswordPlugin and #GSignondDigestPlugin.
611  * 
612  * If the #SignonIdentity that this session belongs to contains a username and a password, 
613  * the daemon will pass them to the authentication plugin, otherwise they should be set directly in
614  * @session_data. The daemon also passes a list of identity's allowed realms to the plugin,
615  * and they cannot be overriden.
616  *
617  * Since: 1.8
618  */
619 void
620 signon_auth_session_process_async (SignonAuthSession *self,
621                                    GVariant *session_data,
622                                    const gchar *mechanism,
623                                    GCancellable *cancellable,
624                                    GAsyncReadyCallback callback,
625                                    gpointer user_data)
626 {
627     SignonAuthSessionPrivate *priv;
628     AuthSessionProcessData *process_data;
629     GSimpleAsyncResult *res;
630
631     g_return_if_fail (SIGNON_IS_AUTH_SESSION (self));
632     priv = self->priv;
633
634     g_return_if_fail (session_data != NULL);
635
636     res = g_simple_async_result_new ((GObject *)self, callback, user_data,
637                                      signon_auth_session_process_async);
638     g_simple_async_result_set_check_cancellable (res, cancellable);
639
640     process_data = g_slice_new0 (AuthSessionProcessData);
641     process_data->session_data = g_variant_ref_sink (session_data);
642     process_data->mechanism = g_strdup (mechanism);
643     process_data->cancellable = cancellable;
644     g_object_set_data_full ((GObject *)res, data_key_process, process_data,
645                             (GDestroyNotify)auth_session_process_data_free);
646
647     priv->busy = TRUE;
648
649     auth_session_check_remote_object(self);
650     _signon_object_call_when_ready (self,
651                                     auth_session_object_quark(),
652                                     auth_session_process_ready_cb,
653                                     res);
654 }
655
656 /**
657  * signon_auth_session_process_finish:
658  * @self: the #SignonAuthSession.
659  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to
660  * signon_auth_session_process_async().
661  * @error: return location for error, or %NULL.
662  *
663  * Collect the result of the signon_auth_session_process_async() operation.
664  *
665  * Returns: a #GVariant of type %G_VARIANT_TYPE_VARDICT containing the
666  * authentication reply. As with signon_auth_session_process_async(), specific
667  * parameters contained in the #GVariant can be found from plugins' documentation:
668  * #GSignondPlugin::response-final for the final response, and #GSignondPlugin::response
669  * for the intermediate responses. See, for example, #GSignondPasswordPlugin 
670  * and #GSignondDigestPlugin.
671  *
672  * Since: 1.8
673  */
674 GVariant *
675 signon_auth_session_process_finish (SignonAuthSession *self, GAsyncResult *res,
676                                     GError **error)
677 {
678     GSimpleAsyncResult *async_result;
679     GVariant *reply;
680
681     g_return_val_if_fail (SIGNON_IS_AUTH_SESSION (self), NULL);
682
683     async_result = (GSimpleAsyncResult *)res;
684     if (g_simple_async_result_propagate_error (async_result, error))
685         return NULL;
686
687     reply = g_simple_async_result_get_op_res_gpointer (async_result);
688     return g_variant_ref (reply);
689 }
690
691 /**
692  * signon_auth_session_cancel:
693  * @self: the #SignonAuthSession.
694  *
695  * Cancel the authentication session.
696  */
697 void
698 signon_auth_session_cancel (SignonAuthSession *self)
699 {
700     g_return_if_fail (SIGNON_IS_AUTH_SESSION (self));
701     SignonAuthSessionPrivate *priv = self->priv;
702
703     g_return_if_fail (priv != NULL);
704
705     auth_session_check_remote_object(self);
706
707     if (!priv->busy)
708         return;
709
710     priv->canceled = TRUE;
711     _signon_object_call_when_ready (self,
712                                     auth_session_object_quark(),
713                                     auth_session_cancel_ready_cb,
714                                     NULL);
715 }
716
717 static void
718 auth_session_state_changed_cb (GDBusProxy *proxy,
719                                gint state,
720                                gchar *message,
721                                gpointer user_data)
722 {
723     g_return_if_fail (SIGNON_IS_AUTH_SESSION (user_data));
724     SignonAuthSession *self = SIGNON_AUTH_SESSION (user_data);
725
726     g_signal_emit ((GObject *)self,
727                     auth_session_signals[STATE_CHANGED],
728                     0,
729                     state,
730                     message);
731 }
732
733 static void auth_session_remote_object_destroyed_cb (GDBusProxy *proxy,
734                                                      gpointer user_data)
735 {
736     g_return_if_fail (SIGNON_IS_AUTH_SESSION (user_data));
737     SignonAuthSession *self = SIGNON_AUTH_SESSION (user_data);
738     SignonAuthSessionPrivate *priv = self->priv;
739     g_return_if_fail (priv != NULL);
740     DEBUG ("remote object unregistered");
741
742     if (priv->proxy)
743     {
744         g_object_unref (priv->proxy);
745         priv->proxy = NULL;
746     }
747
748     /*
749      * as remote object is destroyed only
750      * when the session core is destroyed,
751      * so there should not be any processes
752      * running
753      * */
754     priv->busy = FALSE;
755     priv->canceled = FALSE;
756     _signon_object_not_ready(self);
757 }
758
759 static gboolean
760 auth_session_priv_init (SignonAuthSession *self,
761                         const gchar *method_name, GError **err)
762 {
763     g_return_val_if_fail (SIGNON_IS_AUTH_SESSION (self), FALSE);
764     SignonAuthSessionPrivate *priv = SIGNON_AUTH_SESSION_PRIV (self);
765     g_return_val_if_fail (priv, FALSE);
766
767     priv->method_name = g_strdup (method_name);
768
769     priv->registering = FALSE;
770     priv->busy = FALSE;
771     priv->canceled = FALSE;
772     return TRUE;
773 }
774
775 static void
776 auth_session_query_mechanisms_reply (GObject *object, GAsyncResult *res,
777                                      gpointer userdata)
778 {
779     SsoAuthSession *proxy = SSO_AUTH_SESSION (object);
780     gchar **mechanisms = NULL;
781     GError *error = NULL;
782     AuthSessionQueryAvailableMechanismsCbData *cb_data =
783         (AuthSessionQueryAvailableMechanismsCbData *)userdata;
784     g_return_if_fail (cb_data != NULL);
785
786     sso_auth_session_call_query_available_mechanisms_finish (proxy,
787                                                              &mechanisms,
788                                                              res,
789                                                              &error);
790     if (SIGNON_IS_NOT_CANCELLED (error))
791     {
792         (cb_data->cb) (cb_data->self, mechanisms, error, cb_data->user_data);
793     }
794
795     g_clear_error (&error);
796     g_slice_free (AuthSessionQueryAvailableMechanismsCbData, cb_data);
797 }
798
799 static void
800 auth_session_query_available_mechanisms_ready_cb (gpointer object, const GError *error,
801                                                   gpointer user_data)
802 {
803     g_return_if_fail (SIGNON_IS_AUTH_SESSION (object));
804     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
805     SignonAuthSessionPrivate *priv = self->priv;
806     g_return_if_fail (priv != NULL);
807
808     AuthSessionQueryAvailableMechanismsData *operation_data =
809         (AuthSessionQueryAvailableMechanismsData *)user_data;
810     g_return_if_fail (operation_data != NULL);
811
812     AuthSessionQueryAvailableMechanismsCbData *cb_data = operation_data->cb_data;
813     g_return_if_fail (cb_data != NULL);
814
815     if (error)
816     {
817         (cb_data->cb)
818             (self, NULL, error, cb_data->user_data);
819
820         g_slice_free (AuthSessionQueryAvailableMechanismsCbData, cb_data);
821     }
822     else
823     {
824         g_return_if_fail (priv->proxy != NULL);
825         sso_auth_session_call_query_available_mechanisms (
826             priv->proxy,
827             (const char **)operation_data->wanted_mechanisms,
828             priv->cancellable,
829             auth_session_query_mechanisms_reply,
830             cb_data);
831
832         g_signal_emit (self,
833                        auth_session_signals[STATE_CHANGED],
834                        0,
835                        SIGNON_AUTH_SESSION_STATE_PROCESS_PENDING,
836                        auth_session_process_pending_message);
837     }
838
839     g_strfreev (operation_data->wanted_mechanisms);
840     g_slice_free (AuthSessionQueryAvailableMechanismsData, operation_data);
841 }
842
843 static void
844 auth_session_cancel_ready_cb (gpointer object, const GError *error, gpointer user_data)
845 {
846     g_return_if_fail (SIGNON_IS_AUTH_SESSION (object));
847     g_return_if_fail (user_data == NULL);
848
849     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
850     SignonAuthSessionPrivate *priv = self->priv;
851     g_return_if_fail (priv != NULL);
852
853     if (error)
854     {
855         //TODO: in general this function does not return any values,
856         // that is why I think it should not emit anything for this particular case
857         DEBUG("error during initialization");
858     }
859     else if (priv->proxy && priv->busy)
860         sso_auth_session_call_cancel_sync (priv->proxy,
861                                            priv->cancellable,
862                                            NULL);
863
864     priv->busy = FALSE;
865     priv->canceled = FALSE;
866 }
867
868 static void
869 signon_auth_session_complete (SignonAuthSession *self,
870                               GError *error,
871                               GDBusConnection *connection,
872                               const gchar *bus_name,
873                               const gchar *object_path)
874 {
875     SignonAuthSessionPrivate *priv = self->priv;
876     g_return_if_fail (priv != NULL);
877
878     DEBUG ("%s %d", G_STRFUNC, __LINE__);
879
880     priv->registering = FALSE;
881     if (!g_strcmp0(object_path, "") || error)
882     {
883         if (error)
884             DEBUG ("Error message is %s", error->message);
885         else
886             error = g_error_new (signon_error_quark(),
887                                  SIGNON_ERROR_RUNTIME,
888                                  "Cannot create remote AuthSession object");
889     }
890     else
891     {
892         GError *proxy_error = NULL;
893
894         priv->proxy =
895             sso_auth_session_proxy_new_sync (connection,
896                                              G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
897                                              bus_name,
898                                              object_path,
899                                              priv->cancellable,
900                                              &proxy_error);
901         if (G_UNLIKELY (proxy_error != NULL))
902         {
903             g_warning ("Failed to initialize AuthSession proxy: %s",
904                        proxy_error->message);
905             g_clear_error (&proxy_error);
906         }
907
908         g_dbus_proxy_set_default_timeout ((GDBusProxy *)priv->proxy,
909                                           G_MAXINT);
910
911         priv->signal_state_changed =
912             g_signal_connect (priv->proxy,
913                               "state-changed",
914                               G_CALLBACK (auth_session_state_changed_cb),
915                               self);
916
917         priv->signal_unregistered =
918            g_signal_connect (priv->proxy,
919                              "unregistered",
920                              G_CALLBACK (auth_session_remote_object_destroyed_cb),
921                              self);
922     }
923
924     DEBUG ("Object path received: %s", object_path);
925     _signon_object_ready (self, auth_session_object_quark (), error);
926 }
927
928 static void
929 auth_session_check_remote_object(SignonAuthSession *self)
930 {
931     g_return_if_fail (self != NULL);
932     SignonAuthSessionPrivate *priv = self->priv;
933     g_return_if_fail (priv != NULL);
934
935     if (priv->proxy != NULL)
936         return;
937
938     g_return_if_fail (priv->identity != NULL);
939
940     if (!priv->registering)
941     {
942         DEBUG ("%s %d", G_STRFUNC, __LINE__);
943
944         priv->registering = TRUE;
945         signon_identity_get_auth_session (priv->identity,
946                                           self,
947                                           priv->method_name,
948                                           signon_auth_session_complete);
949
950     }
951 }
952