src/plugins/Makefile
src/plugins/password/Makefile
src/plugins/ssotest/Makefile
+src/plugins/digest/Makefile
test/Makefile
test/common/Makefile
test/db/Makefile
-SUBDIRS=password ssotest
+SUBDIRS=password ssotest digest
--- /dev/null
+include $(top_srcdir)/common.mk
+plugins_LTLIBRARIES = libdigest.la
+NULL=
+
+libdigest_la_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/include \
+ $(GSIGNOND_CFLAGS) \
+ $(NULL)
+
+libdigest_la_LIBADD = \
+ $(top_builddir)/src/common/libgsignond-common.la \
+ $(GSIGNOND_LIBS) \
+ -lgcrypt \
+ $(NULL)
+
+libdigest_la_SOURCES = \
+ gsignond-digest-plugin.c \
+ $(NULL)
+
+CLEANFILES =
--- /dev/null
+/* vi: set et sw=4 ts=4 cino=t0,(0: */
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of gsignond
+ *
+ * Copyright (C) 2012-2013 Intel Corporation.
+ *
+ * Contact: Imran Zaman <imran.zaman@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <gsignond/gsignond-plugin-interface.h>
+#include "gsignond-digest-plugin.h"
+#include <gsignond/gsignond-error.h>
+#include <gsignond/gsignond-log.h>
+
+static void gsignond_plugin_interface_init (GSignondPluginInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GSignondDigestPlugin, gsignond_digest_plugin,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GSIGNOND_TYPE_PLUGIN,
+ gsignond_plugin_interface_init));
+
+#define GSIGNOND_DIGEST_PLUGIN_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+ GSIGNOND_TYPE_DIGEST_PLUGIN, \
+ GSignondDigestPluginPrivate))
+
+#define DATA_SET_VALUE(data, key, value) \
+ if (value) { \
+ gsignond_dictionary_set_string(data, key, value); \
+ }
+#define TO_GUCHAR(data) ((const guchar*)data)
+
+struct _GSignondDigestPluginPrivate
+{
+ GSignondSessionData *session_data;
+};
+
+static gchar *
+_gsignond_digest_plugin_compute_md5_digest(
+ const gchar* algo,
+ const gchar* username,
+ const gchar* realm,
+ const gchar* secret,
+ const gchar* nonce,
+ const gchar* nonce_count,
+ const gchar* cnonce,
+ const gchar* qop,
+ const gchar* method,
+ const gchar* digest_uri,
+ const gchar* hentity)
+{
+ GChecksum *a1 = NULL, *a2 = NULL, *response = NULL;
+ const gchar *ha1 = NULL, *ha2 = NULL;
+ gchar *hresponse = NULL;
+
+ a1 = g_checksum_new (G_CHECKSUM_MD5);
+ g_checksum_update (a1, TO_GUCHAR(username), strlen(username));
+ g_checksum_update (a1, TO_GUCHAR(":"), 1);
+ g_checksum_update (a1, TO_GUCHAR(realm), strlen(realm));
+ g_checksum_update (a1, TO_GUCHAR(":"), 1);
+ g_checksum_update (a1, TO_GUCHAR(secret), strlen(secret));
+
+ if (g_strcmp0 (algo, "md5-sess") == 0) {
+ GChecksum *a1_sess = NULL;
+ a1_sess = g_checksum_new (G_CHECKSUM_MD5);
+ ha1 = g_checksum_get_string (a1);
+ g_checksum_update (a1_sess, TO_GUCHAR(ha1), strlen(ha1));
+ g_checksum_update (a1_sess, TO_GUCHAR(":"), 1);
+ g_checksum_update (a1_sess, TO_GUCHAR(nonce), strlen(nonce));
+ g_checksum_update (a1_sess, TO_GUCHAR(":"), 1);
+ g_checksum_update (a1_sess, TO_GUCHAR(cnonce), strlen(cnonce));
+ g_checksum_free (a1);
+ a1 = a1_sess;
+ }
+
+ a2 = g_checksum_new (G_CHECKSUM_MD5);
+ g_checksum_update (a2, TO_GUCHAR(method), strlen(method));
+ g_checksum_update (a2, TO_GUCHAR(":"), 1);
+ g_checksum_update (a2, TO_GUCHAR(digest_uri), strlen(digest_uri));
+ if (qop && g_strcmp0 (qop, "auth-int") == 0) {
+ g_checksum_update (a2, TO_GUCHAR(":"), 1);
+ g_checksum_update (a2, TO_GUCHAR(hentity), strlen(hentity));
+ }
+ ha1 = g_checksum_get_string (a1);
+ ha2 = g_checksum_get_string (a2);
+
+ response = g_checksum_new (G_CHECKSUM_MD5);
+ g_checksum_update (response, TO_GUCHAR(ha1), strlen(ha1));
+ g_checksum_update (response, TO_GUCHAR(":"), 1);
+ g_checksum_update (response, TO_GUCHAR(nonce), strlen(nonce));
+ g_checksum_update (response, TO_GUCHAR(":"), 1);
+ if (qop) {
+ g_checksum_update (response, TO_GUCHAR(nonce_count),
+ strlen(nonce_count));
+ g_checksum_update (response, TO_GUCHAR(":"), 1);
+ g_checksum_update (response, TO_GUCHAR(cnonce), strlen(cnonce));
+ g_checksum_update (response, TO_GUCHAR(":"), 1);
+ g_checksum_update (response, TO_GUCHAR(qop), strlen(qop));
+ g_checksum_update (response, TO_GUCHAR(":"), 1);
+ }
+ g_checksum_update (response, TO_GUCHAR(ha2), strlen(ha2));
+ hresponse = g_strdup(g_checksum_get_string (response));
+ g_checksum_free (response);
+ g_checksum_free (a2);
+ g_checksum_free (a1);
+ return hresponse;
+}
+
+static gchar *
+_gsignond_digest_plugin_generate_nonce(void)
+{
+ GChecksum *hash = NULL;
+ gchar *nonce = NULL, *timestr = NULL;
+ struct timespec ts;
+ gint fd;
+
+ hash = g_checksum_new (G_CHECKSUM_MD5);
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd != -1) {
+ guint8 buf[32];
+ if (read (fd, buf, sizeof(buf) > 0)) {
+ g_checksum_update (hash, buf, 32);
+ g_checksum_update (hash, TO_GUCHAR(":"), 1);
+ }
+ close(fd);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ timestr = g_strdup_printf ("%p:%d:%lu",
+ hash,
+ g_random_int (),
+ (unsigned long) ts.tv_nsec);
+ g_checksum_update (hash, TO_GUCHAR(timestr), strlen(timestr));
+ g_free (timestr);
+ nonce = g_strdup (g_checksum_get_string (hash));
+ g_checksum_free (hash);
+ return nonce;
+}
+
+static void
+gsignond_digest_plugin_cancel (GSignondPlugin *self)
+{
+ GError* error = g_error_new(GSIGNOND_ERROR,
+ GSIGNOND_ERROR_SESSION_CANCELED,
+ "Session cancelled");
+ gsignond_plugin_error (self, error);
+ g_error_free(error);
+}
+
+static void
+gsignond_digest_plugin_abort (GSignondPlugin *self)
+{
+
+}
+
+static void
+gsignond_digest_plugin_request (
+ GSignondPlugin *self,
+ GSignondSessionData *session_data)
+{
+
+}
+
+static void
+gsignond_digest_plugin_request_initial (
+ GSignondPlugin *plugin,
+ GSignondSessionData *session_data,
+ const gchar *mechanism)
+{
+
+ GSignondDigestPlugin *self = NULL;
+ const gchar *username = gsignond_session_data_get_username(session_data);
+ const gchar *secret = gsignond_session_data_get_secret(session_data);
+ const gchar *realm = gsignond_session_data_get_realm (session_data);
+ const gchar *algo = gsignond_dictionary_get_string (session_data, "Algo");
+ const gchar *nonce = gsignond_dictionary_get_string (session_data,
+ "Nonce");
+ const gchar *nonce_count = gsignond_dictionary_get_string (session_data,
+ "NonceCount");
+ const gchar *qop = gsignond_dictionary_get_string (session_data,
+ "Qop");
+ const gchar *method = gsignond_dictionary_get_string (session_data,
+ "Method");
+ const gchar *digest_uri = gsignond_dictionary_get_string (session_data,
+ "DigestUri");
+ const gchar *hentity = gsignond_dictionary_get_string (session_data,
+ "HEntity");
+
+ if ((!realm || !algo || !nonce || !method || !digest_uri)
+ || (qop && g_strcmp0 (qop, "auth-int") == 0 && !hentity)
+ || (qop && !nonce_count)) {
+ GError* error = g_error_new(GSIGNOND_ERROR, GSIGNOND_ERROR_MISSING_DATA,
+ "Missing Session Data");
+ gsignond_plugin_error (plugin, error);
+ g_error_free(error);
+ return;
+ }
+
+ if (username != NULL && secret != NULL) {
+ gchar *cnonce = _gsignond_digest_plugin_generate_nonce ();
+ GSignondSessionData *response = gsignond_dictionary_new ();
+ gsignond_session_data_set_username (response, username);
+ gsignond_dictionary_set_string (response, "CNonce", cnonce);
+ gchar *digest = _gsignond_digest_plugin_compute_md5_digest (algo,
+ username,realm, secret, nonce, nonce_count, cnonce, qop, method,
+ digest_uri, hentity);
+ g_free (cnonce);
+ gsignond_dictionary_set_string (response, "Response", digest);
+ g_free (digest);
+ gsignond_plugin_response_final (plugin, response);
+ gsignond_dictionary_unref (response);
+ return;
+ }
+
+ self = GSIGNOND_DIGEST_PLUGIN (plugin);
+ if (self->priv->session_data) {
+ gsignond_dictionary_unref (self->priv->session_data);
+ self->priv->session_data = NULL;
+ }
+ gsignond_dictionary_ref (session_data);
+ self->priv->session_data = session_data;
+
+ GSignondSignonuiData *user_action_data = gsignond_signonui_data_new ();
+ DATA_SET_VALUE (user_action_data, "Realm", realm);
+ DATA_SET_VALUE (user_action_data, "DigestUri", digest_uri);
+ gsignond_signonui_data_set_query_username (user_action_data, TRUE);
+ gsignond_signonui_data_set_query_password (user_action_data, TRUE);
+ gsignond_plugin_user_action_required (plugin, user_action_data);
+ gsignond_dictionary_unref (user_action_data);
+}
+
+static void
+gsignond_digest_plugin_user_action_finished (
+ GSignondPlugin *plugin,
+ GSignondSignonuiData *signonui_data)
+{
+ GSignondSessionData *session_data = NULL;
+ GSignondSignonuiError query_error;
+ gboolean res = gsignond_signonui_data_get_query_error(signonui_data,
+ &query_error);
+ g_assert(res == TRUE);
+
+ const gchar* username = gsignond_signonui_data_get_username(signonui_data);
+ const gchar* secret = gsignond_signonui_data_get_password(signonui_data);
+
+ session_data = GSIGNOND_DIGEST_PLUGIN (plugin)->priv->session_data;
+
+ if (query_error == SIGNONUI_ERROR_NONE &&
+ username != NULL &&
+ secret != NULL &&
+ session_data != NULL) {
+ GSignondSessionData *response = NULL;
+ const gchar* realm = gsignond_session_data_get_realm (session_data);
+ const gchar* algo = gsignond_dictionary_get_string (session_data,
+ "Algo");
+ const gchar* nonce = gsignond_dictionary_get_string (session_data,
+ "Nonce");
+ const gchar* nonce_count = gsignond_dictionary_get_string (session_data,
+ "NonceCount");
+ const gchar* qop = gsignond_dictionary_get_string (session_data,
+ "Qop");
+ const gchar* method = gsignond_dictionary_get_string (session_data,
+ "Method");
+ const gchar* digest_uri = gsignond_dictionary_get_string (session_data,
+ "DigestUri");
+ const gchar* hentity = gsignond_dictionary_get_string (session_data,
+ "HEntity");
+ gchar *cnonce = _gsignond_digest_plugin_generate_nonce ();
+ gchar *digest = _gsignond_digest_plugin_compute_md5_digest(algo,
+ username,realm, secret, nonce, nonce_count, cnonce, qop, method,
+ digest_uri, hentity);
+
+ response = gsignond_dictionary_new();
+ gsignond_session_data_set_username(response, username);
+ gsignond_dictionary_set_string(response, "CNonce", cnonce);
+ g_free (cnonce);
+ gsignond_dictionary_set_string(response, "Response", digest);
+ g_free(digest);
+
+ gsignond_plugin_response_final(plugin, response);
+ gsignond_dictionary_unref(response);
+ return;
+ } else if (query_error == SIGNONUI_ERROR_CANCELED) {
+ gsignond_digest_plugin_cancel (plugin);
+ } else {
+ GError* error = g_error_new(GSIGNOND_ERROR,
+ GSIGNOND_ERROR_USER_INTERACTION, "userActionFinished error: %d",
+ query_error);
+ gsignond_plugin_error (plugin, error);
+ g_error_free(error);
+ }
+}
+
+static void
+gsignond_digest_plugin_refresh (
+ GSignondPlugin *self,
+ GSignondSessionData *session_data)
+{
+ gsignond_plugin_refreshed(self, session_data);
+}
+
+static void
+gsignond_plugin_interface_init (GSignondPluginInterface *iface)
+{
+ iface->cancel = gsignond_digest_plugin_cancel;
+ iface->abort = gsignond_digest_plugin_abort;
+ iface->request_initial = gsignond_digest_plugin_request_initial;
+ iface->request = gsignond_digest_plugin_request;
+ iface->user_action_finished = gsignond_digest_plugin_user_action_finished;
+ iface->refresh = gsignond_digest_plugin_refresh;
+}
+
+static void
+gsignond_digest_plugin_init (GSignondDigestPlugin *self)
+{
+ self->priv = GSIGNOND_DIGEST_PLUGIN_GET_PRIVATE (self);
+ self->priv->session_data = NULL;
+}
+
+enum
+{
+ PROP_0,
+ PROP_TYPE,
+ PROP_MECHANISMS
+};
+
+static void
+gsignond_digest_plugin_set_property (
+ GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id)
+ {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gsignond_digest_plugin_get_property (
+ GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GSignondDigestPlugin *digest_plugin = GSIGNOND_DIGEST_PLUGIN (object);
+ (void) digest_plugin;
+ gchar *mechanisms[] = { "digest", NULL };
+
+ switch (prop_id)
+ {
+ case PROP_TYPE:
+ g_value_set_string (value, "digest");
+ break;
+ case PROP_MECHANISMS:
+ g_value_set_boxed (value, mechanisms);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsignond_digest_plugin_dispose (GObject *gobject)
+{
+ g_return_if_fail (GSIGNOND_IS_DIGEST_PLUGIN (gobject));
+ GSignondDigestPlugin *self = GSIGNOND_DIGEST_PLUGIN (gobject);
+
+ if (self->priv->session_data) {
+ gsignond_dictionary_unref (self->priv->session_data);
+ self->priv->session_data = NULL;
+ }
+
+ /* Chain up to the parent class */
+ G_OBJECT_CLASS (gsignond_digest_plugin_parent_class)->dispose (
+ gobject);
+}
+
+static void
+gsignond_digest_plugin_class_init (GSignondDigestPluginClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = gsignond_digest_plugin_set_property;
+ gobject_class->get_property = gsignond_digest_plugin_get_property;
+ gobject_class->dispose = gsignond_digest_plugin_dispose;
+
+ g_object_class_override_property (gobject_class, PROP_TYPE, "type");
+ g_object_class_override_property (gobject_class, PROP_MECHANISMS,
+ "mechanisms");
+
+ g_type_class_add_private (klass, sizeof (GSignondDigestPluginPrivate));
+}
--- /dev/null
+/* vi: set et sw=4 ts=4 cino=t0,(0: */
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of gsignond
+ *
+ * Copyright (C) 2012-2013 Intel Corporation.
+ *
+ * Contact: Imran Zaman <imran.zaman@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __GSIGNOND_DIGEST_PLUGIN_H__
+#define __GSIGNOND_DIGEST_PLUGIN_H__
+
+#include <glib-object.h>
+
+#define GSIGNOND_TYPE_DIGEST_PLUGIN (gsignond_digest_plugin_get_type ())
+#define GSIGNOND_DIGEST_PLUGIN(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSIGNOND_TYPE_DIGEST_PLUGIN, \
+ GSignondDigestPlugin))
+#define GSIGNOND_IS_DIGEST_PLUGIN(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSIGNOND_TYPE_DIGEST_PLUGIN))
+#define GSIGNOND_DIGEST_PLUGIN_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GSIGNOND_TYPE_DIGEST_PLUGIN, \
+ GSignondDigestPluginClass))
+#define GSIGNOND_IS_DIGEST_PLUGIN_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GSIGNOND_TYPE_DIGEST_PLUGIN))
+#define GSIGNOND_DIGEST_PLUGIN_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), GSIGNOND_TYPE_DIGEST_PLUGIN, \
+ GSignondDigestPluginClass))
+
+
+typedef struct _GSignondDigestPlugin GSignondDigestPlugin;
+typedef struct _GSignondDigestPluginClass GSignondDigestPluginClass;
+typedef struct _GSignondDigestPluginPrivate GSignondDigestPluginPrivate;
+
+struct _GSignondDigestPlugin
+{
+ GObject parent_instance;
+
+ GSignondDigestPluginPrivate *priv;
+ int instance_member;
+};
+
+struct _GSignondDigestPluginClass
+{
+ GObjectClass parent_class;
+};
+
+GType gsignond_digest_plugin_get_type (void);
+
+#endif /* __GSIGNOND_DIGEST_PLUGIN_H__ */
-TESTS = passwordplugintest pluginproxytest
+TESTS = digestplugintest passwordplugintest pluginproxytest
TESTS_ENVIRONMENT= SSO_PLUGINS_DIR=$(top_builddir)/src/plugins/password/.libs
-check_PROGRAMS = passwordplugintest pluginproxytest
+check_PROGRAMS = digestplugintest passwordplugintest pluginproxytest
+digestplugintest_SOURCES = digestplugintest.c
+digestplugintest_CFLAGS = \
+ $(GSIGNOND_CFLAGS) \
+ $(CHECK_CFLAGS) \
+ -I$(top_srcdir)/src/plugins/digest \
+ -I$(top_srcdir)/include/
+
+digestplugintest_LDADD = \
+ $(top_builddir)/src/common/libgsignond-common.la \
+ $(top_builddir)/src/plugins/digest/libdigest.la \
+ $(GSIGNOND_LIBS) \
+ $(CHECK_LIBS)
+
passwordplugintest_SOURCES = passwordplugintest.c
passwordplugintest_CFLAGS = \
$(GSIGNOND_CFLAGS) \
--- /dev/null
+/* vi: set et sw=4 ts=4 cino=t0,(0: */
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of gsignond
+ *
+ * Copyright (C) 2012-2013 Intel Corporation.
+ *
+ * Contact: Imran Zaman <imran.zaman@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <check.h>
+#include <stdlib.h>
+#include "gsignond-digest-plugin.h"
+#include <gsignond/gsignond-session-data.h>
+#include <gsignond/gsignond-plugin-interface.h>
+#include <gsignond/gsignond-error.h>
+#include <gsignond/gsignond-log.h>
+#include <gsignond/gsignond-plugin-loader.h>
+#include <gsignond/gsignond-config.h>
+
+START_TEST (test_session_data)
+{
+ GSignondSessionData* data;
+ GSignondSessionData* data_from_variant;
+ GSignondSessionData* data_from_copy;
+ GVariant* variant;
+
+ data = gsignond_dictionary_new();
+ fail_if(data == NULL);
+
+ fail_unless(gsignond_session_data_get_username(data) == NULL);
+ fail_unless(gsignond_session_data_get_secret(data) == NULL);
+
+ gsignond_session_data_set_username(data, "megauser");
+ gsignond_session_data_set_secret(data, "megapassword");
+
+ fail_unless(g_strcmp0(gsignond_session_data_get_username(data),
+ "megauser") == 0);
+ fail_unless(g_strcmp0(gsignond_session_data_get_secret(data),
+ "megapassword") == 0);
+
+ gsignond_session_data_set_username(data, "usermega");
+ fail_unless(g_strcmp0(gsignond_session_data_get_username(data),
+ "usermega") == 0);
+
+ data_from_copy = gsignond_dictionary_copy(data);
+ fail_if(data_from_copy == NULL);
+
+ fail_unless(g_strcmp0(gsignond_session_data_get_username(data_from_copy),
+ "usermega") == 0);
+ fail_unless(g_strcmp0(gsignond_session_data_get_secret(data_from_copy),
+ "megapassword") == 0);
+
+ variant = gsignond_dictionary_to_variant(data);
+ fail_if(variant == NULL);
+ data_from_variant = gsignond_dictionary_new_from_variant(variant);
+ fail_if(data_from_variant == NULL);
+
+ fail_unless(g_strcmp0(gsignond_session_data_get_username(data_from_variant),
+ "usermega") == 0);
+ fail_unless(g_strcmp0(gsignond_session_data_get_secret(data_from_variant),
+ "megapassword") == 0);
+
+ g_variant_unref(variant);
+ gsignond_dictionary_unref(data_from_variant);
+ gsignond_dictionary_unref(data_from_copy);
+ gsignond_dictionary_unref(data);
+}
+END_TEST
+
+static void check_plugin(GSignondPlugin* plugin)
+{
+ gchar* type;
+ gchar** mechanisms;
+
+ fail_if(plugin == NULL);
+
+ g_object_get(plugin, "type", &type, "mechanisms", &mechanisms, NULL);
+
+ fail_unless(g_strcmp0(type, "digest") == 0);
+ fail_unless(g_strcmp0(mechanisms[0], "digest") == 0);
+ fail_unless(mechanisms[1] == NULL);
+
+ g_free(type);
+ g_strfreev(mechanisms);
+}
+
+START_TEST (test_digestplugin_create)
+{
+ gpointer plugin;
+
+ plugin = g_object_new(GSIGNOND_TYPE_DIGEST_PLUGIN, NULL);
+ check_plugin(plugin);
+ g_object_unref(plugin);
+}
+END_TEST
+
+static void
+response_callback(
+ GSignondPlugin* plugin,
+ GSignondSessionData* result,
+ gpointer user_data)
+{
+ GSignondSessionData** user_data_p = user_data;
+ *user_data_p = gsignond_dictionary_copy(result);
+}
+
+static void
+user_action_required_callback(
+ GSignondPlugin* plugin,
+ GSignondSignonuiData* ui_request,
+ gpointer user_data)
+{
+ GSignondSignonuiData** user_data_p = user_data;
+ *user_data_p = gsignond_dictionary_copy(ui_request);
+ gsignond_signonui_data_set_username(*user_data_p, "user1");
+ gsignond_signonui_data_set_password(*user_data_p, "password1");
+}
+
+static void
+error_callback(
+ GSignondPlugin* plugin,
+ GError* error,
+ gpointer user_data)
+{
+ GError** user_data_p = user_data;
+ *user_data_p = g_error_copy(error);
+}
+
+
+START_TEST (test_digestplugin_request)
+{
+ gpointer plugin;
+ gboolean query_res;
+
+ plugin = g_object_new(GSIGNOND_TYPE_DIGEST_PLUGIN, NULL);
+ fail_if(plugin == NULL);
+
+ GSignondSessionData* result = NULL;
+ GSignondSignonuiData* ui_action = NULL;
+ GError* error = NULL;
+
+ g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback),
+ &result);
+ g_signal_connect(plugin, "user-action-required",
+ G_CALLBACK(user_action_required_callback), &ui_action);
+ g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);
+
+ GSignondSessionData* data = gsignond_dictionary_new();
+
+ // set only username and password
+ gsignond_session_data_set_username(data, "user1");
+ gsignond_session_data_set_secret(data, "password1");
+
+ gsignond_plugin_request_initial(plugin, data, "digest");
+ fail_if(result != NULL);
+ fail_if(ui_action != NULL);
+ fail_if(error == NULL);
+ fail_unless(g_error_matches(error, GSIGNOND_ERROR,
+ GSIGNOND_ERROR_MISSING_DATA));
+ g_error_free(error);
+ error = NULL;
+
+ // set all the required stuff so that no ui-action is required
+ gsignond_session_data_set_realm(data, "realm1");
+ gsignond_dictionary_set_string(data, "Algo", "md5-sess");
+ gsignond_dictionary_set_string(data, "Nonce",
+ "abg10b1234ee1f0e8b11d0f600bfb0c093");
+ gsignond_dictionary_set_string(data, "Method", "GET");
+ gsignond_dictionary_set_string(data, "DigestUri", "/test/index.html");
+
+ gsignond_plugin_request_initial(plugin, data, "digest");
+ fail_if(result == NULL);
+ fail_if(ui_action != NULL);
+ fail_if(error != NULL);
+ fail_if(g_strcmp0(gsignond_session_data_get_username(result),
+ "user1") != 0);
+ fail_if(gsignond_dictionary_get_string(result, "Response") == NULL);
+ fail_if(gsignond_dictionary_get_string(result, "CNonce") == NULL);
+ gsignond_dictionary_unref(result);
+ result = NULL;
+
+ //remove secret so that ui action is required
+ gsignond_dictionary_remove (data, "Secret");
+ gsignond_plugin_request_initial(plugin, data, "digest");
+ fail_if(result != NULL);
+ fail_if(ui_action == NULL);
+ fail_if(error != NULL);
+ fail_if(g_strcmp0(gsignond_signonui_data_get_username(ui_action),
+ "user1") != 0);
+ fail_if(g_strcmp0(gsignond_signonui_data_get_password(ui_action),
+ "password1") != 0);
+ fail_if(gsignond_dictionary_get_string(ui_action, "Realm") == NULL);
+ fail_if(gsignond_dictionary_get_string(ui_action, "DigestUri") == NULL);
+ gsignond_signonui_data_get_query_username(ui_action, &query_res);
+ fail_if(query_res == FALSE);
+ gsignond_signonui_data_get_query_password(ui_action, &query_res);
+ fail_if(query_res == FALSE);
+ gsignond_dictionary_unref(ui_action);
+ ui_action = NULL;
+
+ gsignond_dictionary_unref(data);
+ g_object_unref(plugin);
+}
+END_TEST
+
+START_TEST (test_digestplugin_user_action_finished)
+{
+ gpointer plugin;
+
+ plugin = g_object_new(GSIGNOND_TYPE_DIGEST_PLUGIN, NULL);
+ fail_if(plugin == NULL);
+
+ GSignondSessionData *result = NULL, *data = NULL;
+ GSignondSignonuiData *ui_action = NULL, *ui_data = NULL;
+ GError* error = NULL;
+
+ g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback),
+ &result);
+ g_signal_connect(plugin, "user-action-required",
+ G_CALLBACK(user_action_required_callback), &ui_action);
+ g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);
+
+ ui_data = gsignond_signonui_data_new();
+ gsignond_signonui_data_set_query_error(ui_data, SIGNONUI_ERROR_NONE);
+
+ //empty data
+ gsignond_plugin_user_action_finished(plugin, ui_data);
+ fail_if(result != NULL);
+ fail_if(ui_action != NULL);
+ fail_if(error == NULL);
+ fail_unless(g_error_matches(error, GSIGNOND_ERROR,
+ GSIGNOND_ERROR_USER_INTERACTION));
+ g_error_free(error);
+ error = NULL;
+
+ // user cancelled
+ gsignond_signonui_data_set_query_error(ui_data, SIGNONUI_ERROR_CANCELED);
+ gsignond_plugin_user_action_finished(plugin, ui_data);
+ fail_if(result != NULL);
+ fail_if(ui_action != NULL);
+ fail_if(error == NULL);
+ fail_unless(g_error_matches(error, GSIGNOND_ERROR,
+ GSIGNOND_ERROR_SESSION_CANCELED));
+ g_error_free(error);
+ error = NULL;
+
+ // error in ui request
+ gsignond_signonui_data_set_query_error(ui_data, SIGNONUI_ERROR_GENERAL);
+ gsignond_plugin_user_action_finished(plugin, ui_data);
+ fail_if(result != NULL);
+ fail_if(ui_action != NULL);
+ fail_if(error == NULL);
+ fail_unless(g_error_matches(error, GSIGNOND_ERROR,
+ GSIGNOND_ERROR_USER_INTERACTION));
+ g_error_free(error);
+ error = NULL;
+
+ // correct values but no session data
+ gsignond_signonui_data_set_username (ui_data, "user1");
+ gsignond_signonui_data_set_password (ui_data, "password1");
+ gsignond_signonui_data_set_query_error (ui_data, SIGNONUI_ERROR_NONE);
+ gsignond_plugin_user_action_finished (plugin, ui_data);
+ fail_if(result != NULL);
+ fail_if(ui_action != NULL);
+ fail_if(error == NULL);
+ fail_unless(g_error_matches(error, GSIGNOND_ERROR,
+ GSIGNOND_ERROR_USER_INTERACTION));
+ g_error_free(error);
+ error = NULL;
+
+ //correct values
+ data = gsignond_dictionary_new ();
+ gsignond_session_data_set_username (data, "user1");
+ gsignond_session_data_set_realm (data, "realm1");
+ gsignond_dictionary_set_string (data, "Algo", "md5-sess");
+ gsignond_dictionary_set_string (data, "Nonce",
+ "abg10b1234ee1f0e8b11d0f600bfb0c093");
+ gsignond_dictionary_set_string (data, "Method", "GET");
+ gsignond_dictionary_set_string (data, "DigestUri", "/test/index.html");
+ gsignond_plugin_request_initial (plugin, data, "digest");
+ gsignond_dictionary_unref (data); data = NULL;
+
+ gsignond_plugin_user_action_finished (plugin, ui_data);
+ fail_if (result == NULL);
+ fail_if (error != NULL);
+ fail_if(ui_action == NULL);
+ fail_if(g_strcmp0(gsignond_session_data_get_username(result),
+ "user1") != 0);
+ fail_if(gsignond_dictionary_get_string(result, "Response") == NULL);
+ fail_if(gsignond_dictionary_get_string(result, "CNonce") == NULL);
+ gsignond_dictionary_unref(result);
+ result = NULL;
+ gsignond_dictionary_unref(ui_action);
+ ui_action = NULL;
+
+ gsignond_dictionary_unref (ui_data);
+ g_object_unref (plugin);
+}
+END_TEST
+
+START_TEST (test_digestplugin_refresh)
+{
+ gpointer plugin;
+
+ plugin = g_object_new(GSIGNOND_TYPE_DIGEST_PLUGIN, NULL);
+ fail_if(plugin == NULL);
+
+ GSignondSessionData* result = NULL;
+ GError* error = NULL;
+
+ g_signal_connect(plugin, "refreshed", G_CALLBACK(response_callback),
+ &result);
+ g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);
+
+ GSignondSessionData* data = gsignond_dictionary_new();
+ gsignond_plugin_refresh(plugin, data);
+ fail_if(result == NULL);
+ fail_if(error != NULL);
+ gsignond_dictionary_unref(result);
+ result = NULL;
+
+ gsignond_dictionary_unref(data);
+ g_object_unref(plugin);
+}
+END_TEST
+
+Suite* digestplugin_suite (void)
+{
+ Suite *s = suite_create ("Digest plugin");
+
+ /* Core test case */
+ TCase *tc_core = tcase_create ("Tests");
+ tcase_add_test (tc_core, test_session_data);
+ tcase_add_test (tc_core, test_digestplugin_create);
+ tcase_add_test (tc_core, test_digestplugin_request);
+ tcase_add_test (tc_core, test_digestplugin_user_action_finished);
+ tcase_add_test (tc_core, test_digestplugin_refresh);
+ suite_add_tcase (s, tc_core);
+ return s;
+}
+
+int main (void)
+{
+ int number_failed;
+
+ g_type_init();
+
+ Suite *s = digestplugin_suite();
+ SRunner *sr = srunner_create(s);
+ srunner_run_all(sr, CK_NORMAL);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+