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