1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4 * This file is part of gsignond
6 * Copyright (C) 2012 Intel Corporation.
8 * Contact: Jussi Laako <jussi.laako@linux.intel.com>
9 Amarnath Valluri <amarnath.valluri@linux.intel.com>
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.
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.
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
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"
50 SIG_CREDENTIALS_UPDATED,
56 static GParamSpec *properties[N_PROPERTIES];
57 static guint signals[SIG_MAX];
59 struct _GSignondIdentityPrivate
61 GSignondIdentityInfo *info;
62 GSignondDaemon *owner;
63 GHashTable *auth_sessions; // (auth_method,auth_session) table
66 typedef struct _GSignondIdentityCbData
68 GSignondIdentity *identity;
69 GSignondAuthSession *session;
70 } GSignondIdentityCbData;
72 G_DEFINE_TYPE (GSignondIdentity, gsignond_identity, G_TYPE_OBJECT);
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);
81 #define GSIGNOND_IDENTITY_PRIV(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), GSIGNOND_TYPE_IDENTITY, GSignondIdentityPrivate)
83 #define VALIDATE_IDENTITY_READ_ACCESS(identity, ctx, ret) \
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); \
92 WARN ("cannot access identity."); \
93 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_PERMISSION_DENIED, "identity can not be accessed"); \
98 #define VALIDATE_IDENTITY_WRITE_ACCESS(identity, ctx, ret) \
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); \
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"); \
111 #define VALIDATE_IDENTITY_WRITE_ACL(identity, ctx, ret) \
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); \
118 WARN ("acl validity check failed."); \
119 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_PERMISSION_DENIED, "invalid access control list"); \
125 _set_id (GSignondIdentity *identity, guint32 id)
127 gsignond_identity_info_set_id (identity->priv->info, id);
128 g_object_notify_by_pspec (G_OBJECT(identity), properties[PROP_INFO]);
134 _get_property (GObject *object, guint property_id, GValue *value,
137 GSignondIdentity *self = GSIGNOND_IDENTITY (object);
142 g_value_set_boxed (value, self->priv->info);
145 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
150 _set_property (GObject *object, guint property_id, const GValue *value,
153 GSignondIdentity *self = GSIGNOND_IDENTITY (object);
159 (GSignondIdentityInfo *)g_value_get_boxed (value);
162 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
167 _release_weak_ref_on_session (gpointer key, gpointer value, gpointer data)
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);
176 _dispose (GObject *object)
178 GSignondIdentity *self = GSIGNOND_IDENTITY(object);
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;
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;
192 if (self->priv->info) {
193 gsignond_identity_info_unref (self->priv->info);
194 self->priv->info = NULL;
197 G_OBJECT_CLASS (gsignond_identity_parent_class)->dispose (object);
201 _finalize (GObject *object)
203 G_OBJECT_CLASS (gsignond_identity_parent_class)->finalize (object);
207 gsignond_identity_init (GSignondIdentity *self)
209 self->priv = GSIGNOND_IDENTITY_PRIV(self);
211 self->priv->auth_sessions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
215 gsignond_identity_class_init (GSignondIdentityClass *klass)
217 GObjectClass* object_class = G_OBJECT_CLASS (klass);
219 g_type_class_add_private (object_class, sizeof (GSignondIdentityPrivate));
221 object_class->get_property = _get_property;
222 object_class->set_property = _set_property;
223 object_class->dispose = _dispose;
224 object_class->finalize = _finalize;
226 properties[PROP_INFO] =
227 g_param_spec_boxed ("info",
229 "IdentityInfo structure",
230 GSIGNOND_TYPE_IDENTITY_INFO,
231 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
232 G_PARAM_STATIC_STRINGS);
234 g_object_class_install_properties (object_class, N_PROPERTIES, properties);
236 signals[SIG_USER_VERIFIED] = g_signal_new ("user-verified",
237 GSIGNOND_TYPE_IDENTITY,
248 signals[SIG_SECRET_VERIFIED] = g_signal_new ("secret-verified",
249 GSIGNOND_TYPE_IDENTITY,
260 signals[SIG_CREDENTIALS_UPDATED] = g_signal_new ("credentials-updated",
261 GSIGNOND_TYPE_IDENTITY,
272 signals[SIG_INFO_UPDATED] = g_signal_new ("info-updated",
273 GSIGNOND_TYPE_IDENTITY,
281 GSIGNOND_TYPE_IDENTITY_CHANGE_TYPE);
286 gsignond_identity_get_info (GSignondIdentity *identity, const GSignondSecurityContext *ctx, GError **error)
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");
294 GVariant *vinfo = NULL;
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.");
302 VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, NULL);
304 /* prepare identity info, excluding password and username if secret */
305 vinfo = gsignond_identity_info_to_variant (identity->priv->info);
307 WARN ("identity info to variant convertion failed.");
308 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_ERR, "Identity internal eror.");
316 _on_dialog_refreshed (GError *error, gpointer user_data)
318 GSignondIdentityCbData *cb_data = (GSignondIdentityCbData *)user_data;
320 g_signal_handlers_disconnect_by_func(cb_data->session, _on_refresh_dialog, user_data);
322 WARN ("Error : %s", error->message);
323 g_error_free (error);
328 _on_refresh_dialog (GSignondAuthSession *session, GSignondSignonuiData *ui_data, gpointer userdata)
330 GSignondIdentityCbData *cb_data = (GSignondIdentityCbData *) userdata;
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");
339 _on_refresh_requested_by_ui (GSignondSignonuiData *ui_data, gpointer user_data)
341 GSignondIdentityCbData *cb_data = (GSignondIdentityCbData *) user_data;
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);
349 _on_user_action_completed (GSignondSignonuiData *reply, GError *error, gpointer user_data)
351 GSignondIdentityCbData *cb_data = (GSignondIdentityCbData *) user_data;
352 GSignondIdentityPrivate *priv = GSIGNOND_IDENTITY_PRIV (cb_data->identity);
353 GSignondSignonuiError ui_error = SIGNONUI_ERROR_NONE;
355 g_return_if_fail (cb_data && GSIGNOND_IS_AUTH_SESSION (cb_data->session));
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);
361 WARN ("UI-Error: %s on identity %d",
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);
370 g_error_free (error);
371 g_slice_free (GSignondIdentityCbData, cb_data);
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));
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));
387 /* storing secret allowed? */
388 if (gsignond_identity_info_get_store_secret (priv->info)) {
389 gboolean remember = TRUE;
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, "");
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));
414 if (cb_data->session) {
415 gsignond_auth_session_user_action_finished (cb_data->session, reply);
418 g_slice_free (GSignondIdentityCbData, cb_data);
422 _on_process_canceled (GSignondAuthSession *session, GSignondIdentityCbData *cb_data)
424 g_signal_handlers_disconnect_by_func(session, G_CALLBACK(_on_process_canceled), cb_data);
427 WARN ("assert (cb_data)");
430 if (!gsignond_daemon_cancel_dialog (
431 cb_data->identity->priv->owner, G_OBJECT(session), NULL, NULL)) {
432 WARN ("Fail to cancel dialog");
434 g_slice_free (GSignondIdentityCbData, cb_data);
438 _on_user_action_required (GSignondAuthSession *session, GSignondSignonuiData *ui_data, gpointer userdata)
440 GSignondIdentity *identity = GSIGNOND_IDENTITY (userdata);
441 GSignondIdentityCbData *cb_data = g_slice_new (GSignondIdentityCbData);
443 cb_data->identity = identity;
444 cb_data->session = session;
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);
449 g_signal_connect (session, "process-canceled", G_CALLBACK(_on_process_canceled), cb_data);
453 _on_store_token (GSignondAuthSession *session, GSignondDictionary *token_data, gpointer userdata)
455 GSignondIdentity *identity = GSIGNOND_IDENTITY (userdata);
456 guint32 identity_id = GSIGNOND_IDENTITY_INFO_NEW_IDENTITY;
458 g_return_if_fail (identity && session && GSIGNOND_IS_AUTH_SESSION (session));
460 identity_id = gsignond_identity_info_get_id (identity->priv->info);
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);
469 _compare_session_by_pointer (gpointer key, gpointer value, gpointer dead_object)
471 return value == dead_object;
475 _on_session_dead (gpointer data, GObject *session)
477 GSignondIdentity *identity = GSIGNOND_IDENTITY (data);
479 DBG ("identity %p session %p disposed", identity, session);
481 g_hash_table_foreach_remove (identity->priv->auth_sessions,
482 _compare_session_by_pointer, session);
485 GSignondAuthSession *
486 gsignond_identity_get_auth_session (GSignondIdentity *identity,
488 const GSignondSecurityContext *ctx,
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");
496 GSignondAuthSession *session = NULL;
497 GHashTable *supported_methods = NULL;
498 gboolean method_available = FALSE;
499 guint32 identity_id ;
500 GSignondDictionary *token_data = NULL;
502 VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, NULL);
505 WARN ("assertion (method) failed");
506 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_METHOD_NOT_KNOWN,
507 "authentication method not provided");
511 DBG ("get auth session for method '%s'", method);
512 session = g_hash_table_lookup (identity->priv->auth_sessions, method);
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));
519 if (!gsignond_plugin_proxy_factory_get_plugin_mechanisms (gsignond_get_plugin_proxy_factory (),
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",
528 supported_methods = gsignond_identity_info_get_methods (identity->priv->info);
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;
537 method_available = FALSE;
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);
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);
551 if (!token_data) token_data = gsignond_dictionary_new();
553 session = gsignond_auth_session_new (identity->priv->info, method, token_data);
555 if (token_data) gsignond_dictionary_unref (token_data);
558 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
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);
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);
569 DBG ("session %p creation for method '%s' complete", session, method);
575 _on_credentials_updated (GSignondSignonuiData *reply, GError *error, gpointer user_data)
577 GSignondIdentity *identity = GSIGNOND_IDENTITY (user_data);
582 WARN ("failed to verify user : %s", error->message);
583 g_error_free (error);
585 err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_OPERATION_CANCELED, "Operation canceled");
589 GSignondSignonuiError err_id = SIGNONUI_ERROR_NONE;
590 gboolean res = gsignond_signonui_data_get_query_error (reply, &err_id);
593 DBG ("No error code set by UI daemon, treating as ERROR_NONE");
596 if (err_id != SIGNONUI_ERROR_NONE) {
598 case SIGNONUI_ERROR_CANCELED:
599 err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_OPERATION_CANCELED,
600 "Operation canceled");
603 err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_INTERNAL_SERVER,
604 "signon ui returned with error : %d", err_id);
609 const gchar *secret = gsignond_signonui_data_get_password (reply);
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) ;
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");
624 g_signal_emit (identity, signals[SIG_CREDENTIALS_UPDATED], 0 , id, err);
626 if (err) g_error_free (err);
630 gsignond_identity_request_credentials_update (GSignondIdentity *identity,
631 const gchar *message,
632 const GSignondSecurityContext *ctx,
635 GSignondSignonuiData *ui_data = NULL;
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");
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.");
649 VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, FALSE);
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.");
656 ui_data = gsignond_dictionary_new ();
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);
663 gsignond_daemon_show_dialog (GSIGNOND_DAEMON (identity->priv->owner), G_OBJECT(identity),
664 ui_data, _on_credentials_updated, NULL, identity);
666 gsignond_dictionary_unref (ui_data);
672 _on_user_verified (GSignondSignonuiData *reply, GError *error, gpointer user_data)
674 GSignondIdentity *identity = GSIGNOND_IDENTITY (user_data);
675 gboolean res = FALSE;
679 WARN ("failed to verify user : %s", error->message);
680 g_error_free (error);
682 err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_OPERATION_CANCELED, "Operation canceled");
686 GSignondSignonuiError err_id = SIGNONUI_ERROR_NONE;
687 gboolean res = gsignond_signonui_data_get_query_error (reply, &err_id);
689 DBG ("No error code set by UI daemon, treating as ERROR_NONE");
691 if (err_id != SIGNONUI_ERROR_NONE) {
693 case SIGNONUI_ERROR_CANCELED:
694 err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_IDENTITY_OPERATION_CANCELED,
695 "Operation canceled");
697 case SIGNONUI_ERROR_FORGOT_PASSWORD:
698 err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_FORGOT_PASSWORD, "Forgot password");
701 err = gsignond_get_gerror_for_id (GSIGNOND_ERROR_INTERNAL_SERVER,
702 "signon ui returned error : %d", err_id);
707 const gchar *secret = gsignond_signonui_data_get_password (reply);
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;
719 g_signal_emit (identity, signals[SIG_USER_VERIFIED], 0, res, err);
721 if (err) g_error_free (err);
725 gsignond_identity_verify_user (GSignondIdentity *identity,
727 const GSignondSecurityContext *ctx,
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");
735 const gchar *passwd = 0;
736 GSignondSignonuiData *ui_data = NULL;
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.");
744 VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, FALSE);
746 if (!gsignond_identity_info_get_store_secret (identity->priv->info) ||
747 !(passwd = gsignond_identity_info_get_secret (identity->priv->info)) ||
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");
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));
759 gsignond_daemon_show_dialog (GSIGNOND_DAEMON (identity->priv->owner), G_OBJECT (identity),
760 ui_data, _on_user_verified, NULL, identity);
762 gsignond_dictionary_unref (ui_data);
768 gsignond_identity_verify_secret (GSignondIdentity *identity,
770 const GSignondSecurityContext *ctx,
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");
779 VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, FALSE);
781 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Not supported");
787 gsignond_identity_sign_out (GSignondIdentity *identity,
788 const GSignondSecurityContext *ctx,
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");
796 gboolean success = FALSE;
797 guint32 identity_id = GSIGNOND_IDENTITY_INFO_NEW_IDENTITY;
799 VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, FALSE);
801 identity_id = gsignond_identity_info_get_id (identity->priv->info);
803 if (identity_id == GSIGNOND_IDENTITY_INFO_NEW_IDENTITY) {
804 /* TODO; clear the cached secret for unstored identity */
808 success = gsignond_daemon_clear_identity_data (identity->priv->owner, identity_id);
811 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Failed to clear data");
815 g_signal_emit (identity, signals[SIG_INFO_UPDATED], 0, GSIGNOND_IDENTITY_SIGNED_OUT, NULL);
821 GSignondDaemon *daemon;
823 }_StoreCachedTokenCbInfo;
826 _store_cached_token_data (const gchar *method, GSignondAuthSession *session, _StoreCachedTokenCbInfo *data)
828 if (!data || !method || !session) return ;
830 GSignondDictionary *token_data = gsignond_auth_session_get_token_data (session);
833 gsignond_daemon_store_identity_data (data->daemon, data->identity_id, method, token_data);
836 /* check for alphanumeric characters in a string */
838 _check_string (const gchar *strptr)
842 while (*strptr != '\0') {
843 if (isalnum(*strptr))
851 gsignond_identity_store (GSignondIdentity *identity,
852 const GVariant *info,
853 const GSignondSecurityContext *ctx,
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;
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");
871 priv = identity->priv;
873 VALIDATE_IDENTITY_WRITE_ACCESS (identity, ctx, 0);
875 was_new_identity = gsignond_identity_info_get_is_identity_new (priv->info);
877 identity_info = gsignond_identity_info_new_from_variant ((GVariant *)info);
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);
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);
888 gsignond_security_context_free (owner_ctx);
892 contexts = gsignond_identity_info_get_access_control_list (identity_info);
894 VALIDATE_IDENTITY_WRITE_ACL (identity, ctx, 0);
895 gsignond_security_context_list_free (contexts);
898 flags = gsignond_identity_info_get_edit_flags (identity_info);
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;
913 gsignond_identity_info_selective_copy (priv->info, identity_info, flags);
915 /* FIXME : either username/secret changed reset the identity
916 * valdated state to FALSE ???
919 gsignond_identity_info_unref (identity_info);
921 /* Ask daemon to store identity info to db */
922 id = gsignond_daemon_store_identity (priv->owner, identity);
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 */
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);
936 g_signal_emit (identity, signals[SIG_INFO_UPDATED], 0, GSIGNOND_IDENTITY_DATA_UPDATED);
943 gsignond_identity_remove (GSignondIdentity *identity,
944 const GSignondSecurityContext *ctx,
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");
952 gboolean is_removed = FALSE;
954 VALIDATE_IDENTITY_WRITE_ACCESS (identity, ctx, FALSE);
956 is_removed = gsignond_identity_clear (identity);
958 if (!is_removed && error)
959 *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_REMOVE_FAILED, "failed to remove identity");
966 gsignond_identity_clear (GSignondIdentity *identity)
968 if (!(identity && GSIGNOND_IS_IDENTITY (identity))) {
969 WARN ("assertion (identity && GSIGNOND_IS_IDENTITY(identity)) failed");
972 gboolean is_removed = FALSE;
974 if (gsignond_identity_info_get_is_identity_new (identity->priv->info))
977 is_removed = gsignond_daemon_remove_identity (
978 identity->priv->owner,
979 gsignond_identity_info_get_id (identity->priv->info));
982 g_signal_emit (identity, signals[SIG_INFO_UPDATED], 0, GSIGNOND_IDENTITY_REMOVED);
984 WARN ("request to remove identity %u failed",
985 gsignond_identity_info_get_id (identity->priv->info));
992 gsignond_identity_add_reference (GSignondIdentity *identity,
993 const gchar *reference,
994 const GSignondSecurityContext *ctx,
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");
1003 guint32 identity_id = 0;
1005 VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, 0);
1007 identity_id = gsignond_identity_info_get_id (identity->priv->info);
1009 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_STORE_FAILED, "Cannot add reference to unsaved identity");
1012 res = gsignond_daemon_add_identity_reference (identity->priv->owner, identity_id, ctx, reference);
1015 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
1022 gsignond_identity_remove_reference (GSignondIdentity *identity,
1023 const gchar *reference,
1024 const GSignondSecurityContext *ctx,
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");
1034 guint32 identity_id = 0;
1036 VALIDATE_IDENTITY_READ_ACCESS (identity, ctx, 0);
1038 identity_id = gsignond_identity_info_get_id (identity->priv->info);
1040 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_REFERENCE_NOT_FOUND, "reference not '%s' found", reference);
1044 res = gsignond_daemon_remove_identity_reference (identity->priv->owner, identity_id, ctx, reference);
1046 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_REFERENCE_NOT_FOUND,
1047 "reference '%s' not found", reference);
1052 GSignondAccessControlManager *
1053 gsignond_identity_get_acm (GSignondIdentity *identity)
1055 g_return_val_if_fail (identity && GSIGNOND_IS_IDENTITY(identity), NULL);
1057 return gsignond_daemon_get_access_control_manager (identity->priv->owner);
1061 gsignond_identity_get_auth_session_timeout (GSignondIdentity *identity)
1063 g_return_val_if_fail (identity && GSIGNOND_IS_IDENTITY(identity), 0);
1065 return gsignond_daemon_get_auth_session_timeout (identity->priv->owner);
1069 * gsignond_identity_get_id:
1070 * @identity: instance of #GSignondIdentity
1072 * Retrieves identity id.
1074 * Returns: identity id
1077 gsignond_identity_get_id (GSignondIdentity *identity)
1079 g_assert (GSIGNOND_IS_IDENTITY (identity));
1081 return gsignond_identity_info_get_id (identity->priv->info);
1085 * gsignond_identity_get_identity_info:
1086 * @identity: instance of #GSignondIdentity
1088 * Retrieves identity's #GSignondIdentityInfo.
1090 * Returns: (transfer none) #GSignondIdentityInfo
1092 GSignondIdentityInfo *
1093 gsignond_identity_get_identity_info (GSignondIdentity *identity)
1095 g_assert (GSIGNOND_IS_IDENTITY (identity));
1096 g_assert (identity->priv != NULL);
1098 return identity->priv->info;
1102 * gsignond_identity_new:
1103 * @owner: Owner of this object, instance of #GSignondAuthServiceIface
1104 * @info (transfer full): Identity info, instance of #GSignondIdentityInfo
1106 * Creates new instance of #GSignondIdentity
1108 * Returns[transfer full]: new instance of #GSignondIdentity
1110 GSignondIdentity * gsignond_identity_new (GSignondDaemon *owner,
1111 GSignondIdentityInfo *info)
1113 GSignondIdentity *identity =
1114 GSIGNOND_IDENTITY(g_object_new (GSIGNOND_TYPE_IDENTITY,
1118 identity->priv->owner = g_object_ref (owner);