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