Tweaks to SignonAuthSession docs
[platform/upstream/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-2013 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::state-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  * @parent: #SignonIdentity parent object.
407  * @method_name: the name of the authentication method to be used.
408  * @err: a pointer to a location which will contain the error, in case this
409  * function fails.
410  *
411  * Creates a new #SignonAuthSession, which can be used to authenticate using
412  * the specified method.
413  *
414  * Returns: a new #SignonAuthSession.
415  */
416 SignonAuthSession *
417 signon_auth_session_new (GObject *parent,
418                          const gchar *method_name,
419                          GError **err)
420 {
421     if (!SIGNON_IS_IDENTITY(parent))
422     {
423         g_set_error (err,
424                      signon_error_quark(),
425                      SIGNON_ERROR_UNKNOWN,
426                      "Parent object is wrong type");
427         return NULL;
428     }
429     SignonIdentity *identity = SIGNON_IDENTITY(parent);
430
431     DEBUG ("%s %d", G_STRFUNC, __LINE__);
432
433     SignonAuthSession *self = SIGNON_AUTH_SESSION(g_object_new (
434                                      SIGNON_TYPE_AUTH_SESSION,
435                                      "identity", identity,
436                                      NULL));
437     g_return_val_if_fail (self != NULL, NULL);
438
439     if (!auth_session_priv_init(self, method_name, err))
440     {
441         if (*err)
442             g_warning ("%s returned error: %s", G_STRFUNC, (*err)->message);
443
444         g_object_unref (self);
445         return NULL;
446     }
447
448     return self;
449 }
450
451 /**
452  * signon_auth_session_get_method:
453  * @self: the #SignonAuthSession.
454  *
455  * Get the current authentication method.
456  *
457  * Returns: the authentication method being used, or %NULL on failure.
458  */
459 const gchar *
460 signon_auth_session_get_method (SignonAuthSession *self)
461 {
462     g_return_val_if_fail (SIGNON_IS_AUTH_SESSION (self), NULL);
463     SignonAuthSessionPrivate *priv = self->priv;
464
465     g_return_val_if_fail (priv != NULL, NULL);
466
467     return priv->method_name;
468 }
469
470 /**
471  * SignonAuthSessionQueryAvailableMechanismsCb:
472  * @self: the #SignonAuthSession.
473  * @mechanisms: (transfer full) (type GStrv): list of available mechanisms.
474  * @error: a #GError if an error occurred, %NULL otherwise.
475  * @user_data: the user data that was passed when installing this callback.
476  *
477  * Callback to be passed to signon_auth_session_query_available_mechanisms().
478  */
479
480 /**
481  * signon_auth_session_query_available_mechanisms:
482  * @self: the #SignonAuthSession.
483  * @wanted_mechanisms: a %NULL-terminated list of mechanisms supported by the client.
484  * @cb: (scope async): a callback which will be called with the result.
485  * @user_data: user data to be passed to the callback.
486  *
487  * Queries the mechanisms available for this authentication session. The result
488  * will be the intersection between @wanted_mechanisms and the mechanisms
489  * supported by the authentication plugin (and allowed by the #SignonIdentity that this
490  * session belongs to).
491  */
492 void
493 signon_auth_session_query_available_mechanisms (SignonAuthSession *self,
494                                                 const gchar **wanted_mechanisms,
495                                                 SignonAuthSessionQueryAvailableMechanismsCb cb,
496                                                 gpointer user_data)
497 {
498     g_return_if_fail (SIGNON_IS_AUTH_SESSION (self));
499     SignonAuthSessionPrivate* priv = self->priv;
500
501     g_return_if_fail (priv != NULL);
502
503     AuthSessionQueryAvailableMechanismsCbData *cb_data = g_slice_new0 (AuthSessionQueryAvailableMechanismsCbData);
504     cb_data->self = self;
505     cb_data->cb = cb;
506     cb_data->user_data = user_data;
507
508     AuthSessionQueryAvailableMechanismsData *operation_data = g_slice_new0 (AuthSessionQueryAvailableMechanismsData);
509     operation_data->wanted_mechanisms = g_strdupv ((gchar **)wanted_mechanisms);
510     operation_data->cb_data = cb_data;
511
512     auth_session_check_remote_object(self);
513     _signon_object_call_when_ready (self,
514                                     auth_session_object_quark(),
515                                     auth_session_query_available_mechanisms_ready_cb,
516                                     operation_data);
517 }
518
519 /**
520  * SignonAuthSessionProcessCb:
521  * @self: the #SignonAuthSession.
522  * @session_data: (transfer full) (element-type utf8 GValue): a dictionary with
523  * the response.
524  * @error: a #GError if an error occurred, %NULL otherwise.
525  * @user_data: the user data that was passed when installing this callback.
526  *
527  * This callback is invoked when the authentication plugin delivers the result
528  * of the signon_auth_session_process() operation.
529  */
530
531 /**
532  * signon_auth_session_process:
533  * @self: the #SignonAuthSession.
534  * @session_data: (transfer none) (element-type utf8 GValue): a dictionary of parameters.
535  * @mechanism: the authentication mechanism to be used.
536  * @cb: (scope async): a callback which will be called with the result.
537  * @user_data: user data to be passed to the callback.
538  *
539  * Performs one step of the authentication process. If the #SignonIdentity that
540  * this session belongs to contains a username and a password, they will be also 
541  * passed to the authentication plugin, otherwise they should be set directly in
542  * @session_data.
543  * @session_data should be used to add additional authentication parameters to the
544  * session, or to override the parameters otherwise taken from the identity.
545  *
546  * Deprecated: 1.8: Use signon_auth_session_process_async() instead.
547  */
548 void
549 signon_auth_session_process (SignonAuthSession *self,
550                              const GHashTable *session_data,
551                              const gchar* mechanism,
552                              SignonAuthSessionProcessCb cb,
553                              gpointer user_data)
554 {
555     GVariant *v_session_data;
556
557     g_return_if_fail (SIGNON_IS_AUTH_SESSION (self));
558     DEBUG ("%s %d", G_STRFUNC, __LINE__);
559
560     AuthSessionProcessCbData *cb_data = g_slice_new0 (AuthSessionProcessCbData);
561     cb_data->cb = cb;
562     cb_data->user_data = user_data;
563
564     v_session_data = signon_hash_table_to_variant (session_data);
565
566     signon_auth_session_process_async (self, v_session_data, mechanism, NULL,
567                                        process_async_cb_wrapper, cb_data);
568 }
569
570 /**
571  * signon_auth_session_process_async:
572  * @self: the #SignonAuthSession.
573  * @session_data: (transfer full): a dictionary of parameters.
574  * @mechanism: the authentication mechanism to be used.
575  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore.
576  * @callback: (scope async): a callback which will be called when the
577  * authentication reply is available.
578  * @user_data: user data to be passed to the callback.
579  *
580  * Performs one step of the authentication process.
581  * @session_data should be used to add additional authentication parameters to the
582  * session.
583  * 
584  * What specific parameters should be used can be found from authentication plugins'
585  * documentation (look for parameters that are expected in gsignond_plugin_request_initial()
586  * for the first step, and parameters that are expected in gsignond_plugin_request() for
587  * the subsequent steps). See, for example, #GSignondPasswordPlugin and #GSignondDigestPlugin.
588  * 
589  * If the #SignonIdentity that this session belongs to contains a username and a password, 
590  * the daemon will pass them to the authentication plugin, otherwise they should be set directly in
591  * @session_data. The daemon also passes a list of identity's allowed realms to the plugin,
592  * and they cannot be overriden.
593  *
594  * Since: 1.8
595  */
596 void
597 signon_auth_session_process_async (SignonAuthSession *self,
598                                    GVariant *session_data,
599                                    const gchar *mechanism,
600                                    GCancellable *cancellable,
601                                    GAsyncReadyCallback callback,
602                                    gpointer user_data)
603 {
604     SignonAuthSessionPrivate *priv;
605     AuthSessionProcessData *process_data;
606     GSimpleAsyncResult *res;
607
608     g_return_if_fail (SIGNON_IS_AUTH_SESSION (self));
609     priv = self->priv;
610
611     g_return_if_fail (session_data != NULL);
612
613     res = g_simple_async_result_new ((GObject *)self, callback, user_data,
614                                      signon_auth_session_process_async);
615     g_simple_async_result_set_check_cancellable (res, cancellable);
616
617     process_data = g_slice_new0 (AuthSessionProcessData);
618     process_data->session_data = g_variant_ref_sink (session_data);
619     process_data->mechanism = g_strdup (mechanism);
620     process_data->cancellable = cancellable;
621     g_object_set_data_full ((GObject *)res, data_key_process, process_data,
622                             (GDestroyNotify)auth_session_process_data_free);
623
624     priv->busy = TRUE;
625
626     auth_session_check_remote_object(self);
627     _signon_object_call_when_ready (self,
628                                     auth_session_object_quark(),
629                                     auth_session_process_ready_cb,
630                                     res);
631 }
632
633 /**
634  * signon_auth_session_process_finish:
635  * @self: the #SignonAuthSession.
636  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to
637  * signon_auth_session_process_async().
638  * @error: return location for error, or %NULL.
639  *
640  * Collect the result of the signon_auth_session_process_async() operation.
641  *
642  * Returns: a #GVariant of type %G_VARIANT_TYPE_VARDICT containing the
643  * authentication reply. As with signon_auth_session_process_async(), specific
644  * parameters contained in the #GVariant can be found from plugins' documentation:
645  * #GSignondPlugin::response-final for the final response, and #GSignondPlugin::response
646  * for the intermediate responses. See, for example, #GSignondPasswordPlugin 
647  * and #GSignondDigestPlugin.
648  *
649  * Since: 1.8
650  */
651 GVariant *
652 signon_auth_session_process_finish (SignonAuthSession *self, GAsyncResult *res,
653                                     GError **error)
654 {
655     GSimpleAsyncResult *async_result;
656     GVariant *reply;
657
658     g_return_val_if_fail (SIGNON_IS_AUTH_SESSION (self), NULL);
659
660     async_result = (GSimpleAsyncResult *)res;
661     if (g_simple_async_result_propagate_error (async_result, error))
662         return NULL;
663
664     reply = g_simple_async_result_get_op_res_gpointer (async_result);
665     return g_variant_ref (reply);
666 }
667
668 /**
669  * signon_auth_session_cancel:
670  * @self: the #SignonAuthSession.
671  *
672  * Cancel the authentication session.
673  */
674 void
675 signon_auth_session_cancel (SignonAuthSession *self)
676 {
677     g_return_if_fail (SIGNON_IS_AUTH_SESSION (self));
678     SignonAuthSessionPrivate *priv = self->priv;
679
680     g_return_if_fail (priv != NULL);
681
682     auth_session_check_remote_object(self);
683
684     if (!priv->busy)
685         return;
686
687     priv->canceled = TRUE;
688     _signon_object_call_when_ready (self,
689                                     auth_session_object_quark(),
690                                     auth_session_cancel_ready_cb,
691                                     NULL);
692 }
693
694 static void
695 auth_session_state_changed_cb (GDBusProxy *proxy,
696                                gint state,
697                                gchar *message,
698                                gpointer user_data)
699 {
700     g_return_if_fail (SIGNON_IS_AUTH_SESSION (user_data));
701     SignonAuthSession *self = SIGNON_AUTH_SESSION (user_data);
702
703     g_signal_emit ((GObject *)self,
704                     auth_session_signals[STATE_CHANGED],
705                     0,
706                     state,
707                     message);
708 }
709
710 static void auth_session_remote_object_destroyed_cb (GDBusProxy *proxy,
711                                                      gpointer user_data)
712 {
713     g_return_if_fail (SIGNON_IS_AUTH_SESSION (user_data));
714     SignonAuthSession *self = SIGNON_AUTH_SESSION (user_data);
715     SignonAuthSessionPrivate *priv = self->priv;
716     g_return_if_fail (priv != NULL);
717     DEBUG ("remote object unregistered");
718
719     if (priv->proxy)
720     {
721         g_object_unref (priv->proxy);
722         priv->proxy = NULL;
723     }
724
725     /*
726      * as remote object is destroyed only
727      * when the session core is destroyed,
728      * so there should not be any processes
729      * running
730      * */
731     priv->busy = FALSE;
732     priv->canceled = FALSE;
733     _signon_object_not_ready(self);
734 }
735
736 static gboolean
737 auth_session_priv_init (SignonAuthSession *self,
738                         const gchar *method_name, GError **err)
739 {
740     g_return_val_if_fail (SIGNON_IS_AUTH_SESSION (self), FALSE);
741     SignonAuthSessionPrivate *priv = SIGNON_AUTH_SESSION_PRIV (self);
742     g_return_val_if_fail (priv, FALSE);
743
744     priv->method_name = g_strdup (method_name);
745
746     priv->registering = FALSE;
747     priv->busy = FALSE;
748     priv->canceled = FALSE;
749     return TRUE;
750 }
751
752 static void
753 auth_session_query_mechanisms_reply (GObject *object, GAsyncResult *res,
754                                      gpointer userdata)
755 {
756     SsoAuthSession *proxy = SSO_AUTH_SESSION (object);
757     gchar **mechanisms = NULL;
758     GError *error = NULL;
759     AuthSessionQueryAvailableMechanismsCbData *cb_data =
760         (AuthSessionQueryAvailableMechanismsCbData *)userdata;
761     g_return_if_fail (cb_data != NULL);
762
763     sso_auth_session_call_query_available_mechanisms_finish (proxy,
764                                                              &mechanisms,
765                                                              res,
766                                                              &error);
767     if (SIGNON_IS_NOT_CANCELLED (error))
768     {
769         (cb_data->cb) (cb_data->self, mechanisms, error, cb_data->user_data);
770     }
771
772     g_clear_error (&error);
773     g_slice_free (AuthSessionQueryAvailableMechanismsCbData, cb_data);
774 }
775
776 static void
777 auth_session_query_available_mechanisms_ready_cb (gpointer object, const GError *error,
778                                                   gpointer user_data)
779 {
780     g_return_if_fail (SIGNON_IS_AUTH_SESSION (object));
781     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
782     SignonAuthSessionPrivate *priv = self->priv;
783     g_return_if_fail (priv != NULL);
784
785     AuthSessionQueryAvailableMechanismsData *operation_data =
786         (AuthSessionQueryAvailableMechanismsData *)user_data;
787     g_return_if_fail (operation_data != NULL);
788
789     AuthSessionQueryAvailableMechanismsCbData *cb_data = operation_data->cb_data;
790     g_return_if_fail (cb_data != NULL);
791
792     if (error)
793     {
794         (cb_data->cb)
795             (self, NULL, error, cb_data->user_data);
796
797         g_slice_free (AuthSessionQueryAvailableMechanismsCbData, cb_data);
798     }
799     else
800     {
801         g_return_if_fail (priv->proxy != NULL);
802         sso_auth_session_call_query_available_mechanisms (
803             priv->proxy,
804             (const char **)operation_data->wanted_mechanisms,
805             priv->cancellable,
806             auth_session_query_mechanisms_reply,
807             cb_data);
808
809         g_signal_emit (self,
810                        auth_session_signals[STATE_CHANGED],
811                        0,
812                        SIGNON_AUTH_SESSION_STATE_PROCESS_PENDING,
813                        auth_session_process_pending_message);
814     }
815
816     g_strfreev (operation_data->wanted_mechanisms);
817     g_slice_free (AuthSessionQueryAvailableMechanismsData, operation_data);
818 }
819
820 static void
821 auth_session_cancel_ready_cb (gpointer object, const GError *error, gpointer user_data)
822 {
823     g_return_if_fail (SIGNON_IS_AUTH_SESSION (object));
824     g_return_if_fail (user_data == NULL);
825
826     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
827     SignonAuthSessionPrivate *priv = self->priv;
828     g_return_if_fail (priv != NULL);
829
830     if (error)
831     {
832         //TODO: in general this function does not return any values,
833         // that is why I think it should not emit anything for this particular case
834         DEBUG("error during initialization");
835     }
836     else if (priv->proxy && priv->busy)
837         sso_auth_session_call_cancel_sync (priv->proxy,
838                                            priv->cancellable,
839                                            NULL);
840
841     priv->busy = FALSE;
842     priv->canceled = FALSE;
843 }
844
845 static void
846 signon_auth_session_complete (SignonAuthSession *self,
847                               GError *error,
848                               GDBusConnection *connection,
849                               const gchar *bus_name,
850                               const gchar *object_path)
851 {
852     SignonAuthSessionPrivate *priv = self->priv;
853     g_return_if_fail (priv != NULL);
854
855     DEBUG ("%s %d", G_STRFUNC, __LINE__);
856
857     priv->registering = FALSE;
858     if (!g_strcmp0(object_path, "") || error)
859     {
860         if (error)
861             DEBUG ("Error message is %s", error->message);
862         else
863             error = g_error_new (signon_error_quark(),
864                                  SIGNON_ERROR_RUNTIME,
865                                  "Cannot create remote AuthSession object");
866     }
867     else
868     {
869         GError *proxy_error = NULL;
870
871         priv->proxy =
872             sso_auth_session_proxy_new_sync (connection,
873                                              G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
874                                              bus_name,
875                                              object_path,
876                                              priv->cancellable,
877                                              &proxy_error);
878         if (G_UNLIKELY (proxy_error != NULL))
879         {
880             g_warning ("Failed to initialize AuthSession proxy: %s",
881                        proxy_error->message);
882             g_clear_error (&proxy_error);
883         }
884
885         g_dbus_proxy_set_default_timeout ((GDBusProxy *)priv->proxy,
886                                           G_MAXINT);
887
888         priv->signal_state_changed =
889             g_signal_connect (priv->proxy,
890                               "state-changed",
891                               G_CALLBACK (auth_session_state_changed_cb),
892                               self);
893
894         priv->signal_unregistered =
895            g_signal_connect (priv->proxy,
896                              "unregistered",
897                              G_CALLBACK (auth_session_remote_object_destroyed_cb),
898                              self);
899     }
900
901     DEBUG ("Object path received: %s", object_path);
902     _signon_object_ready (self, auth_session_object_quark (), error);
903 }
904
905 static void
906 auth_session_check_remote_object(SignonAuthSession *self)
907 {
908     g_return_if_fail (self != NULL);
909     SignonAuthSessionPrivate *priv = self->priv;
910     g_return_if_fail (priv != NULL);
911
912     if (priv->proxy != NULL)
913         return;
914
915     g_return_if_fail (priv->identity != NULL);
916
917     if (!priv->registering)
918     {
919         DEBUG ("%s %d", G_STRFUNC, __LINE__);
920
921         priv->registering = TRUE;
922         signon_identity_get_auth_session (priv->identity,
923                                           self,
924                                           priv->method_name,
925                                           signon_auth_session_complete);
926
927     }
928 }
929