230b513445558bd8bf1f91dbff585df9ffd74449
[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-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: Authentication session handler.
32  *
33  * The #SignonAuthSession object is responsible for handling the client
34  * authentication. #SignonAuthSession objects can be created from existing
35  * identities (via signon_identity_create_session() or by passing a non-zero ID
36  * to signon_auth_session_new()), in which case the authentication data such as
37  * username and password will be implicitly taken from the identity, or they
38  * can be created with no existing identity bound to them, in which case all
39  * the authentication data must be filled in by the client when
40  * signon_auth_session_process() is called.
41  */
42
43 #include "signon-internals.h"
44 #include "signon-auth-session.h"
45 #include "signon-dbus-queue.h"
46 #include "signon-errors.h"
47 #include "signon-marshal.h"
48 #include "signon-utils.h"
49 #include "signon-identity.h"
50 #include "sso-auth-service.h"
51 #include "sso-auth-session-gen.h"
52
53
54 G_DEFINE_TYPE (SignonAuthSession, signon_auth_session, G_TYPE_OBJECT);
55
56 enum
57 {
58     PROP_0,
59     PROP_IDENTITY,
60     PROP_APPCTX
61 };
62
63 /* Signals */
64 enum
65 {
66     STATE_CHANGED,
67     LAST_SIGNAL
68 };
69
70 static guint auth_session_signals[LAST_SIGNAL] = { 0 };
71 static const gchar auth_session_process_pending_message[] =
72     "The request is added to queue.";
73 static const gchar data_key_process[] = "signon-process";
74
75 struct _SignonAuthSessionPrivate
76 {
77     SsoAuthSession *proxy;
78     SignonIdentity *identity;
79     GCancellable *cancellable;
80
81     guint id;
82     gchar *method_name;
83
84     gboolean registering;
85     gboolean busy;
86     gboolean canceled;
87     gboolean dispose_has_run;
88
89     guint signal_state_changed;
90     guint signal_unregistered;
91 };
92
93 typedef struct _AuthSessionQueryAvailableMechanismsData
94 {
95     gchar **wanted_mechanisms;
96     gpointer cb_data;
97 } AuthSessionQueryAvailableMechanismsData;
98
99 typedef struct _AuthSessionProcessData
100 {
101     GVariant *session_data;
102     gchar *mechanism;
103     GCancellable *cancellable;
104 } AuthSessionProcessData;
105
106 typedef struct _AuthSessionQueryAvailableMechanismsCbData
107 {
108     SignonAuthSession *self;
109     SignonAuthSessionQueryAvailableMechanismsCb cb;
110     gpointer user_data;
111 } AuthSessionQueryAvailableMechanismsCbData;
112
113 typedef struct _AuthSessionProcessCbData
114 {
115     SignonAuthSessionProcessCb cb;
116     gpointer user_data;
117 } AuthSessionProcessCbData;
118
119 #define SIGNON_AUTH_SESSION_PRIV(obj) (SIGNON_AUTH_SESSION(obj)->priv)
120 #define SIGNON_AUTH_SESSION_GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), SIGNON_TYPE_AUTH_SESSION, SignonAuthSessionPrivate))
121
122
123 static void auth_session_state_changed_cb (GDBusProxy *proxy, gint state, gchar *message, gpointer user_data);
124 static void auth_session_remote_object_destroyed_cb (GDBusProxy *proxy, gpointer user_data);
125
126 static gboolean auth_session_priv_init (SignonAuthSession *self, const gchar *method_name, GError **err);
127
128 static void auth_session_query_available_mechanisms_ready_cb (gpointer object, const GError *error, gpointer user_data);
129 static void auth_session_cancel_ready_cb (gpointer object, const GError *error, gpointer user_data);
130
131 static void auth_session_check_remote_object(SignonAuthSession *self);
132
133 static void
134 auth_session_process_data_free (AuthSessionProcessData *process_data)
135 {
136     g_free (process_data->mechanism);
137     g_variant_unref (process_data->session_data);
138     g_slice_free (AuthSessionProcessData, process_data);
139 }
140
141 static void
142 auth_session_process_reply (GObject *object, GAsyncResult *res,
143                             gpointer userdata)
144 {
145     SignonAuthSession *self;
146     SsoAuthSession *proxy = SSO_AUTH_SESSION (object);
147     GSimpleAsyncResult *res_process = (GSimpleAsyncResult *)userdata;
148     GVariant *reply;
149     GError *error = NULL;
150
151     g_return_if_fail (res_process != NULL);
152     DEBUG ("%s %d", G_STRFUNC, __LINE__);
153
154     sso_auth_session_call_process_finish (proxy, &reply, res, &error);
155
156     self = SIGNON_AUTH_SESSION (g_async_result_get_source_object (
157         (GAsyncResult *)res_process));
158     self->priv->busy = FALSE;
159
160     if (G_LIKELY (error == NULL))
161     {
162         g_simple_async_result_set_op_res_gpointer (res_process, reply,
163                                                    (GDestroyNotify)
164                                                    g_variant_unref);
165     }
166     else
167     {
168         g_simple_async_result_take_error (res_process, error);
169     }
170
171     /* We use the idle variant in order to avoid the following critical
172      * message:
173      * g_main_context_pop_thread_default: assertion `g_queue_peek_head (stack) == context' failed
174      */
175     g_simple_async_result_complete_in_idle (res_process);
176     g_object_unref (res_process);
177     g_object_unref (self);
178 }
179
180 static void
181 auth_session_process_ready_cb (gpointer object, const GError *error, gpointer user_data)
182 {
183     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
184     SignonAuthSessionPrivate *priv;
185     GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
186     AuthSessionProcessData *process_data;
187
188     g_return_if_fail (self != NULL);
189     priv = self->priv;
190
191     if (error != NULL)
192     {
193         DEBUG ("AuthSessionError: %s", error->message);
194         g_simple_async_result_set_from_error (res, error);
195         g_simple_async_result_complete (res);
196         g_object_unref (res);
197         return;
198     }
199
200     if (priv->canceled)
201     {
202         priv->busy = FALSE;
203         priv->canceled = FALSE;
204         g_simple_async_result_set_error (res,
205                                          signon_error_quark (),
206                                          SIGNON_ERROR_SESSION_CANCELED,
207                                          "Authentication session was canceled");
208         g_simple_async_result_complete (res);
209         g_object_unref (res);
210         return;
211     }
212
213     DEBUG ("%s %d", G_STRFUNC, __LINE__);
214
215     process_data = g_object_get_data ((GObject *)res, data_key_process);
216     g_return_if_fail (process_data != NULL);
217
218     sso_auth_session_call_process (priv->proxy,
219                                    process_data->session_data,
220                                    process_data->mechanism,
221                                    process_data->cancellable,
222                                    auth_session_process_reply,
223                                    res);
224 }
225
226 static void
227 process_async_cb_wrapper (GObject *object, GAsyncResult *res,
228                           gpointer user_data)
229 {
230     AuthSessionProcessCbData *cb_data = user_data;
231     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
232     GVariant *v_reply;
233     GHashTable *reply = NULL;
234     GError *error = NULL;
235     gboolean cancelled;
236
237     DEBUG ("%s %d", G_STRFUNC, __LINE__);
238
239     v_reply = signon_auth_session_process_finish (self, res, &error);
240
241     cancelled = error != NULL &&
242         error->domain == G_IO_ERROR &&
243         error->code == G_IO_ERROR_CANCELLED;
244
245     /* Do not invoke the callback if the operation was cancelled */
246     if (cb_data->cb != NULL && !cancelled)
247     {
248         if (v_reply != NULL)
249             reply = signon_hash_table_from_variant (v_reply);
250
251         cb_data->cb (self, reply, error, cb_data->user_data);
252     }
253     g_variant_unref (v_reply);
254
255     g_slice_free (AuthSessionProcessCbData, cb_data);
256     g_clear_error (&error);
257 }
258
259 static GQuark
260 auth_session_object_quark ()
261 {
262   static GQuark quark = 0;
263
264   if (!quark)
265     quark = g_quark_from_static_string ("auth_session_object_quark");
266
267   return quark;
268 }
269
270 static void
271 signon_auth_session_set_property (GObject *object,
272                                   guint property_id,
273                                   const GValue *value,
274                                   GParamSpec *pspec)
275 {
276     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
277
278     switch (property_id)
279     {
280         case PROP_IDENTITY:
281             self->priv->identity = g_value_dup_object (value);
282             break;
283         default:
284             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
285     }
286 }
287
288 static void
289 signon_auth_session_get_property (GObject *object,
290                                   guint property_id,
291                                   GValue *value,
292                                   GParamSpec *pspec)
293 {
294     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
295
296     switch (property_id)
297     {
298         case PROP_IDENTITY:
299             g_value_set_object (value, self->priv->identity);
300             break;
301         default:
302             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
303     }
304 }
305
306 static void
307 signon_auth_session_init (SignonAuthSession *self)
308 {
309     self->priv = SIGNON_AUTH_SESSION_GET_PRIV (self);
310     self->priv->cancellable = g_cancellable_new ();
311 }
312
313 static void
314 signon_auth_session_dispose (GObject *object)
315 {
316     g_return_if_fail (SIGNON_IS_AUTH_SESSION (object));
317     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
318     SignonAuthSessionPrivate *priv = self->priv;
319     g_return_if_fail (priv != NULL);
320
321     if (priv->dispose_has_run)
322         return;
323
324     if (priv->cancellable)
325     {
326         g_cancellable_cancel (priv->cancellable);
327         g_object_unref (priv->cancellable);
328         priv->cancellable = NULL;
329     }
330
331     if (priv->proxy)
332     {
333         g_signal_handler_disconnect (priv->proxy, priv->signal_state_changed);
334         g_signal_handler_disconnect (priv->proxy, priv->signal_unregistered);
335         g_object_unref (priv->proxy);
336
337         priv->proxy = NULL;
338     }
339
340     G_OBJECT_CLASS (signon_auth_session_parent_class)->dispose (object);
341
342     priv->dispose_has_run = TRUE;
343 }
344
345 static void
346 signon_auth_session_finalize (GObject *object)
347 {
348     g_return_if_fail (SIGNON_IS_AUTH_SESSION(object));
349
350     SignonAuthSession *self = SIGNON_AUTH_SESSION(object);
351     SignonAuthSessionPrivate *priv = self->priv;
352     g_return_if_fail (priv != NULL);
353
354     g_free (priv->method_name);
355     g_object_unref (priv->identity);
356
357     G_OBJECT_CLASS (signon_auth_session_parent_class)->finalize (object);
358 }
359
360 static void
361 signon_auth_session_class_init (SignonAuthSessionClass *klass)
362 {
363     GObjectClass *object_class = G_OBJECT_CLASS (klass);
364     GParamSpec *pspec;
365
366     object_class->set_property = signon_auth_session_set_property;
367     object_class->get_property = signon_auth_session_get_property;
368
369     pspec = g_param_spec_object ("identity",
370                                  "Identity Object",
371                                  "Identity Object construct parameter",
372                                  SIGNON_TYPE_IDENTITY,
373                                  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
374     g_object_class_install_property (object_class,
375                                      PROP_IDENTITY,
376                                      pspec);
377
378     g_type_class_add_private (object_class, sizeof (SignonAuthSessionPrivate));
379
380     /**
381      * SignonAuthSession::state-changed:
382      * @auth_session: the #SignonAuthSession
383      * @state: the current state of the #SignonAuthSession
384      * @message: the message associated with the state change
385      *
386      * Emitted when the state of the #SignonAuthSession changes.
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.
490  */
491 void
492 signon_auth_session_query_available_mechanisms (SignonAuthSession *self,
493                                                 const gchar **wanted_mechanisms,
494                                                 SignonAuthSessionQueryAvailableMechanismsCb cb,
495                                                 gpointer user_data)
496 {
497     g_return_if_fail (SIGNON_IS_AUTH_SESSION (self));
498     SignonAuthSessionPrivate* priv = self->priv;
499
500     g_return_if_fail (priv != NULL);
501
502     AuthSessionQueryAvailableMechanismsCbData *cb_data = g_slice_new0 (AuthSessionQueryAvailableMechanismsCbData);
503     cb_data->self = self;
504     cb_data->cb = cb;
505     cb_data->user_data = user_data;
506
507     AuthSessionQueryAvailableMechanismsData *operation_data = g_slice_new0 (AuthSessionQueryAvailableMechanismsData);
508     operation_data->wanted_mechanisms = g_strdupv ((gchar **)wanted_mechanisms);
509     operation_data->cb_data = cb_data;
510
511     auth_session_check_remote_object(self);
512     _signon_object_call_when_ready (self,
513                                     auth_session_object_quark(),
514                                     auth_session_query_available_mechanisms_ready_cb,
515                                     operation_data);
516 }
517
518 /**
519  * SignonAuthSessionProcessCb:
520  * @self: the #SignonAuthSession.
521  * @session_data: (transfer full) (element-type utf8 GValue): a dictionary with
522  * the response.
523  * @error: a #GError if an error occurred, %NULL otherwise.
524  * @user_data: the user data that was passed when installing this callback.
525  *
526  * This callback is invoked when the authentication plugin delivers the result
527  * of the signon_auth_session_process() operation.
528  */
529
530 /**
531  * signon_auth_session_process:
532  * @self: the #SignonAuthSession.
533  * @session_data: (transfer none) (element-type utf8 GValue): a dictionary of parameters.
534  * @mechanism: the authentication mechanism to be used.
535  * @cb: (scope async): a callback which will be called with the result.
536  * @user_data: user data to be passed to the callback.
537  *
538  * Performs one step of the authentication process. If the #SignonAuthSession
539  * object is bound to an existing identity, the identity properties such as
540  * username and password will be also passed to the authentication plugin, so
541  * there's no need to fill them into @session_data.
542  * @session_data can be used to add additional authentication parameters to the
543  * session, or to override the parameters otherwise taken from the identity.
544  *
545  * Deprecated: 1.8: Use signon_auth_session_process_async() instead.
546  */
547 void
548 signon_auth_session_process (SignonAuthSession *self,
549                              const GHashTable *session_data,
550                              const gchar* mechanism,
551                              SignonAuthSessionProcessCb cb,
552                              gpointer user_data)
553 {
554     GVariant *v_session_data;
555
556     g_return_if_fail (SIGNON_IS_AUTH_SESSION (self));
557     DEBUG ("%s %d", G_STRFUNC, __LINE__);
558
559     AuthSessionProcessCbData *cb_data = g_slice_new0 (AuthSessionProcessCbData);
560     cb_data->cb = cb;
561     cb_data->user_data = user_data;
562
563     v_session_data = signon_hash_table_to_variant (session_data);
564
565     signon_auth_session_process_async (self, v_session_data, mechanism, NULL,
566                                        process_async_cb_wrapper, cb_data);
567 }
568
569 /**
570  * signon_auth_session_process_async:
571  * @self: the #SignonAuthSession.
572  * @session_data: (transfer floating): a dictionary of parameters.
573  * @mechanism: the authentication mechanism to be used.
574  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore.
575  * @callback: (scope async): a callback which will be called when the
576  * authentication reply is available.
577  * @user_data: user data to be passed to the callback.
578  *
579  * Performs one step of the authentication process. If the #SignonAuthSession
580  * object is bound to an existing identity, the identity properties such as
581  * username and password will be also passed to the authentication plugin, so
582  * there's no need to fill them into @session_data.
583  * @session_data can be used to add additional authentication parameters to the
584  * session, or to override the parameters otherwise taken from the identity.
585  *
586  * Since: 1.8
587  */
588 void
589 signon_auth_session_process_async (SignonAuthSession *self,
590                                    GVariant *session_data,
591                                    const gchar *mechanism,
592                                    GCancellable *cancellable,
593                                    GAsyncReadyCallback callback,
594                                    gpointer user_data)
595 {
596     SignonAuthSessionPrivate *priv;
597     AuthSessionProcessData *process_data;
598     GSimpleAsyncResult *res;
599
600     g_return_if_fail (SIGNON_IS_AUTH_SESSION (self));
601     priv = self->priv;
602
603     g_return_if_fail (session_data != NULL);
604
605     res = g_simple_async_result_new ((GObject *)self, callback, user_data,
606                                      signon_auth_session_process_async);
607     g_simple_async_result_set_check_cancellable (res, cancellable);
608
609     process_data = g_slice_new0 (AuthSessionProcessData);
610     process_data->session_data = g_variant_ref_sink (session_data);
611     process_data->mechanism = g_strdup (mechanism);
612     process_data->cancellable = cancellable;
613     g_object_set_data_full ((GObject *)res, data_key_process, process_data,
614                             (GDestroyNotify)auth_session_process_data_free);
615
616     priv->busy = TRUE;
617
618     auth_session_check_remote_object(self);
619     _signon_object_call_when_ready (self,
620                                     auth_session_object_quark(),
621                                     auth_session_process_ready_cb,
622                                     res);
623 }
624
625 /**
626  * signon_auth_session_process_finish:
627  * @self: the #SignonAuthSession.
628  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to
629  * signon_auth_session_process_async().
630  * @error: return location for error, or %NULL.
631  *
632  * Collect the result of the signon_auth_session_process_async() operation.
633  *
634  * Returns: a #GVariant of type %G_VARIANT_TYPE_VARDICT containing the
635  * authentication reply.
636  *
637  * Since: 1.8
638  */
639 GVariant *
640 signon_auth_session_process_finish (SignonAuthSession *self, GAsyncResult *res,
641                                     GError **error)
642 {
643     GSimpleAsyncResult *async_result;
644     GVariant *reply;
645
646     g_return_val_if_fail (SIGNON_IS_AUTH_SESSION (self), NULL);
647
648     async_result = (GSimpleAsyncResult *)res;
649     if (g_simple_async_result_propagate_error (async_result, error))
650         return NULL;
651
652     reply = g_simple_async_result_get_op_res_gpointer (async_result);
653     return g_variant_ref (reply);
654 }
655
656 /**
657  * signon_auth_session_cancel:
658  * @self: the #SignonAuthSession.
659  *
660  * Cancel the authentication session.
661  */
662 void
663 signon_auth_session_cancel (SignonAuthSession *self)
664 {
665     g_return_if_fail (SIGNON_IS_AUTH_SESSION (self));
666     SignonAuthSessionPrivate *priv = self->priv;
667
668     g_return_if_fail (priv != NULL);
669
670     auth_session_check_remote_object(self);
671
672     if (!priv->busy)
673         return;
674
675     priv->canceled = TRUE;
676     _signon_object_call_when_ready (self,
677                                     auth_session_object_quark(),
678                                     auth_session_cancel_ready_cb,
679                                     NULL);
680 }
681
682 static void
683 auth_session_state_changed_cb (GDBusProxy *proxy,
684                                gint state,
685                                gchar *message,
686                                gpointer user_data)
687 {
688     g_return_if_fail (SIGNON_IS_AUTH_SESSION (user_data));
689     SignonAuthSession *self = SIGNON_AUTH_SESSION (user_data);
690
691     g_signal_emit ((GObject *)self,
692                     auth_session_signals[STATE_CHANGED],
693                     0,
694                     state,
695                     message);
696 }
697
698 static void auth_session_remote_object_destroyed_cb (GDBusProxy *proxy,
699                                                      gpointer user_data)
700 {
701     g_return_if_fail (SIGNON_IS_AUTH_SESSION (user_data));
702     SignonAuthSession *self = SIGNON_AUTH_SESSION (user_data);
703     SignonAuthSessionPrivate *priv = self->priv;
704     g_return_if_fail (priv != NULL);
705     DEBUG ("remote object unregistered");
706
707     if (priv->proxy)
708     {
709         g_object_unref (priv->proxy);
710         priv->proxy = NULL;
711     }
712
713     /*
714      * as remote object is destroyed only
715      * when the session core is destroyed,
716      * so there should not be any processes
717      * running
718      * */
719     priv->busy = FALSE;
720     priv->canceled = FALSE;
721     _signon_object_not_ready(self);
722 }
723
724 static gboolean
725 auth_session_priv_init (SignonAuthSession *self,
726                         const gchar *method_name, GError **err)
727 {
728     g_return_val_if_fail (SIGNON_IS_AUTH_SESSION (self), FALSE);
729     SignonAuthSessionPrivate *priv = SIGNON_AUTH_SESSION_PRIV (self);
730     g_return_val_if_fail (priv, FALSE);
731
732     priv->method_name = g_strdup (method_name);
733
734     priv->registering = FALSE;
735     priv->busy = FALSE;
736     priv->canceled = FALSE;
737     return TRUE;
738 }
739
740 static void
741 auth_session_query_mechanisms_reply (GObject *object, GAsyncResult *res,
742                                      gpointer userdata)
743 {
744     SsoAuthSession *proxy = SSO_AUTH_SESSION (object);
745     gchar **mechanisms = NULL;
746     GError *error = NULL;
747     AuthSessionQueryAvailableMechanismsCbData *cb_data =
748         (AuthSessionQueryAvailableMechanismsCbData *)userdata;
749     g_return_if_fail (cb_data != NULL);
750
751     sso_auth_session_call_query_available_mechanisms_finish (proxy,
752                                                              &mechanisms,
753                                                              res,
754                                                              &error);
755     if (SIGNON_IS_NOT_CANCELLED (error))
756     {
757         (cb_data->cb) (cb_data->self, mechanisms, error, cb_data->user_data);
758     }
759
760     g_clear_error (&error);
761     g_slice_free (AuthSessionQueryAvailableMechanismsCbData, cb_data);
762 }
763
764 static void
765 auth_session_query_available_mechanisms_ready_cb (gpointer object, const GError *error,
766                                                   gpointer user_data)
767 {
768     g_return_if_fail (SIGNON_IS_AUTH_SESSION (object));
769     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
770     SignonAuthSessionPrivate *priv = self->priv;
771     g_return_if_fail (priv != NULL);
772
773     AuthSessionQueryAvailableMechanismsData *operation_data =
774         (AuthSessionQueryAvailableMechanismsData *)user_data;
775     g_return_if_fail (operation_data != NULL);
776
777     AuthSessionQueryAvailableMechanismsCbData *cb_data = operation_data->cb_data;
778     g_return_if_fail (cb_data != NULL);
779
780     if (error)
781     {
782         (cb_data->cb)
783             (self, NULL, error, cb_data->user_data);
784
785         g_slice_free (AuthSessionQueryAvailableMechanismsCbData, cb_data);
786     }
787     else
788     {
789         g_return_if_fail (priv->proxy != NULL);
790         sso_auth_session_call_query_available_mechanisms (
791             priv->proxy,
792             (const char **)operation_data->wanted_mechanisms,
793             priv->cancellable,
794             auth_session_query_mechanisms_reply,
795             cb_data);
796
797         g_signal_emit (self,
798                        auth_session_signals[STATE_CHANGED],
799                        0,
800                        SIGNON_AUTH_SESSION_STATE_PROCESS_PENDING,
801                        auth_session_process_pending_message);
802     }
803
804     g_strfreev (operation_data->wanted_mechanisms);
805     g_slice_free (AuthSessionQueryAvailableMechanismsData, operation_data);
806 }
807
808 static void
809 auth_session_cancel_ready_cb (gpointer object, const GError *error, gpointer user_data)
810 {
811     g_return_if_fail (SIGNON_IS_AUTH_SESSION (object));
812     g_return_if_fail (user_data == NULL);
813
814     SignonAuthSession *self = SIGNON_AUTH_SESSION (object);
815     SignonAuthSessionPrivate *priv = self->priv;
816     g_return_if_fail (priv != NULL);
817
818     if (error)
819     {
820         //TODO: in general this function does not return any values,
821         // that is why I think it should not emit anything for this particular case
822         DEBUG("error during initialization");
823     }
824     else if (priv->proxy && priv->busy)
825         sso_auth_session_call_cancel_sync (priv->proxy,
826                                            priv->cancellable,
827                                            NULL);
828
829     priv->busy = FALSE;
830     priv->canceled = FALSE;
831 }
832
833 static void
834 signon_auth_session_complete (SignonAuthSession *self,
835                               GError *error,
836                               GDBusConnection *connection,
837                               const gchar *bus_name,
838                               const gchar *object_path)
839 {
840     SignonAuthSessionPrivate *priv = self->priv;
841     g_return_if_fail (priv != NULL);
842
843     DEBUG ("%s %d", G_STRFUNC, __LINE__);
844
845     priv->registering = FALSE;
846     if (!g_strcmp0(object_path, "") || error)
847     {
848         if (error)
849             DEBUG ("Error message is %s", error->message);
850         else
851             error = g_error_new (signon_error_quark(),
852                                  SIGNON_ERROR_RUNTIME,
853                                  "Cannot create remote AuthSession object");
854     }
855     else
856     {
857         GError *proxy_error = NULL;
858
859         priv->proxy =
860             sso_auth_session_proxy_new_sync (connection,
861                                              G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
862                                              bus_name,
863                                              object_path,
864                                              priv->cancellable,
865                                              &proxy_error);
866         if (G_UNLIKELY (proxy_error != NULL))
867         {
868             g_warning ("Failed to initialize AuthSession proxy: %s",
869                        proxy_error->message);
870             g_clear_error (&proxy_error);
871         }
872
873         g_dbus_proxy_set_default_timeout ((GDBusProxy *)priv->proxy,
874                                           G_MAXINT);
875
876         priv->signal_state_changed =
877             g_signal_connect (priv->proxy,
878                               "state-changed",
879                               G_CALLBACK (auth_session_state_changed_cb),
880                               self);
881
882         priv->signal_unregistered =
883            g_signal_connect (priv->proxy,
884                              "unregistered",
885                              G_CALLBACK (auth_session_remote_object_destroyed_cb),
886                              self);
887     }
888
889     DEBUG ("Object path received: %s", object_path);
890     _signon_object_ready (self, auth_session_object_quark (), error);
891 }
892
893 static void
894 auth_session_check_remote_object(SignonAuthSession *self)
895 {
896     g_return_if_fail (self != NULL);
897     SignonAuthSessionPrivate *priv = self->priv;
898     g_return_if_fail (priv != NULL);
899
900     if (priv->proxy != NULL)
901         return;
902
903     g_return_if_fail (priv->identity != NULL);
904
905     if (!priv->registering)
906     {
907         DEBUG ("%s %d", G_STRFUNC, __LINE__);
908
909         priv->registering = TRUE;
910         signon_identity_get_auth_session (priv->identity,
911                                           self,
912                                           priv->method_name,
913                                           signon_auth_session_complete);
914
915     }
916 }
917