f165a2608391918c490120fa2f7166aa969223a8
[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     }
242
243     _ProcessData * data = g_slice_new0 (_ProcessData);
244     data->self = self;
245     data->ready_cb = ready_cb;
246     data->state_change_cb = state_change_cb;
247     data->userdata = userdata;
248     gsignond_plugin_proxy_process(self->priv->proxy, self, session_data,
249                                   self->priv->token_data,
250                                   mechanism, data);
251
252     return TRUE;
253 }
254
255 gboolean
256 gsignond_auth_session_cancel (GSignondAuthSession *self,
257                               const GSignondSecurityContext *ctx,
258                               GError **error)
259 {
260     if (!self || !GSIGNOND_IS_AUTH_SESSION (self)) {
261         WARN ("assertion (self && GSIGNOND_IS_AUTH_SESSION (self)) failed");
262         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
263         return FALSE;
264     }
265     VALIDATE_READ_ACCESS (self->priv->identity_info, ctx, FALSE);
266
267     gsignond_plugin_proxy_cancel(self->priv->proxy, self);
268     g_signal_emit (self, signals[SIG_PROCESS_CANCELED], 0, NULL);
269
270     return TRUE;
271 }
272
273 void
274 gsignond_auth_session_abort_process (GSignondAuthSession *self)
275 {
276     g_return_if_fail (self && GSIGNOND_IS_AUTH_SESSION (self));
277
278     gsignond_plugin_proxy_cancel (self->priv->proxy, self);
279     g_signal_emit (self, signals[SIG_PROCESS_CANCELED], 0, NULL);
280 }
281
282 void 
283 gsignond_auth_session_user_action_finished (GSignondAuthSession *self,
284                                             GSignondSignonuiData *ui_data)
285 {
286     gsignond_plugin_proxy_user_action_finished(self->priv->proxy, ui_data);
287 }
288
289 void
290 gsignond_auth_session_refresh (GSignondAuthSession *self, 
291                                GSignondSignonuiData *ui_data)
292 {
293     gsignond_plugin_proxy_refresh(self->priv->proxy, ui_data);
294 }
295
296 GSignondAccessControlManager *
297 gsignond_auth_session_get_acm (GSignondAuthSession *session)
298 {
299     return gsignond_get_access_control_manager ();
300 }
301
302 static void
303 _get_property (GObject *object, guint property_id, GValue *value,
304                GParamSpec *pspec)
305 {
306     GSignondAuthSession *self = GSIGNOND_AUTH_SESSION (object);
307
308     switch (property_id)
309     {
310         case PROP_METHOD:
311             g_value_set_string (value, self->priv->method);
312             break;
313         default:
314             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
315     }
316 }
317
318 static void
319 _set_property (GObject *object, guint property_id, const GValue *value,
320                GParamSpec *pspec)
321 {
322     GSignondAuthSession *self = GSIGNOND_AUTH_SESSION (object);
323
324     switch (property_id)
325     {
326         case PROP_METHOD:
327             self->priv->method = g_value_dup_string (value);
328             break;
329         default:
330             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
331     }
332 }
333
334 static void
335 _dispose (GObject *object)
336 {
337     GSignondAuthSession *self = GSIGNOND_AUTH_SESSION (object);
338
339     if (self->priv->proxy) {
340         g_object_unref (self->priv->proxy);
341         self->priv->proxy = NULL;
342     }
343
344     if (self->priv->identity_info) {
345         g_hash_table_unref ((GHashTable *)self->priv->identity_info);
346         self->priv->identity_info = NULL;
347     }
348
349     if (self->priv->token_data) {
350         gsignond_dictionary_unref (self->priv->token_data);
351         self->priv->token_data = NULL;
352     }
353
354     G_OBJECT_CLASS (gsignond_auth_session_parent_class)->dispose (object);
355 }
356
357 static void
358 _finalize (GObject *object)
359 {
360     GSignondAuthSession *self = GSIGNOND_AUTH_SESSION (object);
361
362     if (self->priv->method) {
363         g_free (self->priv->method);
364         self->priv->method = NULL;
365     }
366
367     if (self->priv->available_mechanisms) {
368         g_sequence_free (self->priv->available_mechanisms);
369         self->priv->available_mechanisms = NULL;
370     }
371
372     G_OBJECT_CLASS (gsignond_auth_session_parent_class)->finalize (object);
373 }
374
375 static void
376 gsignond_auth_session_init (GSignondAuthSession *self)
377 {
378     self->priv = GSIGNOND_AUTH_SESSION_PRIV (self);
379
380     self->priv->method = NULL;
381     self->priv->proxy = NULL;
382     self->priv->identity_info = NULL;
383     self->priv->token_data = NULL;
384     self->priv->available_mechanisms = NULL;
385 }
386
387 static void
388 gsignond_auth_session_class_init (GSignondAuthSessionClass *klass)
389 {
390     GObjectClass *object_class = G_OBJECT_CLASS (klass);
391
392     g_type_class_add_private (klass, sizeof (GSignondAuthSessionPrivate));
393
394     object_class->get_property = _get_property;
395     object_class->set_property = _set_property;
396     object_class->dispose = _dispose;
397     object_class->finalize = _finalize;
398
399     properties[PROP_METHOD] =
400         g_param_spec_string ("method",
401                              "authentication method",
402                              "Authentication method used",
403                              NULL,
404                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
405                              | G_PARAM_STATIC_STRINGS);
406
407     g_object_class_install_properties (object_class, N_PROPERTIES, properties);
408
409     signals[SIG_PROCESS_STORE] =  g_signal_new ("process-store",
410             GSIGNOND_TYPE_AUTH_SESSION,
411             G_SIGNAL_RUN_LAST,
412             0,
413             NULL,
414             NULL,
415             NULL,
416             G_TYPE_NONE,
417             1,
418             GSIGNOND_TYPE_DICTIONARY);
419
420     signals[SIG_PROCESS_USER_ACTION_REQUIRED] =  g_signal_new ("process-user-action-required",
421             GSIGNOND_TYPE_AUTH_SESSION,
422             G_SIGNAL_RUN_LAST,
423             0,
424             NULL,
425             NULL,
426             NULL,
427             G_TYPE_NONE,
428             1,
429             GSIGNOND_TYPE_SIGNONUI_DATA);
430
431     signals[SIG_PROCESS_REFRESHED] =  g_signal_new ("process-refreshed",
432             GSIGNOND_TYPE_AUTH_SESSION,
433             G_SIGNAL_RUN_LAST,
434             0,
435             NULL,
436             NULL,
437             NULL,
438             G_TYPE_NONE,
439             1,
440             GSIGNOND_TYPE_SIGNONUI_DATA);
441
442     signals[SIG_PROCESS_CANCELED] =  g_signal_new ("process-canceled",
443             GSIGNOND_TYPE_AUTH_SESSION,
444             G_SIGNAL_RUN_LAST,
445             0,
446             NULL,
447             NULL,
448             NULL,
449             G_TYPE_NONE,
450             0,
451             G_TYPE_NONE);
452
453 }
454
455 /**
456  * gsignond_auth_session_get_method:
457  * @session: instance of #GSignondAuthSession
458  *
459  * Retrieves authentication method used by #session.
460  *
461  * Returns: (transfer none) authenticaiton method if success, NULL otherwise
462  */
463 const gchar *
464 gsignond_auth_session_get_method (GSignondAuthSession *session)
465 {
466     g_return_val_if_fail (session && GSIGNOND_IS_AUTH_SESSION (session), NULL);
467
468     return session->priv->method;
469 }
470
471 GSignondDictionary *
472 gsignond_auth_session_get_token_data (GSignondAuthSession *session)
473 {
474     g_return_val_if_fail (session && GSIGNOND_IS_AUTH_SESSION (session), NULL);
475
476     return session->priv->token_data;
477 }
478
479 void
480 gsignond_auth_session_notify_process_result (GSignondAuthSession *iface,
481                                              GSignondSessionData *result,
482                                              gpointer userdata)
483 {
484     if (!userdata) {
485         WARN("assert (userdata)");
486         return ;
487     }
488     _ProcessData *data = (_ProcessData *)userdata;
489
490     if (data->ready_cb) data->ready_cb (result, NULL, data->userdata);
491
492     g_slice_free (_ProcessData, data);
493 }
494
495 void
496 gsignond_auth_session_notify_process_error (GSignondAuthSession *iface,
497                                             const GError *error,
498                                             gpointer userdata)
499 {
500     if (!userdata) {
501         WARN("assert (userdata)");
502         return ;
503     }
504     _ProcessData *data = (_ProcessData *)userdata;
505
506     if (data->ready_cb) data->ready_cb (NULL, error, data->userdata);
507
508     g_slice_free (_ProcessData, data);
509 }
510
511 void 
512 gsignond_auth_session_notify_state_changed (GSignondAuthSession *self,
513                                             gint state,
514                                             const gchar *message,
515                                             gpointer userdata)
516 {
517     if (!userdata) {
518         WARN("assert (userdata)");
519         return ;
520     }
521     _ProcessData *data = (_ProcessData *)userdata;
522
523     if (data->state_change_cb) data->state_change_cb (state, message, data->userdata);
524 }
525
526 void 
527 gsignond_auth_session_notify_store (GSignondAuthSession *self, 
528                                     GSignondDictionary *token_data)
529 {
530     g_return_if_fail (self && GSIGNOND_IS_AUTH_SESSION (self));
531     g_return_if_fail (token_data);
532
533     /* cache token data */
534     if (self->priv->token_data)
535         gsignond_dictionary_unref (self->priv->token_data);
536     self->priv->token_data = gsignond_dictionary_ref (token_data);
537
538     g_signal_emit (self, signals[SIG_PROCESS_STORE], 0, token_data);
539 }
540
541 void 
542 gsignond_auth_session_notify_user_action_required (GSignondAuthSession *self, 
543                                                    GSignondSignonuiData *ui_data)
544 {
545     g_signal_emit (self, signals[SIG_PROCESS_USER_ACTION_REQUIRED], 0, ui_data);
546 }
547
548 void 
549 gsignond_auth_session_notify_refreshed (GSignondAuthSession *self, 
550                                         GSignondSignonuiData *ui_data)
551 {
552     g_signal_emit (self, signals[SIG_PROCESS_REFRESHED], 0, ui_data);
553 }
554
555
556 /**
557  * gsignond_auth_session_new:
558  * @info: instance of #GSignondIdentityInfo
559  * @method: authentication method
560  * @token_data: (transfer full) stored token data stored for #method
561  *
562  * Creates instance of #GSignondAuthSession.
563  *
564  * Returns: (transfer full) newly created object 
565  */
566 GSignondAuthSession * 
567 gsignond_auth_session_new (GSignondIdentityInfo *info, const gchar *method, GSignondDictionary *token_data)
568 {
569     GSignondPluginProxy* proxy = NULL;
570
571     g_return_val_if_fail (method, NULL);
572
573     proxy = gsignond_plugin_proxy_factory_get_plugin(
574     gsignond_get_plugin_proxy_factory(), method);
575     if (!proxy) return NULL;
576
577     GSignondAuthSession *auth_session =
578         g_object_new (GSIGNOND_TYPE_AUTH_SESSION,
579                       "method", method, NULL);
580     auth_session->priv->proxy = proxy;
581     auth_session->priv->identity_info = g_hash_table_ref ((GHashTable *)info);
582     auth_session->priv->token_data = token_data ? gsignond_dictionary_ref(token_data)
583                                                 : gsignond_dictionary_new();
584
585     return auth_session;
586 }