bf7f30f9172f4614444040c83d56de757de47b8e
[platform/upstream/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 "gsignond/gsignond-signonui.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_close (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     GSignondIdentityInfo *info = NULL;
295     GVariant *vinfo = NULL;
296
297     if (!identity->priv->info) {
298         WARN ("assertion (identity->priv->info) failed");
299         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_ERR, "Identity not found.");
300         return NULL;
301     }
302
303     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, NULL);
304
305     info = gsignond_identity_info_copy (identity->priv->info);
306
307     /* remove password */
308     gsignond_identity_info_remove_secret (info);
309
310     /* remove username if its secret */
311     if (gsignond_identity_info_get_is_username_secret (info))
312         gsignond_identity_info_remove_username (info);
313
314     /* prepare identity info, excluding password and username if secret */
315     vinfo = gsignond_dictionary_to_variant (identity->priv->info);
316     gsignond_identity_info_unref (info);
317     if (!vinfo) {
318         WARN ("identity info to variant convertion failed.");
319         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_ERR, "Identity internal eror.");
320         return NULL;
321     }
322
323     return vinfo;
324 }
325
326 static void
327 _on_dialog_refreshed (GError *error, gpointer user_data)
328 {
329     GSignondIdentityCbData *cb_data = (GSignondIdentityCbData *)user_data;
330
331     g_signal_handlers_disconnect_by_func(cb_data->session, _on_refresh_dialog, user_data);
332     if (error) {
333         WARN ("Error : %s", error->message);
334         g_error_free (error);
335     }
336 }
337
338 static void
339 _on_refresh_dialog (GSignondAuthSession *session, GSignondSignonuiData *ui_data, gpointer userdata)
340 {
341     GSignondIdentityCbData *cb_data = (GSignondIdentityCbData *) userdata;
342
343     if (!gsignond_daemon_refresh_dialog (GSIGNOND_DAEMON (cb_data->identity->priv->owner), 
344             G_OBJECT (cb_data->session), ui_data, _on_dialog_refreshed, userdata)) {
345         WARN ("Dialog Refresh Failed");
346     }
347 }
348
349 static void
350 _on_refresh_requested_by_ui (GSignondSignonuiData *ui_data, gpointer user_data)
351 {
352     GSignondIdentityCbData *cb_data = (GSignondIdentityCbData *) user_data;
353
354     /* check for dialog refresh requests */
355     g_signal_connect (cb_data->session, "process-refreshed", G_CALLBACK (_on_refresh_dialog), cb_data);
356     gsignond_auth_session_refresh (cb_data->session, ui_data);
357 }
358
359 static void
360 _on_user_action_completed (GSignondSignonuiData *reply, GError *error, gpointer user_data)
361 {
362     GSignondIdentityCbData *cb_data = (GSignondIdentityCbData *) user_data;
363     GSignondIdentityPrivate *priv = GSIGNOND_IDENTITY_PRIV (cb_data->identity);
364     GSignondSignonuiError ui_error = SIGNONUI_ERROR_NONE;
365
366     g_return_if_fail (cb_data && GSIGNOND_IS_AUTH_SESSION (cb_data->session));
367
368     g_signal_handlers_disconnect_by_func(cb_data->session, _on_refresh_dialog, user_data);
369     g_signal_handlers_disconnect_by_func(cb_data->session, _on_process_canceled, user_data);
370
371     if (error) {
372         WARN ("UI-Error: %s on identity %d",
373               error->message,
374               gsignond_identity_info_get_id (priv->info));
375         if (cb_data->session) {
376             GSignondSignonuiData *reply = gsignond_signonui_data_new();
377             gsignond_signonui_data_set_query_error (reply, SIGNONUI_ERROR_GENERAL);
378             gsignond_auth_session_user_action_finished (cb_data->session, reply);
379             gsignond_signonui_data_unref(reply);
380         }
381         g_error_free (error);
382         g_slice_free (GSignondIdentityCbData, cb_data);
383         return;
384     }
385
386     if (gsignond_signonui_data_get_query_error (reply, &ui_error)
387         && ui_error != SIGNONUI_ERROR_NONE) {
388         WARN ("signonui error %d for identity %d",
389               ui_error, gsignond_identity_info_get_id (priv->info));
390     }
391
392     if (!gsignond_identity_info_get_validated (priv->info) &&
393         ui_error == SIGNONUI_ERROR_NONE) {
394         gsignond_identity_info_set_username (priv->info,
395                                              gsignond_signonui_data_get_username (reply));
396     }
397
398     /* storing secret allowed? */
399     if (gsignond_identity_info_get_store_secret (priv->info)) {
400         gboolean remember = TRUE;
401
402         /* and there was no opt-out? */
403         if (!gsignond_signonui_data_get_remember_password (reply, &remember))
404             DBG ("identity %d - don't remember password",
405                  gsignond_identity_info_get_id (priv->info));
406         if (remember && ui_error == SIGNONUI_ERROR_NONE) {
407                 gsignond_identity_info_set_secret (priv->info,
408                                                    gsignond_signonui_data_get_password (reply));
409         } else if (!remember ||
410                    (ui_error == SIGNONUI_ERROR_CANCELED ||
411                     ui_error == SIGNONUI_ERROR_FORGOT_PASSWORD)) {
412             /* reset to empty in case user canceled or forgot,
413              * or doesn't want password to be remebered anymore */
414             gsignond_identity_info_set_secret (priv->info, "");
415         }
416     }
417     /* TODO: auto-set to validated on successful process() cycle */
418     /* store if not a new identity (new is stored later) */
419     if (!gsignond_identity_info_get_is_identity_new (priv->info)) {
420         if (!gsignond_daemon_store_identity (priv->owner, cb_data->identity))
421             WARN ("failed to update identity %d",
422                   gsignond_identity_info_get_id (priv->info));
423     }
424
425     if (cb_data->session) {
426         gsignond_auth_session_user_action_finished (cb_data->session, reply);
427     }
428
429     g_slice_free (GSignondIdentityCbData, cb_data);
430 }
431
432 static void
433 _on_process_canceled (GSignondAuthSession *session, GSignondIdentityCbData *cb_data)
434 {
435     g_signal_handlers_disconnect_by_func(session, G_CALLBACK(_on_process_canceled), cb_data);
436
437     if (!cb_data) {
438         WARN ("assert (cb_data)");
439         return;
440     }
441     if (!gsignond_daemon_cancel_dialog (
442             cb_data->identity->priv->owner, G_OBJECT(session), NULL, NULL)) {
443         WARN ("Fail to cancel dialog");
444     }
445     g_slice_free (GSignondIdentityCbData, cb_data);
446 }
447
448 static void
449 _on_user_action_required (GSignondAuthSession *session, GSignondSignonuiData *ui_data, gpointer userdata)
450 {
451     GSignondIdentity *identity = GSIGNOND_IDENTITY (userdata);
452     GSignondIdentityCbData *cb_data = g_slice_new (GSignondIdentityCbData);
453
454     cb_data->identity = identity;
455     cb_data->session = session;
456
457     gsignond_daemon_show_dialog (GSIGNOND_DAEMON (identity->priv->owner), G_OBJECT(session), 
458             ui_data, _on_user_action_completed, _on_refresh_requested_by_ui, cb_data);
459
460     g_signal_connect (session, "process-canceled", G_CALLBACK(_on_process_canceled), cb_data);
461 }
462
463 static void
464 _on_store_token (GSignondAuthSession *session, GSignondDictionary *token_data, gpointer userdata)
465 {
466     GSignondIdentity *identity = GSIGNOND_IDENTITY (userdata);
467     guint32 identity_id = GSIGNOND_IDENTITY_INFO_NEW_IDENTITY;
468
469     g_return_if_fail (identity && session && GSIGNOND_IS_AUTH_SESSION (session));
470
471     identity_id = gsignond_identity_info_get_id (identity->priv->info);
472
473     if (identity_id != GSIGNOND_IDENTITY_INFO_NEW_IDENTITY) {
474         gsignond_daemon_store_identity_data (identity->priv->owner, identity_id, 
475             gsignond_auth_session_get_method (session), token_data);
476     }
477 }
478
479 static gboolean
480 _compare_session_by_pointer (gpointer key, gpointer value, gpointer dead_object)
481 {
482     return value == dead_object;
483 }
484
485 static void
486 _on_session_close (gpointer data, GObject *session)
487 {
488     GSignondIdentity *identity = GSIGNOND_IDENTITY (data);
489
490     DBG ("identity %p session %p disposed", identity, session);
491     
492     g_hash_table_foreach_remove (identity->priv->auth_sessions,
493             _compare_session_by_pointer, session);   
494 }
495
496 GSignondAuthSession *
497 gsignond_identity_get_auth_session (GSignondIdentity *identity,
498                                     const gchar *method,
499                                     const GSignondSecurityContext *ctx,
500                                     GError **error)
501 {
502     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
503         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
504         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
505         return FALSE;
506     }
507     GSignondAuthSession *session = NULL;
508     GHashTable *supported_methods = NULL;
509     gboolean method_available = FALSE;
510     guint32 identity_id ;
511     GSignondDictionary *token_data = NULL;
512
513     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, NULL);
514
515     if (!method) {
516         WARN ("assertion (method) failed");
517         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_METHOD_NOT_KNOWN,
518                       "authentication method not provided");
519         return NULL;
520     }
521
522     DBG ("get auth session for method '%s'", method);
523     session = g_hash_table_lookup (identity->priv->auth_sessions, method);
524
525     if (session && GSIGNOND_IS_AUTH_SESSION (session)) {
526         DBG("using cashed auth session '%p' for method '%s'", session, method);
527         return GSIGNOND_AUTH_SESSION(g_object_ref (session));
528     }
529
530     if (!gsignond_plugin_proxy_factory_get_plugin_mechanisms (gsignond_get_plugin_proxy_factory (),
531                                                               method)) {
532         WARN ("method '%s' doesn't exist", method);
533         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_METHOD_NOT_KNOWN,
534                                                         "authentication method '%s' doesn't exist",
535                                                         method);
536         return NULL;
537     }
538
539     supported_methods = gsignond_identity_info_get_methods (identity->priv->info);
540
541     if (supported_methods) {
542         method_available = g_hash_table_contains (supported_methods, method);
543         g_hash_table_unref (supported_methods);
544     } else if (gsignond_identity_info_get_is_identity_new (
545                                                          identity->priv->info))
546         method_available = TRUE;
547     else
548         method_available = FALSE;
549
550
551     if (!method_available) {
552         WARN ("authentication method '%s' is not supported", method);
553         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_METHOD_NOT_AVAILABLE,
554                       "authentication method '%s' not supported for this identity", method);
555         return NULL;
556     }
557
558     if ( (identity_id = gsignond_identity_info_get_id (identity->priv->info)) !=
559             GSIGNOND_IDENTITY_INFO_NEW_IDENTITY) {
560         token_data = gsignond_daemon_load_identity_data (identity->priv->owner, identity_id, method);
561     } 
562     if (!token_data) token_data = gsignond_dictionary_new();
563
564     session = gsignond_auth_session_new (identity->priv->info, method, token_data);
565
566     if (token_data) gsignond_dictionary_unref (token_data);
567
568     if (!session) {
569         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
570         return NULL;
571     }
572
573     /* Handle 'ui' signanls on session */
574     g_signal_connect (session, "process-user-action-required", G_CALLBACK (_on_user_action_required), identity);
575     g_signal_connect (session, "process-store", G_CALLBACK (_on_store_token), identity);
576
577     g_hash_table_insert (identity->priv->auth_sessions, g_strdup (method), session);
578     g_object_weak_ref (G_OBJECT (session), _on_session_close, identity);
579
580     DBG ("session %p creation for method '%s' complete", session, method);
581
582     return session;
583 }
584
585 static void
586 _on_credentials_updated (GSignondSignonuiData *reply, GError *error, gpointer user_data)
587 {
588     GSignondIdentity *identity = GSIGNOND_IDENTITY (user_data);
589     guint32 id = 0;
590     GError *err = NULL;
591
592     if (error) {
593         WARN ("failed to verify user : %s", error->message);
594         g_error_free (error);
595
596         err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_OPERATION_CANCELED, "Operation cancled");
597     }
598     else
599     {
600         GSignondSignonuiError err_id = SIGNONUI_ERROR_NONE;
601         gboolean res = gsignond_signonui_data_get_query_error (reply, &err_id);
602
603         if (!res) {
604             DBG ("No error code set by UI daemon, treating as ERROR_NONE");
605         }
606
607         if (err_id != SIGNONUI_ERROR_NONE) {
608             switch (err_id) {
609                 case SIGNONUI_ERROR_CANCELED:
610                     err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_OPERATION_CANCELED,
611                         "Operation cancled");
612                     break;
613                 default:
614                     err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_INTERNAL_SERVER, 
615                         "signon ui returned with error : %d", err_id);
616                     break;
617             }
618         }
619         else {
620             const gchar *secret = gsignond_signonui_data_get_password (reply);
621
622             if (!secret) {
623                 err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_INTERNAL_SERVER,
624                                 "Server internal error occured");
625             } else if (identity->priv->info) {
626                 gsignond_identity_info_set_secret (identity->priv->info, secret) ;
627
628                 /* Save new secret in db */
629                 id = gsignond_daemon_store_identity (identity->priv->owner, identity);
630                 if (!id) err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_STORE_FAILED, "Failed to store secret");
631             }
632         }
633     }
634
635     g_signal_emit (identity, signals[SIG_CREDENTIALS_UPDATED], 0 , id, err);
636
637     if (err) g_error_free (err);
638 }
639
640 gboolean
641 gsignond_identity_request_credentials_update (GSignondIdentity *identity,
642                                               const gchar *message,
643                                               const GSignondSecurityContext *ctx,
644                                               GError **error)
645 {
646     GSignondSignonuiData *ui_data = NULL;
647
648     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
649         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
650         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
651         return FALSE;
652     }
653
654     if (!identity->priv->info) {
655         WARN ("assertion (identity->priv->info) failed");
656         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_ERR, "Identity not found.");
657         return FALSE;
658     }
659
660     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, FALSE);
661
662     if (!gsignond_identity_info_get_store_secret (identity->priv->info)) {
663         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_CREDENTIALS_NOT_AVAILABLE, "Password can not be stored.");
664         return FALSE;
665     }
666
667     ui_data = gsignond_signonui_data_new ();
668
669     gsignond_signonui_data_set_query_password (ui_data, TRUE);
670     gsignond_signonui_data_set_username (ui_data, gsignond_identity_info_get_username (identity->priv->info));
671     gsignond_signonui_data_set_caption (ui_data, gsignond_identity_info_get_caption (identity->priv->info));
672     gsignond_signonui_data_set_message (ui_data, message);
673   
674     gsignond_daemon_show_dialog (GSIGNOND_DAEMON (identity->priv->owner), G_OBJECT(identity),
675         ui_data, _on_credentials_updated, NULL, identity);
676
677     gsignond_signonui_data_unref (ui_data);
678
679     return TRUE;
680 }
681
682 static void
683 _on_user_verified (GSignondSignonuiData *reply, GError *error, gpointer user_data)
684 {
685     GSignondIdentity *identity = GSIGNOND_IDENTITY (user_data);
686     gboolean res = FALSE;
687     GError *err = NULL;
688
689     if (error) {
690         WARN ("failed to verify user : %s", error->message);
691         g_error_free (error);
692
693         err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_OPERATION_CANCELED, "Operation cancled");
694     }
695     else
696     {
697         GSignondSignonuiError err_id = SIGNONUI_ERROR_NONE;
698         gboolean res = gsignond_signonui_data_get_query_error (reply, &err_id);
699         if (!res) {
700             DBG ("No error code set by UI daemon, treating as ERROR_NONE");
701         }
702         if (err_id != SIGNONUI_ERROR_NONE) {
703             switch (err_id) {
704                 case SIGNONUI_ERROR_CANCELED:
705                     err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_OPERATION_CANCELED,
706                         "Operation cancled");
707                     break;
708                 case SIGNONUI_ERROR_FORGOT_PASSWORD:
709                     err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_FORGOT_PASSWORD, "Forgot password");
710                     break;
711                 default:
712                     err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_INTERNAL_SERVER, 
713                         "signon ui returned error : %d", err_id);
714                     break;
715             }
716         }
717         else {
718             const gchar *secret = gsignond_signonui_data_get_password (reply);
719
720             if (!secret) {
721                 err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_INTERNAL_SERVER,
722                                 "Server internal error occured");
723             } else if (identity->priv->info) {
724                 res = g_strcmp0 (secret, gsignond_identity_info_get_secret 
725                                        (identity->priv->info)) == 0;
726             }
727         }
728     }
729
730     g_signal_emit (identity, signals[SIG_USER_VERIFIED], 0, res, err);
731
732     if (err) g_error_free (err);
733 }
734
735 gboolean 
736 gsignond_identity_verify_user (GSignondIdentity *identity,
737                                GVariant *params,
738                                const GSignondSecurityContext *ctx,
739                                GError **error)
740 {
741     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
742         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) == 0) failed");
743         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
744         return FALSE;
745     }
746     const gchar *passwd = 0;
747     GSignondSignonuiData *ui_data = NULL;
748
749     if (!identity->priv->info) {
750         WARN ("assertion (identity->priv->info) failed");
751         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_ERR, "Identity not found.");
752         return FALSE;
753     }
754
755     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, FALSE);
756
757     if (!gsignond_identity_info_get_store_secret (identity->priv->info) ||
758         !(passwd = gsignond_identity_info_get_secret (identity->priv->info)) ||
759         !strlen (passwd)) {
760         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_CREDENTIALS_NOT_AVAILABLE,
761                                                         "user can not be verified as credentials are not stored");
762         return FALSE;
763     }
764
765     ui_data = gsignond_signonui_data_new_from_variant (params);
766     gsignond_signonui_data_set_query_password (ui_data, TRUE);
767     gsignond_signonui_data_set_username (ui_data, gsignond_identity_info_get_username (identity->priv->info));
768     gsignond_signonui_data_set_caption (ui_data, gsignond_identity_info_get_caption (identity->priv->info));
769
770     gsignond_daemon_show_dialog (GSIGNOND_DAEMON (identity->priv->owner), G_OBJECT (identity),
771         ui_data, _on_user_verified, NULL, identity);
772
773     gsignond_signonui_data_unref (ui_data);
774
775     return TRUE;
776 }
777
778 gboolean
779 gsignond_identity_verify_secret (GSignondIdentity *identity,
780                                  const gchar *secret,
781                                  const GSignondSecurityContext *ctx,
782                                  GError **error)
783 {
784     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
785         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
786         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
787         return FALSE;
788     }
789
790     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, FALSE);
791
792     if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Not supported");
793
794     return FALSE;
795 }
796
797 gboolean
798 gsignond_identity_sign_out (GSignondIdentity *identity,
799                             const GSignondSecurityContext *ctx,
800                             GError **error)
801 {
802     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
803         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
804         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
805         return FALSE;
806     }
807     gboolean success = FALSE;
808     guint32 identity_id = GSIGNOND_IDENTITY_INFO_NEW_IDENTITY;
809
810     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, FALSE);
811
812     identity_id = gsignond_identity_info_get_id (identity->priv->info);
813
814     if (identity_id == GSIGNOND_IDENTITY_INFO_NEW_IDENTITY) {
815         /* TODO; clear the cached secret for unstored identity */
816         success = TRUE;
817     }
818     else {
819         success = gsignond_daemon_clear_identity_data (identity->priv->owner, identity_id);
820     }
821     if(!success) {
822         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Failed to clear data");
823         return FALSE;
824     }
825
826     g_signal_emit (identity, signals[SIG_INFO_UPDATED], 0, GSIGNOND_IDENTITY_SIGNED_OUT, NULL);
827
828     return success;
829 }
830
831 typedef struct _{
832     GSignondDaemon *daemon;
833     guint32 identity_id;
834 }_StoreCachedTokenCbInfo;
835 static void
836 _store_cached_token_data (const gchar *method, GSignondAuthSession *session, _StoreCachedTokenCbInfo *data)
837 {
838     if (!data || !method || !session) return ;
839
840     GSignondDictionary *token_data = gsignond_auth_session_get_token_data (session);
841
842     if (token_data)
843         gsignond_daemon_store_identity_data (data->daemon, data->identity_id, method, token_data);
844 }
845
846 guint32
847 gsignond_identity_store (GSignondIdentity *identity, 
848                          const GVariant *info,
849                          const GSignondSecurityContext *ctx,
850                          GError **error)
851 {
852     GSignondIdentityInfo *identity_info = NULL;
853     gboolean was_new_identity = FALSE;
854     GSignondSecurityContextList *contexts = NULL;
855     GSignondSecurityContext *owner = NULL;
856     guint32 id;
857
858     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
859         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
860         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
861         return 0;
862     }
863     
864     VALIDATE_IDENTITY_WRITE_ACCESS (identity, ctx, 0);
865
866     identity_info = gsignond_dictionary_new_from_variant ((GVariant *)info);
867     /* dont trust 'identity id' passed via 'info' */
868     id = gsignond_identity_info_get_id (identity->priv->info);
869     gsignond_identity_info_set_id (identity_info, id);
870
871     was_new_identity = gsignond_identity_info_get_is_identity_new (identity_info);
872
873     contexts = gsignond_identity_info_get_access_control_list (identity_info);
874     if (!contexts) {
875         contexts = gsignond_identity_info_get_access_control_list (identity->priv->info);
876         gsignond_identity_info_set_access_control_list (identity_info, contexts);
877     }
878     else {
879         VALIDATE_IDENTITY_WRITE_ACL (identity, ctx, 0);
880     }
881     gsignond_security_context_list_free (contexts);
882    
883     owner = gsignond_identity_info_get_owner (identity_info);
884     if (!owner) {
885         owner = gsignond_identity_info_get_owner (identity->priv->info);
886         gsignond_identity_info_set_owner (identity_info, owner);
887     }
888     gsignond_security_context_free (owner);
889
890
891     /* update object cache */
892     if (identity->priv->info)
893         gsignond_identity_info_unref (identity->priv->info);
894     identity->priv->info = identity_info;
895
896     /* Ask daemon to store identity info to db */
897     id = gsignond_daemon_store_identity (identity->priv->owner, identity);
898     if (!id) {
899         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_STORE_FAILED,
900                                                         "Failed to store identity");
901     }
902     else {
903         if (was_new_identity) {
904             _set_id (identity, id);
905             _StoreCachedTokenCbInfo data = { identity->priv->owner, id };
906             /* store any cached token data if available at auth sessions */
907             g_hash_table_foreach (identity->priv->auth_sessions, (GHFunc)_store_cached_token_data, (gpointer)&data);
908         }
909
910         g_signal_emit (identity, signals[SIG_INFO_UPDATED], 0, GSIGNOND_IDENTITY_DATA_UPDATED);
911     }
912  
913     return id;
914 }
915
916 gboolean
917 gsignond_identity_remove (GSignondIdentity *identity, 
918                           const GSignondSecurityContext *ctx,
919                           GError **error)
920 {
921     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
922         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
923         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
924         return FALSE;
925     }
926     gboolean is_removed = FALSE;
927     
928     VALIDATE_IDENTITY_WRITE_ACCESS (identity, ctx, FALSE);
929
930     is_removed = gsignond_identity_clear (identity);
931
932     if (!is_removed && error)
933         *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_REMOVE_FAILED, "failed to remove identity");
934
935     return is_removed;
936 }
937
938
939 gboolean
940 gsignond_identity_clear (GSignondIdentity *identity)
941 {
942     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
943         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
944         return FALSE;
945     }
946     gboolean is_removed = FALSE;
947
948     if (gsignond_identity_info_get_is_identity_new (identity->priv->info))
949         is_removed = TRUE;
950     else
951         is_removed = gsignond_daemon_remove_identity (
952                        identity->priv->owner, 
953                        gsignond_identity_info_get_id (identity->priv->info));
954
955     if (is_removed)
956         g_signal_emit (identity, signals[SIG_INFO_UPDATED], 0, GSIGNOND_IDENTITY_REMOVED);
957     else
958         WARN ("request to remove identity %u failed",
959               gsignond_identity_info_get_id (identity->priv->info));
960
961     return is_removed;
962 }
963
964
965 guint32
966 gsignond_identity_add_reference (GSignondIdentity *identity,
967                                  const gchar *reference,
968                                  const GSignondSecurityContext *ctx,
969                                  GError **error)
970 {
971     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
972         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
973         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
974         return 0;
975     }
976     guint32 res = 0;
977     guint32 identity_id = 0;
978
979     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, 0);
980
981     identity_id = gsignond_identity_info_get_id (identity->priv->info);
982     if (!identity_id) {
983         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_STORE_FAILED, "Cannot add reference to unsaved identity");
984         return 0;
985     }
986     res = gsignond_daemon_add_identity_reference (identity->priv->owner, identity_id, ctx, reference);
987
988     if (res == 0) {
989         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
990     }
991
992     return res;
993 }
994
995 guint32
996 gsignond_identity_remove_reference (GSignondIdentity *identity,
997                                     const gchar *reference,
998                                     const GSignondSecurityContext *ctx,
999                                     GError **error)
1000 {
1001     if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
1002         WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
1003         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
1004         return 0;
1005     }
1006
1007     gboolean res = 0;
1008     guint32 identity_id = 0;
1009
1010     VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, 0);
1011
1012     identity_id = gsignond_identity_info_get_id (identity->priv->info);
1013     if (!identity_id) {
1014         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_REFERENCE_NOT_FOUND, "reference not '%s' found", reference);
1015         return 0;
1016     }
1017
1018     res = gsignond_daemon_remove_identity_reference (identity->priv->owner, identity_id, ctx, reference);
1019     if (res == FALSE) {
1020         if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_REFERENCE_NOT_FOUND,
1021                                                         "reference '%s' not found", reference);
1022     }
1023     return identity_id;
1024 }
1025
1026 GSignondAccessControlManager *
1027 gsignond_identity_get_acm (GSignondIdentity *identity)
1028 {
1029     g_return_val_if_fail (identity && GSIGNOND_IS_IDENTITY(identity), NULL);
1030
1031     return gsignond_daemon_get_access_control_manager (identity->priv->owner);
1032 }
1033
1034 guint
1035 gsignond_identity_get_auth_session_timeout (GSignondIdentity *identity)
1036 {
1037     g_return_val_if_fail (identity && GSIGNOND_IS_IDENTITY(identity), 0);
1038
1039     return gsignond_daemon_get_auth_session_timeout (identity->priv->owner);
1040 }
1041
1042 /**
1043  * gsignond_identity_get_id:
1044  * @identity: instance of #GSignondIdentity
1045  * 
1046  * Retrieves identity id.
1047  *
1048  * Returns: identity id
1049  */
1050 guint32 
1051 gsignond_identity_get_id (GSignondIdentity *identity)
1052 {
1053     g_assert (GSIGNOND_IS_IDENTITY (identity));
1054
1055     return gsignond_identity_info_get_id (identity->priv->info);
1056 }
1057
1058 /**
1059  * gsignond_identity_get_identity_info:
1060  * @identity: instance of #GSignondIdentity
1061  *
1062  * Retrieves identity's #GSignondIdentityInfo.
1063  *
1064  * Returns: (transfer none) #GSignondIdentityInfo
1065  */
1066 GSignondIdentityInfo *
1067 gsignond_identity_get_identity_info (GSignondIdentity *identity)
1068 {
1069     g_assert (GSIGNOND_IS_IDENTITY (identity));
1070     g_assert (identity->priv != NULL);
1071
1072     return identity->priv->info;
1073 }
1074
1075 /**
1076  * gsignond_identity_new:
1077  * @owner: Owner of this object, instance of #GSignondAuthServiceIface
1078  * @info (transfer full): Identity info, instance of #GSignondIdentityInfo
1079  * 
1080  * Creates new instance of #GSignondIdentity
1081  *
1082  * Returns[transfer full]: new instance of #GSignondIdentity
1083  */
1084 GSignondIdentity * gsignond_identity_new (GSignondDaemon *owner,
1085                                           GSignondIdentityInfo *info)
1086 {
1087     GSignondIdentity *identity =
1088         GSIGNOND_IDENTITY(g_object_new (GSIGNOND_TYPE_IDENTITY,
1089                                         "info", info,
1090                                         NULL));
1091
1092     identity->priv->owner = g_object_ref (owner);
1093
1094     return identity;
1095 }