Update to upstream 1.0.1
[profile/ivi/gsignond.git] / src / daemon / gsignond-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 gsignond
5  *
6  * Copyright (C) 2013 Intel Corporation.
7  *
8  * Contact: Jussi Laako <jussi.laako@linux.intel.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  */
25
26 #include "gsignond-auth-session.h"
27 #include "gsignond/gsignond-error.h"
28 #include "gsignond/gsignond-log.h"
29 #include "gsignond/gsignond-session-data.h"
30 #include "plugins/gsignond-plugin-proxy-factory.h"
31 #include "gsignond-daemon.h"
32
33 enum
34 {
35     PROP_0,
36     PROP_METHOD,
37     N_PROPERTIES
38 };
39
40 static GParamSpec *properties[N_PROPERTIES];
41
42 enum {
43     SIG_PROCESS_STORE,
44     SIG_PROCESS_USER_ACTION_REQUIRED,
45     SIG_PROCESS_REFRESHED,
46     SIG_PROCESS_CANCELED,
47  
48     SIG_MAX
49 };
50
51 static guint signals[SIG_MAX] = { 0 };
52
53 typedef struct {
54     GSignondAuthSession *self;
55     ProcessReadyCb ready_cb;
56     StateChangeCb state_change_cb;
57     gpointer userdata;
58 } _ProcessData;
59
60 struct _GSignondAuthSessionPrivate
61 {
62     gchar *method;
63     GSignondPluginProxy *proxy;
64     GSequence *available_mechanisms;
65     GSignondIdentityInfo *identity_info;
66     GSignondDictionary *token_data;
67 };
68
69 G_DEFINE_TYPE (GSignondAuthSession, gsignond_auth_session, G_TYPE_OBJECT)
70
71 #define GSIGNOND_AUTH_SESSION_PRIV(obj) \
72     G_TYPE_INSTANCE_GET_PRIVATE ((obj), GSIGNOND_TYPE_AUTH_SESSION, \
73                                  GSignondAuthSessionPrivate)
74
75 #define VALIDATE_READ_ACCESS(info, ctx, ret) \
76 { \
77     GSignondAccessControlManager *acm = gsignond_get_access_control_manager(); \
78     GSignondSecurityContextList *acl = gsignond_identity_info_get_access_control_list (info); \
79     GSignondSecurityContext *owner = gsignond_identity_info_get_owner (info); \
80     gboolean valid = gsignond_access_control_manager_peer_is_allowed_to_use_identity (acm, ctx, owner, acl); \
81     gsignond_security_context_free (owner); \
82     gsignond_security_context_list_free (acl); \
83     if (!valid) { \
84         WARN ("security check failed"); \
85         if (error) { \
86             *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_PERMISSION_DENIED, "Can not access identity"); \
87         } \
88         return ret; \
89     } \
90 }
91
92 static gint
93 _sort_cmp (gconstpointer str1, gconstpointer str2, gpointer user_data)
94 {
95     (void) user_data;
96
97     return g_strcmp0 ((const gchar *) str1, (const gchar *) str2);
98 }
99
100 static void
101 _create_mechanism_cache (GSignondAuthSession *self)
102 {
103     GSignondAuthSessionPrivate *priv = self->priv;
104
105     if (priv->available_mechanisms)
106         return;
107
108     gchar **mechanisms, **iter;
109     GSequence *allowed_mechanisms = NULL;
110     GSequenceIter *wcard = NULL;
111
112     self->priv->available_mechanisms = g_sequence_new (g_free);
113     if (!gsignond_identity_info_get_is_identity_new (priv->identity_info)) {
114         allowed_mechanisms = gsignond_identity_info_get_mechanisms (
115                                                            priv->identity_info,
116                                                            priv->method);
117         if (!allowed_mechanisms)
118             return;
119         wcard = g_sequence_lookup (allowed_mechanisms,
120                                    (gpointer) "*",
121                                    _sort_cmp, NULL);
122     }
123
124     g_object_get (self->priv->proxy, 
125                   "mechanisms", &mechanisms,
126                   NULL);
127     if (!mechanisms) {
128         if (allowed_mechanisms)
129             g_sequence_free (allowed_mechanisms);
130         return;
131     }
132     if (wcard || !allowed_mechanisms) {
133         DBG ("add all mechanisms to allowed");
134         for (iter = mechanisms; *iter != NULL; iter++) {
135             g_sequence_insert_sorted (priv->available_mechanisms,
136                                       (gpointer) *iter,
137                                       _sort_cmp,
138                                       NULL);
139             DBG ("  allow '%s'", *iter);
140         }
141     } else {
142         DBG ("allow intersection of plugin and ACL mechanisms");
143         for (iter = mechanisms; *iter != NULL; iter++) {
144             GSequenceIter *pos = g_sequence_lookup (allowed_mechanisms,
145                                                     (gpointer) *iter,
146                                                     _sort_cmp,
147                                                     NULL);
148             if (pos) {
149                 DBG ("  allow: '%s'", *iter); 
150                 g_sequence_insert_sorted (priv->available_mechanisms,
151                                           (gpointer) *iter,
152                                           _sort_cmp,
153                                           NULL);
154             }
155         }
156     }
157     if (allowed_mechanisms)
158         g_sequence_free (allowed_mechanisms);
159     g_free (mechanisms);
160 }
161
162 gchar **
163 gsignond_auth_session_query_available_mechanisms (GSignondAuthSession *self,
164                                                   const gchar **wanted_mechanisms,
165                                                   const GSignondSecurityContext *ctx,
166                                                   GError **error)
167 {
168     if (!self || !GSIGNOND_IS_AUTH_SESSION (self)) {
169         WARN ("assertion (iself && GSIGNOND_IS_AUTH_SESSION (self)) failed");
170         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
171         return NULL;
172     }
173
174     VALIDATE_READ_ACCESS (self->priv->identity_info, ctx, NULL);
175
176     gchar **mechanisms, **iter;
177     const gchar **src_iter;
178
179     _create_mechanism_cache (self);
180     mechanisms = (gchar **)
181         g_malloc0 ((g_sequence_get_length (self->priv->available_mechanisms) +
182                    1) * sizeof(gchar *));
183     iter = mechanisms;
184     for (src_iter = wanted_mechanisms; *src_iter != NULL; src_iter++) {
185         GSequenceIter *pos = g_sequence_lookup (
186                                               self->priv->available_mechanisms,
187                                               (gpointer) *src_iter,
188                                               _sort_cmp,
189                                               NULL);
190         if (pos) {
191             *iter = g_sequence_get (pos);
192             iter++;
193         }
194     }
195     *iter = NULL;
196
197     return mechanisms;
198 }
199
200 gboolean
201 gsignond_auth_session_process (GSignondAuthSession *self,
202                                GSignondSessionData *session_data,
203                                const gchar *mechanism,
204                                const GSignondSecurityContext *ctx,
205                                ProcessReadyCb ready_cb,
206                                StateChangeCb state_change_cb,
207                                gpointer userdata,
208                                GError **error)
209 {
210     if (!self || !GSIGNOND_IS_AUTH_SESSION (self)) {
211         WARN ("assertion (self && GSIGNOND_IS_AUTH_SESSION (self)) failed");
212         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
213         return FALSE;
214     }
215
216     VALIDATE_READ_ACCESS (self->priv->identity_info, ctx, FALSE);
217
218     _create_mechanism_cache (self);
219     if (!g_sequence_lookup (self->priv->available_mechanisms,
220                             (gpointer) mechanism,
221                             _sort_cmp,
222                             NULL)) {
223         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_MECHANISM_NOT_AVAILABLE, "Mechanism is not available");
224         return FALSE;
225     }
226
227     if (session_data && 
228         self->priv->identity_info) {
229         if (!gsignond_session_data_get_username (session_data)) {
230             const gchar *username =
231                 gsignond_identity_info_get_username (self->priv->identity_info);
232             if (username)
233                 gsignond_session_data_set_username (session_data, username);
234         }
235         if (!gsignond_session_data_get_secret (session_data)) {
236             const gchar *secret =
237                 gsignond_identity_info_get_secret (self->priv->identity_info);
238             if (secret)
239                 gsignond_session_data_set_secret (session_data, secret);
240         }
241         GSequence *realms =
242             gsignond_identity_info_get_realms (self->priv->identity_info);
243         if (realms)
244             gsignond_session_data_set_allowed_realms (session_data,
245                                                       realms);
246     }
247
248     _ProcessData * data = g_slice_new0 (_ProcessData);
249     data->self = self;
250     data->ready_cb = ready_cb;
251     data->state_change_cb = state_change_cb;
252     data->userdata = userdata;
253     gsignond_plugin_proxy_process(self->priv->proxy, self, session_data,
254                                   self->priv->token_data,
255                                   mechanism, data);
256
257     return TRUE;
258 }
259
260 gboolean
261 gsignond_auth_session_cancel (GSignondAuthSession *self,
262                               const GSignondSecurityContext *ctx,
263                               GError **error)
264 {
265     if (!self || !GSIGNOND_IS_AUTH_SESSION (self)) {
266         WARN ("assertion (self && GSIGNOND_IS_AUTH_SESSION (self)) failed");
267         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
268         return FALSE;
269     }
270     VALIDATE_READ_ACCESS (self->priv->identity_info, ctx, FALSE);
271
272     gsignond_plugin_proxy_cancel(self->priv->proxy, self);
273     g_signal_emit (self, signals[SIG_PROCESS_CANCELED], 0, NULL);
274
275     return TRUE;
276 }
277
278 void
279 gsignond_auth_session_abort_process (GSignondAuthSession *self)
280 {
281     g_return_if_fail (self && GSIGNOND_IS_AUTH_SESSION (self));
282
283     gsignond_plugin_proxy_cancel (self->priv->proxy, self);
284     g_signal_emit (self, signals[SIG_PROCESS_CANCELED], 0, NULL);
285 }
286
287 void 
288 gsignond_auth_session_user_action_finished (GSignondAuthSession *self,
289                                             GSignondSignonuiData *ui_data)
290 {
291     gsignond_plugin_proxy_user_action_finished(self->priv->proxy, ui_data);
292 }
293
294 void
295 gsignond_auth_session_refresh (GSignondAuthSession *self, 
296                                GSignondSignonuiData *ui_data)
297 {
298     gsignond_plugin_proxy_refresh(self->priv->proxy, ui_data);
299 }
300
301 GSignondAccessControlManager *
302 gsignond_auth_session_get_acm (GSignondAuthSession *session)
303 {
304     return gsignond_get_access_control_manager ();
305 }
306
307 static void
308 _get_property (GObject *object, guint property_id, GValue *value,
309                GParamSpec *pspec)
310 {
311     GSignondAuthSession *self = GSIGNOND_AUTH_SESSION (object);
312
313     switch (property_id)
314     {
315         case PROP_METHOD:
316             g_value_set_string (value, self->priv->method);
317             break;
318         default:
319             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
320     }
321 }
322
323 static void
324 _set_property (GObject *object, guint property_id, const GValue *value,
325                GParamSpec *pspec)
326 {
327     GSignondAuthSession *self = GSIGNOND_AUTH_SESSION (object);
328
329     switch (property_id)
330     {
331         case PROP_METHOD:
332             self->priv->method = g_value_dup_string (value);
333             break;
334         default:
335             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
336     }
337 }
338
339 static void
340 _dispose (GObject *object)
341 {
342     GSignondAuthSession *self = GSIGNOND_AUTH_SESSION (object);
343
344     if (self->priv->proxy) {
345         g_object_unref (self->priv->proxy);
346         self->priv->proxy = NULL;
347     }
348
349     if (self->priv->identity_info) {
350         gsignond_identity_info_unref (self->priv->identity_info);
351         self->priv->identity_info = NULL;
352     }
353
354     if (self->priv->token_data) {
355         gsignond_dictionary_unref (self->priv->token_data);
356         self->priv->token_data = NULL;
357     }
358
359     G_OBJECT_CLASS (gsignond_auth_session_parent_class)->dispose (object);
360 }
361
362 static void
363 _finalize (GObject *object)
364 {
365     GSignondAuthSession *self = GSIGNOND_AUTH_SESSION (object);
366
367     if (self->priv->method) {
368         g_free (self->priv->method);
369         self->priv->method = NULL;
370     }
371
372     if (self->priv->available_mechanisms) {
373         g_sequence_free (self->priv->available_mechanisms);
374         self->priv->available_mechanisms = NULL;
375     }
376
377     G_OBJECT_CLASS (gsignond_auth_session_parent_class)->finalize (object);
378 }
379
380 static void
381 gsignond_auth_session_init (GSignondAuthSession *self)
382 {
383     self->priv = GSIGNOND_AUTH_SESSION_PRIV (self);
384
385     self->priv->method = NULL;
386     self->priv->proxy = NULL;
387     self->priv->identity_info = NULL;
388     self->priv->token_data = NULL;
389     self->priv->available_mechanisms = NULL;
390 }
391
392 static void
393 gsignond_auth_session_class_init (GSignondAuthSessionClass *klass)
394 {
395     GObjectClass *object_class = G_OBJECT_CLASS (klass);
396
397     g_type_class_add_private (klass, sizeof (GSignondAuthSessionPrivate));
398
399     object_class->get_property = _get_property;
400     object_class->set_property = _set_property;
401     object_class->dispose = _dispose;
402     object_class->finalize = _finalize;
403
404     properties[PROP_METHOD] =
405         g_param_spec_string ("method",
406                              "authentication method",
407                              "Authentication method used",
408                              NULL,
409                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
410                              | G_PARAM_STATIC_STRINGS);
411
412     g_object_class_install_properties (object_class, N_PROPERTIES, properties);
413
414     signals[SIG_PROCESS_STORE] =  g_signal_new ("process-store",
415             GSIGNOND_TYPE_AUTH_SESSION,
416             G_SIGNAL_RUN_LAST,
417             0,
418             NULL,
419             NULL,
420             NULL,
421             G_TYPE_NONE,
422             1,
423             GSIGNOND_TYPE_DICTIONARY);
424
425     signals[SIG_PROCESS_USER_ACTION_REQUIRED] =  g_signal_new ("process-user-action-required",
426             GSIGNOND_TYPE_AUTH_SESSION,
427             G_SIGNAL_RUN_LAST,
428             0,
429             NULL,
430             NULL,
431             NULL,
432             G_TYPE_NONE,
433             1,
434             GSIGNOND_TYPE_SIGNONUI_DATA);
435
436     signals[SIG_PROCESS_REFRESHED] =  g_signal_new ("process-refreshed",
437             GSIGNOND_TYPE_AUTH_SESSION,
438             G_SIGNAL_RUN_LAST,
439             0,
440             NULL,
441             NULL,
442             NULL,
443             G_TYPE_NONE,
444             1,
445             GSIGNOND_TYPE_SIGNONUI_DATA);
446
447     signals[SIG_PROCESS_CANCELED] =  g_signal_new ("process-canceled",
448             GSIGNOND_TYPE_AUTH_SESSION,
449             G_SIGNAL_RUN_LAST,
450             0,
451             NULL,
452             NULL,
453             NULL,
454             G_TYPE_NONE,
455             0,
456             G_TYPE_NONE);
457
458 }
459
460 /**
461  * gsignond_auth_session_get_method:
462  * @session: instance of #GSignondAuthSession
463  *
464  * Retrieves authentication method used by #session.
465  *
466  * Returns: (transfer none) authenticaiton method if success, NULL otherwise
467  */
468 const gchar *
469 gsignond_auth_session_get_method (GSignondAuthSession *session)
470 {
471     g_return_val_if_fail (session && GSIGNOND_IS_AUTH_SESSION (session), NULL);
472
473     return session->priv->method;
474 }
475
476 GSignondDictionary *
477 gsignond_auth_session_get_token_data (GSignondAuthSession *session)
478 {
479     g_return_val_if_fail (session && GSIGNOND_IS_AUTH_SESSION (session), NULL);
480
481     return session->priv->token_data;
482 }
483
484 void
485 gsignond_auth_session_notify_process_result (GSignondAuthSession *iface,
486                                              GSignondSessionData *result,
487                                              gpointer userdata)
488 {
489     if (!userdata) {
490         WARN("assert (userdata)");
491         return ;
492     }
493     _ProcessData *data = (_ProcessData *)userdata;
494
495     if (data->ready_cb) data->ready_cb (result, NULL, data->userdata);
496
497     g_slice_free (_ProcessData, data);
498 }
499
500 void
501 gsignond_auth_session_notify_process_error (GSignondAuthSession *iface,
502                                             const GError *error,
503                                             gpointer userdata)
504 {
505     if (!userdata) {
506         WARN("assert (userdata)");
507         return ;
508     }
509     _ProcessData *data = (_ProcessData *)userdata;
510
511     if (data->ready_cb) data->ready_cb (NULL, error, data->userdata);
512
513     g_slice_free (_ProcessData, data);
514 }
515
516 void 
517 gsignond_auth_session_notify_state_changed (GSignondAuthSession *self,
518                                             gint state,
519                                             const gchar *message,
520                                             gpointer userdata)
521 {
522     if (!userdata) {
523         WARN("assert (userdata)");
524         return ;
525     }
526     _ProcessData *data = (_ProcessData *)userdata;
527
528     if (data->state_change_cb) data->state_change_cb (state, message, data->userdata);
529 }
530
531 void 
532 gsignond_auth_session_notify_store (GSignondAuthSession *self, 
533                                     GSignondDictionary *token_data)
534 {
535     g_return_if_fail (self && GSIGNOND_IS_AUTH_SESSION (self));
536     g_return_if_fail (token_data);
537
538     /* cache token data */
539     if (self->priv->token_data)
540         gsignond_dictionary_unref (self->priv->token_data);
541     self->priv->token_data = gsignond_dictionary_ref (token_data);
542
543     g_signal_emit (self, signals[SIG_PROCESS_STORE], 0, token_data);
544 }
545
546 void 
547 gsignond_auth_session_notify_user_action_required (GSignondAuthSession *self, 
548                                                    GSignondSignonuiData *ui_data)
549 {
550     g_signal_emit (self, signals[SIG_PROCESS_USER_ACTION_REQUIRED], 0, ui_data);
551 }
552
553 void 
554 gsignond_auth_session_notify_refreshed (GSignondAuthSession *self, 
555                                         GSignondSignonuiData *ui_data)
556 {
557     g_signal_emit (self, signals[SIG_PROCESS_REFRESHED], 0, ui_data);
558 }
559
560
561 /**
562  * gsignond_auth_session_new:
563  * @info: instance of #GSignondIdentityInfo
564  * @method: authentication method
565  * @token_data: (transfer full) stored token data stored for #method
566  *
567  * Creates instance of #GSignondAuthSession.
568  *
569  * Returns: (transfer full) newly created object 
570  */
571 GSignondAuthSession * 
572 gsignond_auth_session_new (GSignondIdentityInfo *info, const gchar *method, GSignondDictionary *token_data)
573 {
574     GSignondPluginProxy* proxy = NULL;
575
576     g_return_val_if_fail (method, NULL);
577
578     proxy = gsignond_plugin_proxy_factory_get_plugin(
579     gsignond_get_plugin_proxy_factory(), method);
580     if (!proxy) return NULL;
581
582     GSignondAuthSession *auth_session =
583         g_object_new (GSIGNOND_TYPE_AUTH_SESSION,
584                       "method", method, NULL);
585     auth_session->priv->proxy = proxy;
586     auth_session->priv->identity_info = gsignond_identity_info_ref (info);
587     auth_session->priv->token_data = token_data ? gsignond_dictionary_ref(token_data)
588                                                 : gsignond_dictionary_new();
589
590     return auth_session;
591 }