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) 2013 Intel Corporation.
8 * Contact: Jussi Laako <jussi.laako@linux.intel.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 #include "gsignond-auth-session.h"
27 #include "gsignond/gsignond-error.h"
28 #include "gsignond/gsignond-log.h"
29 #include "gsignond/gsignond-session-data.h"
30 #include "plugins/gsignond-plugin-proxy-factory.h"
31 #include "gsignond-daemon.h"
40 static GParamSpec *properties[N_PROPERTIES];
44 SIG_PROCESS_USER_ACTION_REQUIRED,
45 SIG_PROCESS_REFRESHED,
51 static guint signals[SIG_MAX] = { 0 };
54 GSignondAuthSession *self;
55 ProcessReadyCb ready_cb;
56 StateChangeCb state_change_cb;
60 struct _GSignondAuthSessionPrivate
63 GSignondPluginProxy *proxy;
64 GSequence *available_mechanisms;
65 GSignondIdentityInfo *identity_info;
66 GSignondDictionary *token_data;
69 G_DEFINE_TYPE (GSignondAuthSession, gsignond_auth_session, G_TYPE_OBJECT)
71 #define GSIGNOND_AUTH_SESSION_PRIV(obj) \
72 G_TYPE_INSTANCE_GET_PRIVATE ((obj), GSIGNOND_TYPE_AUTH_SESSION, \
73 GSignondAuthSessionPrivate)
75 #define VALIDATE_READ_ACCESS(info, ctx, ret) \
77 GSignondAccessControlManager *acm = gsignond_get_access_control_manager(); \
78 GSignondSecurityContextList *acl = gsignond_identity_info_get_access_control_list (info); \
79 GSignondSecurityContext *owner = gsignond_identity_info_get_owner (info); \
80 gboolean valid = gsignond_access_control_manager_peer_is_allowed_to_use_identity (acm, ctx, owner, acl); \
81 gsignond_security_context_free (owner); \
82 gsignond_security_context_list_free (acl); \
84 WARN ("security check failed"); \
86 *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_PERMISSION_DENIED, "Can not access identity"); \
93 _sort_cmp (gconstpointer str1, gconstpointer str2, gpointer user_data)
97 return g_strcmp0 ((const gchar *) str1, (const gchar *) str2);
101 _create_mechanism_cache (GSignondAuthSession *self)
103 GSignondAuthSessionPrivate *priv = self->priv;
105 if (priv->available_mechanisms)
108 gchar **mechanisms, **iter;
109 GSequence *allowed_mechanisms = NULL;
110 GSequenceIter *wcard = NULL;
112 self->priv->available_mechanisms = g_sequence_new (g_free);
113 if (!gsignond_identity_info_get_is_identity_new (priv->identity_info)) {
114 allowed_mechanisms = gsignond_identity_info_get_mechanisms (
117 if (!allowed_mechanisms)
119 wcard = g_sequence_lookup (allowed_mechanisms,
124 g_object_get (self->priv->proxy,
125 "mechanisms", &mechanisms,
128 if (allowed_mechanisms)
129 g_sequence_free (allowed_mechanisms);
132 if (wcard || !allowed_mechanisms) {
133 DBG ("add all mechanisms to allowed");
134 for (iter = mechanisms; *iter != NULL; iter++) {
135 g_sequence_insert_sorted (priv->available_mechanisms,
139 DBG (" allow '%s'", *iter);
142 DBG ("allow intersection of plugin and ACL mechanisms");
143 for (iter = mechanisms; *iter != NULL; iter++) {
144 GSequenceIter *pos = g_sequence_lookup (allowed_mechanisms,
149 DBG (" allow: '%s'", *iter);
150 g_sequence_insert_sorted (priv->available_mechanisms,
157 if (allowed_mechanisms)
158 g_sequence_free (allowed_mechanisms);
163 gsignond_auth_session_query_available_mechanisms (GSignondAuthSession *self,
164 const gchar **wanted_mechanisms,
165 const GSignondSecurityContext *ctx,
168 if (!self || !GSIGNOND_IS_AUTH_SESSION (self)) {
169 WARN ("assertion (iself && GSIGNOND_IS_AUTH_SESSION (self)) failed");
170 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
174 VALIDATE_READ_ACCESS (self->priv->identity_info, ctx, NULL);
176 gchar **mechanisms, **iter;
177 const gchar **src_iter;
179 _create_mechanism_cache (self);
180 mechanisms = (gchar **)
181 g_malloc0 ((g_sequence_get_length (self->priv->available_mechanisms) +
182 1) * sizeof(gchar *));
184 for (src_iter = wanted_mechanisms; *src_iter != NULL; src_iter++) {
185 GSequenceIter *pos = g_sequence_lookup (
186 self->priv->available_mechanisms,
187 (gpointer) *src_iter,
191 *iter = g_sequence_get (pos);
201 gsignond_auth_session_process (GSignondAuthSession *self,
202 GSignondSessionData *session_data,
203 const gchar *mechanism,
204 const GSignondSecurityContext *ctx,
205 ProcessReadyCb ready_cb,
206 StateChangeCb state_change_cb,
210 if (!self || !GSIGNOND_IS_AUTH_SESSION (self)) {
211 WARN ("assertion (self && GSIGNOND_IS_AUTH_SESSION (self)) failed");
212 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
216 VALIDATE_READ_ACCESS (self->priv->identity_info, ctx, FALSE);
218 _create_mechanism_cache (self);
219 if (!g_sequence_lookup (self->priv->available_mechanisms,
220 (gpointer) mechanism,
223 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_MECHANISM_NOT_AVAILABLE, "Mechanism is not available");
228 self->priv->identity_info) {
229 if (!gsignond_session_data_get_username (session_data)) {
230 const gchar *username =
231 gsignond_identity_info_get_username (self->priv->identity_info);
233 gsignond_session_data_set_username (session_data, username);
235 if (!gsignond_session_data_get_secret (session_data)) {
236 const gchar *secret =
237 gsignond_identity_info_get_secret (self->priv->identity_info);
239 gsignond_session_data_set_secret (session_data, secret);
243 _ProcessData * data = g_slice_new0 (_ProcessData);
245 data->ready_cb = ready_cb;
246 data->state_change_cb = state_change_cb;
247 data->userdata = userdata;
248 gsignond_plugin_proxy_process(self->priv->proxy, self, session_data,
249 self->priv->token_data,
256 gsignond_auth_session_cancel (GSignondAuthSession *self,
257 const GSignondSecurityContext *ctx,
260 if (!self || !GSIGNOND_IS_AUTH_SESSION (self)) {
261 WARN ("assertion (self && GSIGNOND_IS_AUTH_SESSION (self)) failed");
262 if (error) *error = gsignond_get_gerror_for_id (GSIGNOND_ERROR_UNKNOWN, "Unknown error");
265 VALIDATE_READ_ACCESS (self->priv->identity_info, ctx, FALSE);
267 gsignond_plugin_proxy_cancel(self->priv->proxy, self);
268 g_signal_emit (self, signals[SIG_PROCESS_CANCELED], 0, NULL);
274 gsignond_auth_session_abort_process (GSignondAuthSession *self)
276 g_return_if_fail (self && GSIGNOND_IS_AUTH_SESSION (self));
278 gsignond_plugin_proxy_cancel (self->priv->proxy, self);
279 g_signal_emit (self, signals[SIG_PROCESS_CANCELED], 0, NULL);
283 gsignond_auth_session_user_action_finished (GSignondAuthSession *self,
284 GSignondSignonuiData *ui_data)
286 gsignond_plugin_proxy_user_action_finished(self->priv->proxy, ui_data);
290 gsignond_auth_session_refresh (GSignondAuthSession *self,
291 GSignondSignonuiData *ui_data)
293 gsignond_plugin_proxy_refresh(self->priv->proxy, ui_data);
296 GSignondAccessControlManager *
297 gsignond_auth_session_get_acm (GSignondAuthSession *session)
299 return gsignond_get_access_control_manager ();
303 _get_property (GObject *object, guint property_id, GValue *value,
306 GSignondAuthSession *self = GSIGNOND_AUTH_SESSION (object);
311 g_value_set_string (value, self->priv->method);
314 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
319 _set_property (GObject *object, guint property_id, const GValue *value,
322 GSignondAuthSession *self = GSIGNOND_AUTH_SESSION (object);
327 self->priv->method = g_value_dup_string (value);
330 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
335 _dispose (GObject *object)
337 GSignondAuthSession *self = GSIGNOND_AUTH_SESSION (object);
339 if (self->priv->proxy) {
340 g_object_unref (self->priv->proxy);
341 self->priv->proxy = NULL;
344 if (self->priv->identity_info) {
345 g_hash_table_unref ((GHashTable *)self->priv->identity_info);
346 self->priv->identity_info = NULL;
349 if (self->priv->token_data) {
350 gsignond_dictionary_unref (self->priv->token_data);
351 self->priv->token_data = NULL;
354 G_OBJECT_CLASS (gsignond_auth_session_parent_class)->dispose (object);
358 _finalize (GObject *object)
360 GSignondAuthSession *self = GSIGNOND_AUTH_SESSION (object);
362 if (self->priv->method) {
363 g_free (self->priv->method);
364 self->priv->method = NULL;
367 if (self->priv->available_mechanisms) {
368 g_sequence_free (self->priv->available_mechanisms);
369 self->priv->available_mechanisms = NULL;
372 G_OBJECT_CLASS (gsignond_auth_session_parent_class)->finalize (object);
376 gsignond_auth_session_init (GSignondAuthSession *self)
378 self->priv = GSIGNOND_AUTH_SESSION_PRIV (self);
380 self->priv->method = NULL;
381 self->priv->proxy = NULL;
382 self->priv->identity_info = NULL;
383 self->priv->token_data = NULL;
384 self->priv->available_mechanisms = NULL;
388 gsignond_auth_session_class_init (GSignondAuthSessionClass *klass)
390 GObjectClass *object_class = G_OBJECT_CLASS (klass);
392 g_type_class_add_private (klass, sizeof (GSignondAuthSessionPrivate));
394 object_class->get_property = _get_property;
395 object_class->set_property = _set_property;
396 object_class->dispose = _dispose;
397 object_class->finalize = _finalize;
399 properties[PROP_METHOD] =
400 g_param_spec_string ("method",
401 "authentication method",
402 "Authentication method used",
404 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
405 | G_PARAM_STATIC_STRINGS);
407 g_object_class_install_properties (object_class, N_PROPERTIES, properties);
409 signals[SIG_PROCESS_STORE] = g_signal_new ("process-store",
410 GSIGNOND_TYPE_AUTH_SESSION,
418 GSIGNOND_TYPE_DICTIONARY);
420 signals[SIG_PROCESS_USER_ACTION_REQUIRED] = g_signal_new ("process-user-action-required",
421 GSIGNOND_TYPE_AUTH_SESSION,
429 GSIGNOND_TYPE_SIGNONUI_DATA);
431 signals[SIG_PROCESS_REFRESHED] = g_signal_new ("process-refreshed",
432 GSIGNOND_TYPE_AUTH_SESSION,
440 GSIGNOND_TYPE_SIGNONUI_DATA);
442 signals[SIG_PROCESS_CANCELED] = g_signal_new ("process-canceled",
443 GSIGNOND_TYPE_AUTH_SESSION,
456 * gsignond_auth_session_get_method:
457 * @session: instance of #GSignondAuthSession
459 * Retrieves authentication method used by #session.
461 * Returns: (transfer none) authenticaiton method if success, NULL otherwise
464 gsignond_auth_session_get_method (GSignondAuthSession *session)
466 g_return_val_if_fail (session && GSIGNOND_IS_AUTH_SESSION (session), NULL);
468 return session->priv->method;
472 gsignond_auth_session_get_token_data (GSignondAuthSession *session)
474 g_return_val_if_fail (session && GSIGNOND_IS_AUTH_SESSION (session), NULL);
476 return session->priv->token_data;
480 gsignond_auth_session_notify_process_result (GSignondAuthSession *iface,
481 GSignondSessionData *result,
485 WARN("assert (userdata)");
488 _ProcessData *data = (_ProcessData *)userdata;
490 if (data->ready_cb) data->ready_cb (result, NULL, data->userdata);
492 g_slice_free (_ProcessData, data);
496 gsignond_auth_session_notify_process_error (GSignondAuthSession *iface,
501 WARN("assert (userdata)");
504 _ProcessData *data = (_ProcessData *)userdata;
506 if (data->ready_cb) data->ready_cb (NULL, error, data->userdata);
508 g_slice_free (_ProcessData, data);
512 gsignond_auth_session_notify_state_changed (GSignondAuthSession *self,
514 const gchar *message,
518 WARN("assert (userdata)");
521 _ProcessData *data = (_ProcessData *)userdata;
523 if (data->state_change_cb) data->state_change_cb (state, message, data->userdata);
527 gsignond_auth_session_notify_store (GSignondAuthSession *self,
528 GSignondDictionary *token_data)
530 g_return_if_fail (self && GSIGNOND_IS_AUTH_SESSION (self));
531 g_return_if_fail (token_data);
533 /* cache token data */
534 if (self->priv->token_data)
535 gsignond_dictionary_unref (self->priv->token_data);
536 self->priv->token_data = gsignond_dictionary_ref (token_data);
538 g_signal_emit (self, signals[SIG_PROCESS_STORE], 0, token_data);
542 gsignond_auth_session_notify_user_action_required (GSignondAuthSession *self,
543 GSignondSignonuiData *ui_data)
545 g_signal_emit (self, signals[SIG_PROCESS_USER_ACTION_REQUIRED], 0, ui_data);
549 gsignond_auth_session_notify_refreshed (GSignondAuthSession *self,
550 GSignondSignonuiData *ui_data)
552 g_signal_emit (self, signals[SIG_PROCESS_REFRESHED], 0, ui_data);
557 * gsignond_auth_session_new:
558 * @info: instance of #GSignondIdentityInfo
559 * @method: authentication method
560 * @token_data: (transfer full) stored token data stored for #method
562 * Creates instance of #GSignondAuthSession.
564 * Returns: (transfer full) newly created object
566 GSignondAuthSession *
567 gsignond_auth_session_new (GSignondIdentityInfo *info, const gchar *method, GSignondDictionary *token_data)
569 GSignondPluginProxy* proxy = NULL;
571 g_return_val_if_fail (method, NULL);
573 proxy = gsignond_plugin_proxy_factory_get_plugin(
574 gsignond_get_plugin_proxy_factory(), method);
575 if (!proxy) return NULL;
577 GSignondAuthSession *auth_session =
578 g_object_new (GSIGNOND_TYPE_AUTH_SESSION,
579 "method", method, NULL);
580 auth_session->priv->proxy = proxy;
581 auth_session->priv->identity_info = g_hash_table_ref ((GHashTable *)info);
582 auth_session->priv->token_data = token_data ? gsignond_dictionary_ref(token_data)
583 : gsignond_dictionary_new();