cb36fa1ffb8aaa7ac183305889a5240c2b7c8b99
[profile/ivi/gsignond.git] / src / daemon / gsignond-identity.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) 2012 Intel Corporation.
7  *
8  * Contact: Jussi Laako <jussi.laako@linux.intel.com>
9             Amarnath Valluri <amarnath.valluri@linux.intel.com>
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24  * 02110-1301 USA
25  */
26
27 #include "gsignond-identity.h"
28 #include <string.h>
29
30 #include "gsignond/gsignond-log.h"
31 #include "gsignond/gsignond-error.h"
32 #include "gsignond-daemon.h"
33 #include "gsignond-identity-enum-types.h"
34 #include "gsignond-auth-session.h"
35 #include "gsignond/gsignond-config-dbus.h"
36 #include "common/gsignond-identity-info-internal.h"
37 #include "plugins/gsignond-plugin-proxy-factory.h"
38
39 enum 
40 {
41     PROP_0,
42     PROP_INFO,
43     N_PROPERTIES
44 };
45
46 enum {
47     SIG_USER_VERIFIED,
48     SIG_SECRET_VERIFIED,
49     SIG_CREDENTIALS_UPDATED,
50     SIG_INFO_UPDATED,
51  
52     SIG_MAX
53 };
54
55 static GParamSpec *properties[N_PROPERTIES];
56 static guint signals[SIG_MAX];
57
58 struct _GSignondIdentityPrivate
59 {
60     GSignondIdentityInfo *info;
61     GSignondDaemon *owner;
62     GHashTable *auth_sessions; // (auth_method,auth_session) table
63 };
64
65 typedef struct _GSignondIdentityCbData
66 {
67     GSignondIdentity *identity;
68     GSignondAuthSession *session;
69 } GSignondIdentityCbData;
70
71 G_DEFINE_TYPE (GSignondIdentity, gsignond_identity, G_TYPE_OBJECT);
72
73
74 static void _on_session_dead (gpointer data, GObject *session);
75 static void _on_refresh_dialog (GSignondAuthSession *session, GSignondSignonuiData *ui_data, gpointer userdata);
76 static void _on_process_canceled (GSignondAuthSession *session, GSignondIdentityCbData *cb_data);
77 static void _on_user_action_required (GSignondAuthSession *session, GSignondSignonuiData *ui_data, gpointer userdata);
78 static void _on_store_token (GSignondAuthSession *session, GSignondDictionary *token_data, gpointer userdata);
79
80 #define GSIGNOND_IDENTITY_PRIV(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), GSIGNOND_TYPE_IDENTITY, GSignondIdentityPrivate)
81
82 #define VALIDATE_IDENTITY_READ_ACCESS(identity, ctx, ret) \
83 { \
84     GSignondAccessControlManager *acm = gsignond_daemon_get_access_control_manager (identity->priv->owner); \
85     GSignondSecurityContextList *acl = gsignond_identity_info_get_access_control_list (identity->priv->info); \
86     GSignondSecurityContext *owner = gsignond_identity_info_get_owner (identity->priv->info); \
87     gboolean valid = gsignond_access_control_manager_peer_is_allowed_to_use_identity (acm, ctx, owner, acl); \
88     gsignond_security_context_free (owner); \
89     gsignond_security_context_list_free (acl); \
90     if (!valid) { \
91         WARN ("cannot access identity."); \
92         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_PERMISSION_DENIED, "identity can not be accessed"); \
93         return ret; \
94     } \
95 }
96
97 #define VALIDATE_IDENTITY_WRITE_ACCESS(identity, ctx, ret) \
98 { \
99     GSignondAccessControlManager *acm = gsignond_daemon_get_access_control_manager (identity->priv->owner); \
100     GSignondSecurityContext *owner = gsignond_identity_info_get_owner (identity->priv->info); \
101     gboolean valid = gsignond_access_control_manager_peer_is_owner_of_identity (acm, ctx, owner); \
102     gsignond_security_context_free (owner); \
103     if (!valid) { \
104         WARN ("is_owner_of_identity check failed."); \
105         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_PERMISSION_DENIED, "identity can not be accessed"); \
106         return ret; \
107     } \
108 }
109
110 #define VALIDATE_IDENTITY_WRITE_ACL(identity, ctx, ret) \
111 { \
112     GSignondAccessControlManager *acm = gsignond_daemon_get_access_control_manager (identity->priv->owner); \
113     GSignondSecurityContextList *acl = gsignond_identity_info_get_access_control_list (identity->priv->info); \
114     gboolean valid = gsignond_access_control_manager_acl_is_valid (acm, ctx, acl); \
115     gsignond_security_context_list_free (acl); \
116     if (!valid) { \
117         WARN ("acl validity check failed."); \
118         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_PERMISSION_DENIED, "invalid access control list"); \
119         return ret; \
120     } \
121 }
122
123 static gboolean 
124 _set_id (GSignondIdentity *identity, guint32 id)
125 {
126     gsignond_identity_info_set_id (identity->priv->info, id);
127     g_object_notify_by_pspec (G_OBJECT(identity), properties[PROP_INFO]);
128
129     return TRUE;
130 }
131
132 static void
133 _get_property (GObject *object, guint property_id, GValue *value,
134                GParamSpec *pspec)
135 {
136     GSignondIdentity *self = GSIGNOND_IDENTITY (object);
137
138     switch (property_id)
139     {
140         case PROP_INFO:
141             g_value_set_boxed (value, self->priv->info);
142             break;
143         default:
144             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
145     }
146 }
147
148 static void
149 _set_property (GObject *object, guint property_id, const GValue *value,
150                GParamSpec *pspec)
151 {
152     GSignondIdentity *self = GSIGNOND_IDENTITY (object);
153
154     switch (property_id)
155     {
156         case PROP_INFO:
157             self->priv->info =
158                (GSignondIdentityInfo *)g_value_get_boxed (value);
159             break;
160         default:
161             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
162     }
163 }
164
165 static void
166 _release_weak_ref_on_session (gpointer key, gpointer value, gpointer data)
167 {
168     GObject *session = G_OBJECT (value);
169     g_signal_handlers_disconnect_by_func (session, G_CALLBACK (_on_user_action_required), data);
170     g_signal_handlers_disconnect_by_func (session, G_CALLBACK (_on_store_token), data);
171     g_object_weak_unref (session, _on_session_dead, data);
172 }
173
174 static void
175 _dispose (GObject *object)
176 {
177     GSignondIdentity *self = GSIGNOND_IDENTITY(object);
178
179     if (self->priv->auth_sessions) {
180         g_hash_table_foreach (self->priv->auth_sessions, _release_weak_ref_on_session, self);
181         g_hash_table_unref (self->priv->auth_sessions);
182         self->priv->auth_sessions = NULL;
183     }
184
185     if (self->priv->owner) {
186         DBG("unref owner %p", self->priv->owner);
187         g_object_unref (self->priv->owner);
188         self->priv->owner = NULL;
189     }
190
191     if (self->priv->info) {
192         gsignond_identity_info_unref (self->priv->info);
193         self->priv->info = NULL;
194     }
195
196     G_OBJECT_CLASS (gsignond_identity_parent_class)->dispose (object);
197 }
198
199 static void
200 _finalize (GObject *object)
201 {
202     G_OBJECT_CLASS (gsignond_identity_parent_class)->finalize (object);
203 }
204
205 static void
206 gsignond_identity_init (GSignondIdentity *self)
207 {
208     self->priv = GSIGNOND_IDENTITY_PRIV(self);
209
210     self->priv->auth_sessions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
211 }
212
213 static void
214 gsignond_identity_class_init (GSignondIdentityClass *klass)
215 {
216     GObjectClass* object_class = G_OBJECT_CLASS (klass);
217
218     g_type_class_add_private (object_class, sizeof (GSignondIdentityPrivate));
219
220     object_class->get_property = _get_property;
221     object_class->set_property = _set_property;
222     object_class->dispose = _dispose;
223     object_class->finalize = _finalize;
224
225     properties[PROP_INFO] =
226         g_param_spec_boxed ("info", 
227                             "identity info", 
228                             "IdentityInfo structure",
229                             GSIGNOND_TYPE_IDENTITY_INFO,
230                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
231                             G_PARAM_STATIC_STRINGS);
232     
233     g_object_class_install_properties (object_class, N_PROPERTIES, properties);
234
235     signals[SIG_USER_VERIFIED] =  g_signal_new ("user-verified",
236                 GSIGNOND_TYPE_IDENTITY,
237                 G_SIGNAL_RUN_LAST,
238                 0,
239                 NULL,
240                 NULL,
241                 NULL,
242                 G_TYPE_NONE,
243                 2,
244                 G_TYPE_BOOLEAN,
245                 G_TYPE_ERROR);
246
247     signals[SIG_SECRET_VERIFIED] = g_signal_new ("secret-verified",
248                 GSIGNOND_TYPE_IDENTITY,
249                 G_SIGNAL_RUN_LAST,
250                 0,
251                 NULL,
252                 NULL,
253                 NULL,
254                 G_TYPE_NONE,
255                 2,
256                 G_TYPE_BOOLEAN,
257                 G_TYPE_ERROR);
258
259     signals[SIG_CREDENTIALS_UPDATED] = g_signal_new ("credentials-updated",
260                 GSIGNOND_TYPE_IDENTITY,
261                 G_SIGNAL_RUN_LAST,
262                 0,
263                 NULL,
264                 NULL,
265                 NULL,
266                 G_TYPE_NONE,
267                 2,
268                 G_TYPE_UINT,
269                 G_TYPE_ERROR);
270
271     signals[SIG_INFO_UPDATED] = g_signal_new ("info-updated",
272                 GSIGNOND_TYPE_IDENTITY,
273                 G_SIGNAL_RUN_LAST,
274                 0,
275                 NULL,
276                 NULL,
277                 NULL,
278                 G_TYPE_NONE,
279                 1,
280                 GSIGNOND_TYPE_IDENTITY_CHANGE_TYPE);
281
282 }
283
284 GVariant * 
285 gsignond_identity_get_info (GSignondIdentity *identity, const GSignondSecurityContext *ctx, GError **error)
286 {
287     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
288         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
289         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
290         return FALSE;
291     }
292
293     GSignondIdentityInfo *info = NULL;
294     GVariant *vinfo = NULL;
295
296     if (!identity->priv->info) {
297         WARN ("assertion (identity->priv->info) failed");
298         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_ERR, "Identity not found.");
299         return NULL;
300     }
301
302     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, NULL);
303
304     info = gsignond_identity_info_copy (identity->priv->info);
305
306     /* remove password */
307     gsignond_identity_info_remove_secret (info);
308
309     /* remove username if its secret */
310     if (gsignond_identity_info_get_is_username_secret (info))
311         gsignond_identity_info_remove_username (info);
312
313     /* prepare identity info, excluding password and username if secret */
314     vinfo = gsignond_dictionary_to_variant (identity->priv->info);
315     gsignond_identity_info_unref (info);
316     if (!vinfo) {
317         WARN ("identity info to variant convertion failed.");
318         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_ERR, "Identity internal eror.");
319         return NULL;
320     }
321
322     return vinfo;
323 }
324
325 static void
326 _on_dialog_refreshed (GError *error, gpointer user_data)
327 {
328     GSignondIdentityCbData *cb_data = (GSignondIdentityCbData *)user_data;
329
330     g_signal_handlers_disconnect_by_func(cb_data->session, _on_refresh_dialog, user_data);
331     if (error) {
332         WARN ("Error : %s", error->message);
333         g_error_free (error);
334     }
335 }
336
337 static void
338 _on_refresh_dialog (GSignondAuthSession *session, GSignondSignonuiData *ui_data, gpointer userdata)
339 {
340     GSignondIdentityCbData *cb_data = (GSignondIdentityCbData *) userdata;
341
342     if (!gsignond_daemon_refresh_dialog (GSIGNOND_DAEMON (cb_data->identity->priv->owner), 
343             G_OBJECT (cb_data->session), ui_data, _on_dialog_refreshed, userdata)) {
344         WARN ("Dialog Refresh Failed");
345     }
346 }
347
348 static void
349 _on_refresh_requested_by_ui (GSignondSignonuiData *ui_data, gpointer user_data)
350 {
351     GSignondIdentityCbData *cb_data = (GSignondIdentityCbData *) user_data;
352
353     /* check for dialog refresh requests */
354     g_signal_connect (cb_data->session, "process-refreshed", G_CALLBACK (_on_refresh_dialog), cb_data);
355     gsignond_auth_session_refresh (cb_data->session, ui_data);
356 }
357
358 static void
359 _on_user_action_completed (GSignondSignonuiData *reply, GError *error, gpointer user_data)
360 {
361     GSignondIdentityCbData *cb_data = (GSignondIdentityCbData *) user_data;
362     GSignondIdentityPrivate *priv = GSIGNOND_IDENTITY_PRIV (cb_data->identity);
363     GSignondSignonuiError ui_error = SIGNONUI_ERROR_NONE;
364
365     g_return_if_fail (cb_data && GSIGNOND_IS_AUTH_SESSION (cb_data->session));
366
367     g_signal_handlers_disconnect_by_func(cb_data->session, _on_refresh_dialog, user_data);
368     g_signal_handlers_disconnect_by_func(cb_data->session, _on_process_canceled, user_data);
369
370     if (error) {
371         WARN ("UI-Error: %s on identity %d",
372               error->message,
373               gsignond_identity_info_get_id (priv->info));
374         if (cb_data->session) {
375             GSignondSignonuiData *reply = gsignond_dictionary_new();
376             gsignond_signonui_data_set_query_error (reply, SIGNONUI_ERROR_GENERAL);
377             gsignond_auth_session_user_action_finished (cb_data->session, reply);
378             gsignond_dictionary_unref(reply);
379         }
380         g_error_free (error);
381         g_slice_free (GSignondIdentityCbData, cb_data);
382         return;
383     }
384
385     if (gsignond_signonui_data_get_query_error (reply, &ui_error)
386         && ui_error != SIGNONUI_ERROR_NONE) {
387         WARN ("signonui error %d for identity %d",
388               ui_error, gsignond_identity_info_get_id (priv->info));
389     }
390
391     if (!gsignond_identity_info_get_validated (priv->info) &&
392         ui_error == SIGNONUI_ERROR_NONE) {
393         gsignond_identity_info_set_username (priv->info,
394                                              gsignond_signonui_data_get_username (reply));
395     }
396
397     /* storing secret allowed? */
398     if (gsignond_identity_info_get_store_secret (priv->info)) {
399         gboolean remember = TRUE;
400
401         /* and there was no opt-out? */
402         if (!gsignond_signonui_data_get_remember_password (reply, &remember))
403             DBG ("identity %d - don't remember password",
404                  gsignond_identity_info_get_id (priv->info));
405         if (remember && ui_error == SIGNONUI_ERROR_NONE) {
406                 gsignond_identity_info_set_secret (priv->info,
407                                                    gsignond_signonui_data_get_password (reply));
408         } else if (!remember ||
409                    (ui_error == SIGNONUI_ERROR_CANCELED ||
410                     ui_error == SIGNONUI_ERROR_FORGOT_PASSWORD)) {
411             /* reset to empty in case user canceled or forgot,
412              * or doesn't want password to be remebered anymore */
413             gsignond_identity_info_set_secret (priv->info, "");
414         }
415     }
416     /* TODO: auto-set to validated on successful process() cycle */
417     /* store if not a new identity (new is stored later) */
418     if (!gsignond_identity_info_get_is_identity_new (priv->info)) {
419         if (!gsignond_daemon_store_identity (priv->owner, cb_data->identity))
420             WARN ("failed to update identity %d",
421                   gsignond_identity_info_get_id (priv->info));
422     }
423
424     if (cb_data->session) {
425         gsignond_auth_session_user_action_finished (cb_data->session, reply);
426     }
427
428     g_slice_free (GSignondIdentityCbData, cb_data);
429 }
430
431 static void
432 _on_process_canceled (GSignondAuthSession *session, GSignondIdentityCbData *cb_data)
433 {
434     g_signal_handlers_disconnect_by_func(session, G_CALLBACK(_on_process_canceled), cb_data);
435
436     if (!cb_data) {
437         WARN ("assert (cb_data)");
438         return;
439     }
440     if (!gsignond_daemon_cancel_dialog (
441             cb_data->identity->priv->owner, G_OBJECT(session), NULL, NULL)) {
442         WARN ("Fail to cancel dialog");
443     }
444     g_slice_free (GSignondIdentityCbData, cb_data);
445 }
446
447 static void
448 _on_user_action_required (GSignondAuthSession *session, GSignondSignonuiData *ui_data, gpointer userdata)
449 {
450     GSignondIdentity *identity = GSIGNOND_IDENTITY (userdata);
451     GSignondIdentityCbData *cb_data = g_slice_new (GSignondIdentityCbData);
452
453     cb_data->identity = identity;
454     cb_data->session = session;
455
456     gsignond_daemon_show_dialog (GSIGNOND_DAEMON (identity->priv->owner), G_OBJECT(session), 
457             ui_data, _on_user_action_completed, _on_refresh_requested_by_ui, cb_data);
458
459     g_signal_connect (session, "process-canceled", G_CALLBACK(_on_process_canceled), cb_data);
460 }
461
462 static void
463 _on_store_token (GSignondAuthSession *session, GSignondDictionary *token_data, gpointer userdata)
464 {
465     GSignondIdentity *identity = GSIGNOND_IDENTITY (userdata);
466     guint32 identity_id = GSIGNOND_IDENTITY_INFO_NEW_IDENTITY;
467
468     g_return_if_fail (identity && session && GSIGNOND_IS_AUTH_SESSION (session));
469
470     identity_id = gsignond_identity_info_get_id (identity->priv->info);
471
472     if (identity_id != GSIGNOND_IDENTITY_INFO_NEW_IDENTITY) {
473         gsignond_daemon_store_identity_data (identity->priv->owner, identity_id, 
474             gsignond_auth_session_get_method (session), token_data);
475     }
476 }
477
478 static gboolean
479 _compare_session_by_pointer (gpointer key, gpointer value, gpointer dead_object)
480 {
481     return value == dead_object;
482 }
483
484 static void
485 _on_session_dead (gpointer data, GObject *session)
486 {
487     GSignondIdentity *identity = GSIGNOND_IDENTITY (data);
488
489     DBG ("identity %p session %p disposed", identity, session);
490     
491     g_hash_table_foreach_remove (identity->priv->auth_sessions,
492             _compare_session_by_pointer, session);   
493 }
494
495 GSignondAuthSession *
496 gsignond_identity_get_auth_session (GSignondIdentity *identity,
497                                     const gchar *method,
498                                     const GSignondSecurityContext *ctx,
499                                     GError **error)
500 {
501     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
502         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
503         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
504         return FALSE;
505     }
506     GSignondAuthSession *session = NULL;
507     GHashTable *supported_methods = NULL;
508     gboolean method_available = FALSE;
509     guint32 identity_id ;
510     GSignondDictionary *token_data = NULL;
511
512     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, NULL);
513
514     if (!method) {
515         WARN ("assertion (method) failed");
516         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_METHOD_NOT_KNOWN,
517                       "authentication method not provided");
518         return NULL;
519     }
520
521     DBG ("get auth session for method '%s'", method);
522     session = g_hash_table_lookup (identity->priv->auth_sessions, method);
523
524     if (session && GSIGNOND_IS_AUTH_SESSION (session)) {
525         DBG("using cashed auth session '%p' for method '%s'", session, method);
526         return GSIGNOND_AUTH_SESSION(g_object_ref (session));
527     }
528
529     if (!gsignond_plugin_proxy_factory_get_plugin_mechanisms (gsignond_get_plugin_proxy_factory (),
530                                                               method)) {
531         WARN ("method '%s' doesn't exist", method);
532         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_METHOD_NOT_KNOWN,
533                                                         "authentication method '%s' doesn't exist",
534                                                         method);
535         return NULL;
536     }
537
538     supported_methods = gsignond_identity_info_get_methods (identity->priv->info);
539
540     if (supported_methods) {
541         method_available = g_hash_table_contains (supported_methods, method);
542         g_hash_table_unref (supported_methods);
543     } else if (gsignond_identity_info_get_is_identity_new (
544                                                          identity->priv->info))
545         method_available = TRUE;
546     else
547         method_available = FALSE;
548
549
550     if (!method_available) {
551         WARN ("authentication method '%s' is not supported", method);
552         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_METHOD_NOT_AVAILABLE,
553                       "authentication method '%s' not supported for this identity", method);
554         return NULL;
555     }
556
557     if ( (identity_id = gsignond_identity_info_get_id (identity->priv->info)) !=
558             GSIGNOND_IDENTITY_INFO_NEW_IDENTITY) {
559         token_data = gsignond_daemon_load_identity_data (identity->priv->owner, identity_id, method);
560     } 
561     if (!token_data) token_data = gsignond_dictionary_new();
562
563     session = gsignond_auth_session_new (identity->priv->info, method, token_data);
564
565     if (token_data) gsignond_dictionary_unref (token_data);
566
567     if (!session) {
568         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
569         return NULL;
570     }
571
572     /* Handle 'ui' signanls on session */
573     g_signal_connect (session, "process-user-action-required", G_CALLBACK (_on_user_action_required), identity);
574     g_signal_connect (session, "process-store", G_CALLBACK (_on_store_token), identity);
575
576     g_hash_table_insert (identity->priv->auth_sessions, g_strdup (method), session);
577     g_object_weak_ref (G_OBJECT (session), _on_session_dead, identity);
578
579     DBG ("session %p creation for method '%s' complete", session, method);
580
581     return session;
582 }
583
584 static void
585 _on_credentials_updated (GSignondSignonuiData *reply, GError *error, gpointer user_data)
586 {
587     GSignondIdentity *identity = GSIGNOND_IDENTITY (user_data);
588     guint32 id = 0;
589     GError *err = NULL;
590
591     if (error) {
592         WARN ("failed to verify user : %s", error->message);
593         g_error_free (error);
594
595         err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_OPERATION_CANCELED, "Operation canceled");
596     }
597     else
598     {
599         GSignondSignonuiError err_id = SIGNONUI_ERROR_NONE;
600         gboolean res = gsignond_signonui_data_get_query_error (reply, &err_id);
601
602         if (!res) {
603             DBG ("No error code set by UI daemon, treating as ERROR_NONE");
604         }
605
606         if (err_id != SIGNONUI_ERROR_NONE) {
607             switch (err_id) {
608                 case SIGNONUI_ERROR_CANCELED:
609                     err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_OPERATION_CANCELED,
610                         "Operation canceled");
611                     break;
612                 default:
613                     err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_INTERNAL_SERVER, 
614                         "signon ui returned with error : %d", err_id);
615                     break;
616             }
617         }
618         else {
619             const gchar *secret = gsignond_signonui_data_get_password (reply);
620
621             if (!secret) {
622                 err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_INTERNAL_SERVER,
623                                 "Server internal error occured");
624             } else if (identity->priv->info) {
625                 gsignond_identity_info_set_secret (identity->priv->info, secret) ;
626
627                 /* Save new secret in db */
628                 id = gsignond_daemon_store_identity (identity->priv->owner, identity);
629                 if (!id) err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_STORE_FAILED, "Failed to store secret");
630             }
631         }
632     }
633
634     g_signal_emit (identity, signals[SIG_CREDENTIALS_UPDATED], 0 , id, err);
635
636     if (err) g_error_free (err);
637 }
638
639 gboolean
640 gsignond_identity_request_credentials_update (GSignondIdentity *identity,
641                                               const gchar *message,
642                                               const GSignondSecurityContext *ctx,
643                                               GError **error)
644 {
645     GSignondSignonuiData *ui_data = NULL;
646
647     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
648         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
649         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
650         return FALSE;
651     }
652
653     if (!identity->priv->info) {
654         WARN ("assertion (identity->priv->info) failed");
655         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_ERR, "Identity not found.");
656         return FALSE;
657     }
658
659     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, FALSE);
660
661     if (!gsignond_identity_info_get_store_secret (identity->priv->info)) {
662         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_CREDENTIALS_NOT_AVAILABLE, "Password can not be stored.");
663         return FALSE;
664     }
665
666     ui_data = gsignond_dictionary_new ();
667
668     gsignond_signonui_data_set_query_password (ui_data, TRUE);
669     gsignond_signonui_data_set_username (ui_data, gsignond_identity_info_get_username (identity->priv->info));
670     gsignond_signonui_data_set_caption (ui_data, gsignond_identity_info_get_caption (identity->priv->info));
671     gsignond_signonui_data_set_message (ui_data, message);
672   
673     gsignond_daemon_show_dialog (GSIGNOND_DAEMON (identity->priv->owner), G_OBJECT(identity),
674         ui_data, _on_credentials_updated, NULL, identity);
675
676     gsignond_dictionary_unref (ui_data);
677
678     return TRUE;
679 }
680
681 static void
682 _on_user_verified (GSignondSignonuiData *reply, GError *error, gpointer user_data)
683 {
684     GSignondIdentity *identity = GSIGNOND_IDENTITY (user_data);
685     gboolean res = FALSE;
686     GError *err = NULL;
687
688     if (error) {
689         WARN ("failed to verify user : %s", error->message);
690         g_error_free (error);
691
692         err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_OPERATION_CANCELED, "Operation canceled");
693     }
694     else
695     {
696         GSignondSignonuiError err_id = SIGNONUI_ERROR_NONE;
697         gboolean res = gsignond_signonui_data_get_query_error (reply, &err_id);
698         if (!res) {
699             DBG ("No error code set by UI daemon, treating as ERROR_NONE");
700         }
701         if (err_id != SIGNONUI_ERROR_NONE) {
702             switch (err_id) {
703                 case SIGNONUI_ERROR_CANCELED:
704                     err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_OPERATION_CANCELED,
705                         "Operation canceled");
706                     break;
707                 case SIGNONUI_ERROR_FORGOT_PASSWORD:
708                     err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_FORGOT_PASSWORD, "Forgot password");
709                     break;
710                 default:
711                     err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_INTERNAL_SERVER, 
712                         "signon ui returned error : %d", err_id);
713                     break;
714             }
715         }
716         else {
717             const gchar *secret = gsignond_signonui_data_get_password (reply);
718
719             if (!secret) {
720                 err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_INTERNAL_SERVER,
721                                 "Server internal error occured");
722             } else if (identity->priv->info) {
723                 res = g_strcmp0 (secret, gsignond_identity_info_get_secret 
724                                        (identity->priv->info)) == 0;
725             }
726         }
727     }
728
729     g_signal_emit (identity, signals[SIG_USER_VERIFIED], 0, res, err);
730
731     if (err) g_error_free (err);
732 }
733
734 gboolean 
735 gsignond_identity_verify_user (GSignondIdentity *identity,
736                                GVariant *params,
737                                const GSignondSecurityContext *ctx,
738                                GError **error)
739 {
740     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
741         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) == 0) failed");
742         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
743         return FALSE;
744     }
745     const gchar *passwd = 0;
746     GSignondSignonuiData *ui_data = NULL;
747
748     if (!identity->priv->info) {
749         WARN ("assertion (identity->priv->info) failed");
750         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_ERR, "Identity not found.");
751         return FALSE;
752     }
753
754     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, FALSE);
755
756     if (!gsignond_identity_info_get_store_secret (identity->priv->info) ||
757         !(passwd = gsignond_identity_info_get_secret (identity->priv->info)) ||
758         !strlen (passwd)) {
759         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_CREDENTIALS_NOT_AVAILABLE,
760                                                         "user can not be verified as credentials are not stored");
761         return FALSE;
762     }
763
764     ui_data = gsignond_dictionary_new_from_variant (params);
765     gsignond_signonui_data_set_query_password (ui_data, TRUE);
766     gsignond_signonui_data_set_username (ui_data, gsignond_identity_info_get_username (identity->priv->info));
767     gsignond_signonui_data_set_caption (ui_data, gsignond_identity_info_get_caption (identity->priv->info));
768
769     gsignond_daemon_show_dialog (GSIGNOND_DAEMON (identity->priv->owner), G_OBJECT (identity),
770         ui_data, _on_user_verified, NULL, identity);
771
772     gsignond_dictionary_unref (ui_data);
773
774     return TRUE;
775 }
776
777 gboolean
778 gsignond_identity_verify_secret (GSignondIdentity *identity,
779                                  const gchar *secret,
780                                  const GSignondSecurityContext *ctx,
781                                  GError **error)
782 {
783     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
784         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
785         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
786         return FALSE;
787     }
788
789     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, FALSE);
790
791     if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Not supported");
792
793     return FALSE;
794 }
795
796 gboolean
797 gsignond_identity_sign_out (GSignondIdentity *identity,
798                             const GSignondSecurityContext *ctx,
799                             GError **error)
800 {
801     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
802         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
803         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
804         return FALSE;
805     }
806     gboolean success = FALSE;
807     guint32 identity_id = GSIGNOND_IDENTITY_INFO_NEW_IDENTITY;
808
809     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, FALSE);
810
811     identity_id = gsignond_identity_info_get_id (identity->priv->info);
812
813     if (identity_id == GSIGNOND_IDENTITY_INFO_NEW_IDENTITY) {
814         /* TODO; clear the cached secret for unstored identity */
815         success = TRUE;
816     }
817     else {
818         success = gsignond_daemon_clear_identity_data (identity->priv->owner, identity_id);
819     }
820     if(!success) {
821         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Failed to clear data");
822         return FALSE;
823     }
824
825     g_signal_emit (identity, signals[SIG_INFO_UPDATED], 0, GSIGNOND_IDENTITY_SIGNED_OUT, NULL);
826
827     return success;
828 }
829
830 typedef struct _{
831     GSignondDaemon *daemon;
832     guint32 identity_id;
833 }_StoreCachedTokenCbInfo;
834 static void
835 _store_cached_token_data (const gchar *method, GSignondAuthSession *session, _StoreCachedTokenCbInfo *data)
836 {
837     if (!data || !method || !session) return ;
838
839     GSignondDictionary *token_data = gsignond_auth_session_get_token_data (session);
840
841     if (token_data)
842         gsignond_daemon_store_identity_data (data->daemon, data->identity_id, method, token_data);
843 }
844
845 guint32
846 gsignond_identity_store (GSignondIdentity *identity, 
847                          const GVariant *info,
848                          const GSignondSecurityContext *ctx,
849                          GError **error)
850 {
851     GSignondIdentityInfo *identity_info = NULL;
852     gboolean was_new_identity = FALSE;
853     GSignondSecurityContextList *contexts = NULL;
854     GSignondSecurityContext *owner = NULL;
855     guint32 id;
856
857     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
858         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
859         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
860         return 0;
861     }
862     
863     VALIDATE_IDENTITY_WRITE_ACCESS (identity, ctx, 0);
864
865     identity_info = gsignond_dictionary_new_from_variant ((GVariant *)info);
866     /* dont trust 'identity id' passed via 'info' */
867     id = gsignond_identity_info_get_id (identity->priv->info);
868     gsignond_identity_info_set_id (identity_info, id);
869
870     was_new_identity = gsignond_identity_info_get_is_identity_new (identity_info);
871
872     contexts = gsignond_identity_info_get_access_control_list (identity_info);
873     if (!contexts) {
874         contexts = gsignond_identity_info_get_access_control_list (identity->priv->info);
875         gsignond_identity_info_set_access_control_list (identity_info, contexts);
876     }
877     else {
878         VALIDATE_IDENTITY_WRITE_ACL (identity, ctx, 0);
879     }
880     gsignond_security_context_list_free (contexts);
881    
882     owner = gsignond_identity_info_get_owner (identity_info);
883     if (!owner) {
884         owner = gsignond_identity_info_get_owner (identity->priv->info);
885         gsignond_identity_info_set_owner (identity_info, owner);
886     }
887     gsignond_security_context_free (owner);
888
889
890     /* update object cache */
891     if (identity->priv->info)
892         gsignond_identity_info_unref (identity->priv->info);
893     identity->priv->info = identity_info;
894
895     /* Ask daemon to store identity info to db */
896     id = gsignond_daemon_store_identity (identity->priv->owner, identity);
897     if (!id) {
898         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_STORE_FAILED,
899                                                         "Failed to store identity");
900     }
901     else {
902         if (was_new_identity) {
903             _set_id (identity, id);
904             _StoreCachedTokenCbInfo data = { identity->priv->owner, id };
905             /* store any cached token data if available at auth sessions */
906             g_hash_table_foreach (identity->priv->auth_sessions, (GHFunc)_store_cached_token_data, (gpointer)&data);
907         }
908
909         g_signal_emit (identity, signals[SIG_INFO_UPDATED], 0, GSIGNOND_IDENTITY_DATA_UPDATED);
910     }
911  
912     return id;
913 }
914
915 gboolean
916 gsignond_identity_remove (GSignondIdentity *identity, 
917                           const GSignondSecurityContext *ctx,
918                           GError **error)
919 {
920     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
921         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
922         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
923         return FALSE;
924     }
925     gboolean is_removed = FALSE;
926     
927     VALIDATE_IDENTITY_WRITE_ACCESS (identity, ctx, FALSE);
928
929     is_removed = gsignond_identity_clear (identity);
930
931     if (!is_removed && error)
932         *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_REMOVE_FAILED, "failed to remove identity");
933
934     return is_removed;
935 }
936
937
938 gboolean
939 gsignond_identity_clear (GSignondIdentity *identity)
940 {
941     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
942         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
943         return FALSE;
944     }
945     gboolean is_removed = FALSE;
946
947     if (gsignond_identity_info_get_is_identity_new (identity->priv->info))
948         is_removed = TRUE;
949     else
950         is_removed = gsignond_daemon_remove_identity (
951                        identity->priv->owner, 
952                        gsignond_identity_info_get_id (identity->priv->info));
953
954     if (is_removed)
955         g_signal_emit (identity, signals[SIG_INFO_UPDATED], 0, GSIGNOND_IDENTITY_REMOVED);
956     else
957         WARN ("request to remove identity %u failed",
958               gsignond_identity_info_get_id (identity->priv->info));
959
960     return is_removed;
961 }
962
963
964 guint32
965 gsignond_identity_add_reference (GSignondIdentity *identity,
966                                  const gchar *reference,
967                                  const GSignondSecurityContext *ctx,
968                                  GError **error)
969 {
970     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
971         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
972         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
973         return 0;
974     }
975     guint32 res = 0;
976     guint32 identity_id = 0;
977
978     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, 0);
979
980     identity_id = gsignond_identity_info_get_id (identity->priv->info);
981     if (!identity_id) {
982         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_STORE_FAILED, "Cannot add reference to unsaved identity");
983         return 0;
984     }
985     res = gsignond_daemon_add_identity_reference (identity->priv->owner, identity_id, ctx, reference);
986
987     if (res == 0) {
988         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
989     }
990
991     return res;
992 }
993
994 guint32
995 gsignond_identity_remove_reference (GSignondIdentity *identity,
996                                     const gchar *reference,
997                                     const GSignondSecurityContext *ctx,
998                                     GError **error)
999 {
1000     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
1001         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
1002         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
1003         return 0;
1004     }
1005
1006     gboolean res = 0;
1007     guint32 identity_id = 0;
1008
1009     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, 0);
1010
1011     identity_id = gsignond_identity_info_get_id (identity->priv->info);
1012     if (!identity_id) {
1013         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_REFERENCE_NOT_FOUND, "reference not '%s' found", reference);
1014         return 0;
1015     }
1016
1017     res = gsignond_daemon_remove_identity_reference (identity->priv->owner, identity_id, ctx, reference);
1018     if (res == FALSE) {
1019         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_REFERENCE_NOT_FOUND,
1020                                                         "reference '%s' not found", reference);
1021     }
1022     return identity_id;
1023 }
1024
1025 GSignondAccessControlManager *
1026 gsignond_identity_get_acm (GSignondIdentity *identity)
1027 {
1028     g_return_val_if_fail (identity && GSIGNOND_IS_IDENTITY(identity), NULL);
1029
1030     return gsignond_daemon_get_access_control_manager (identity->priv->owner);
1031 }
1032
1033 guint
1034 gsignond_identity_get_auth_session_timeout (GSignondIdentity *identity)
1035 {
1036     g_return_val_if_fail (identity && GSIGNOND_IS_IDENTITY(identity), 0);
1037
1038     return gsignond_daemon_get_auth_session_timeout (identity->priv->owner);
1039 }
1040
1041 /**
1042  * gsignond_identity_get_id:
1043  * @identity: instance of #GSignondIdentity
1044  * 
1045  * Retrieves identity id.
1046  *
1047  * Returns: identity id
1048  */
1049 guint32 
1050 gsignond_identity_get_id (GSignondIdentity *identity)
1051 {
1052     g_assert (GSIGNOND_IS_IDENTITY (identity));
1053
1054     return gsignond_identity_info_get_id (identity->priv->info);
1055 }
1056
1057 /**
1058  * gsignond_identity_get_identity_info:
1059  * @identity: instance of #GSignondIdentity
1060  *
1061  * Retrieves identity's #GSignondIdentityInfo.
1062  *
1063  * Returns: (transfer none) #GSignondIdentityInfo
1064  */
1065 GSignondIdentityInfo *
1066 gsignond_identity_get_identity_info (GSignondIdentity *identity)
1067 {
1068     g_assert (GSIGNOND_IS_IDENTITY (identity));
1069     g_assert (identity->priv != NULL);
1070
1071     return identity->priv->info;
1072 }
1073
1074 /**
1075  * gsignond_identity_new:
1076  * @owner: Owner of this object, instance of #GSignondAuthServiceIface
1077  * @info (transfer full): Identity info, instance of #GSignondIdentityInfo
1078  * 
1079  * Creates new instance of #GSignondIdentity
1080  *
1081  * Returns[transfer full]: new instance of #GSignondIdentity
1082  */
1083 GSignondIdentity * gsignond_identity_new (GSignondDaemon *owner,
1084                                           GSignondIdentityInfo *info)
1085 {
1086     GSignondIdentity *identity =
1087         GSIGNOND_IDENTITY(g_object_new (GSIGNOND_TYPE_IDENTITY,
1088                                         "info", info,
1089                                         NULL));
1090
1091     identity->priv->owner = g_object_ref (owner);
1092
1093     return identity;
1094 }