Add password plugin, tests and necessary basic pieces
authorAlexander Kanavin <alexander.kanavin@intel.com>
Wed, 16 Jan 2013 17:15:25 +0000 (19:15 +0200)
committerAlexander Kanavin <alexander.kanavin@intel.com>
Wed, 23 Jan 2013 16:59:30 +0000 (18:59 +0200)
16 files changed:
.gitignore
configure.ac
include/gsignond/gsignond-dictionary.h [new file with mode: 0644]
include/gsignond/gsignond-error.h
include/gsignond/gsignond-plugin-interface.h
include/gsignond/gsignond-session-data.h [new file with mode: 0644]
src/common/Makefile.am
src/common/gsignond-dictionary.c [new file with mode: 0644]
src/common/gsignond-error.c
src/common/gsignond-plugin-interface.c
src/common/gsignond-session-data.c [new file with mode: 0644]
src/plugins/password/Makefile.am
src/plugins/password/gsignond-password-plugin.c
test/Makefile.am
test/passwordplugin/Makefile.am [new file with mode: 0644]
test/passwordplugin/passwordplugintest.c [new file with mode: 0644]

index f1388b0..859e388 100644 (file)
@@ -25,5 +25,7 @@ m4/lt*.m4
 build-aux
 *dbus*gen*
 src/daemon/gsignond
+test/db/testdb
+test/passwordplugin/passwordplugintest
 stamp-h1
 *service
index cb347bc..198f8d7 100644 (file)
@@ -28,6 +28,11 @@ PKG_CHECK_MODULES([GSIGNOND],
 AC_SUBST(GSIGNOND_CFLAGS)
 AC_SUBST(GSIGNOND_LIBS)
 
+# AM_PATH_CHECK() is deprecated, but check documentation fails to tell that :-/
+PKG_CHECK_MODULES([CHECK], [check >= 0.9.4], [have_check=yes], [have_check=no])
+AC_SUBST(CHECK_CFLAGS)
+AC_SUBST(CHECK_LIBS)
+
 DBUS_SERVICES_DIR="`pkg-config --variable session_bus_services_dir dbus-1`"
 AC_SUBST(DBUS_SERVICES_DIR)
 DBUS_INTERFACES_DIR="`pkg-config --variable interfaces_dir dbus-1`"
@@ -55,4 +60,5 @@ src/plugins/Makefile
 src/plugins/password/Makefile
 test/Makefile
 test/db/Makefile
+test/passwordplugin/Makefile
 ])
diff --git a/include/gsignond/gsignond-dictionary.h b/include/gsignond/gsignond-dictionary.h
new file mode 100644 (file)
index 0000000..44c4dcb
--- /dev/null
@@ -0,0 +1,71 @@
+/* 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 Intel Corporation.
+ *
+ * Contact: Alexander Kanavin <alex.kanavin@gmail.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_DICTIONARY_H__
+#define __GSIGNOND_DICTIONARY_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GSIGNOND_TYPE_DICTIONARY (G_TYPE_HASH_TABLE)
+
+#define GSIGNOND_DICTIONARY(obj)  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+                                           GSIGNOND_TYPE_DICTIONARY, \
+                                           GSignondDictionary))
+#define GSIGNOND_IS_DICTIONARY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+                                           GSIGNOND_TYPE_DICTIONARY))
+
+typedef GHashTable GSignondDictionary;
+
+GType
+gsignond_dictionary_get_type (void);
+
+GSignondDictionary *
+gsignond_dictionary_new (void);
+
+void
+gsignond_dictionary_free (GSignondDictionary *dict);
+
+GSignondDictionary *
+gsignond_dictionary_copy (GSignondDictionary *other);
+
+GSignondDictionary *
+gsignond_dictionary_new_from_variant (GVariant *variant);
+
+GVariant *
+gsignond_dictionary_to_variant (GSignondDictionary *self);
+
+GVariant *
+gsignond_dictionary_get (GSignondDictionary *dict, gchar *key);
+
+void
+gsignond_dictionary_set (GSignondDictionary *dict, 
+    gchar *key, GVariant *value);
+
+G_END_DECLS
+
+#endif /* __GSIGNOND_DICTIONARY_H__ */
index 1c02d01..3297cab 100644 (file)
@@ -31,7 +31,7 @@
 
 G_BEGIN_DECLS
 
-#define G_LOG_DOMAIN "gsignond"
+#define GSIGNOND_ERROR_DOMAIN "gsignond"
 
 /**
  * GSIGNOND_ERROR:
@@ -41,7 +41,70 @@ G_BEGIN_DECLS
 
 typedef enum {
     GSIGNOND_ERROR_NONE,
-    /* Add error codes */
+
+    GSIGNOND_ERROR_UNKNOWN = 1,               /**< Catch-all for errors not distinguished
+                                        by another code. */
+    GSIGNOND_ERROR_INTERNAL_SERVER = 2,        /**< Signon Daemon internal error. */
+    GSIGNOND_ERROR_INTERNAL_COMMUNICATION = 3, /**< Communication with Signon Daemon
+                                     error. */
+    GSIGNOND_ERROR_PERMISSION_DENIED = 4,      /**< The operation cannot be performed due to
+                                        insufficient client permissions. */
+    GSIGNOND_ERROR_ENCRYPTION_FAILURE,         /**< Failure during data
+                                     encryption/decryption. */
+    GSIGNOND_ERROR_AUTH_SERVICE_ERR = 100,           /* Placeholder to rearrange enumeration
+                                         - AuthService specific */
+    GSIGNOND_ERROR_METHOD_NOT_KNOWN,            /**< The method with this name is not
+                                     found. */
+    GSIGNOND_ERROR_SERVICE_NOT_AVAILABLE,       /**< The service is temporarily
+                                     unavailable. */
+    GSIGNOND_ERROR_INVALID_QUERY,              /**< Parameters for the query are invalid. */
+    GSIGNOND_ERROR_IDENTITY_ERR = 200,              /* Placeholder to rearrange enumeration
+                                         - Identity specific */
+    GSIGNOND_ERROR_METHOD_NOT_AVAILABLE,        /**< The requested method is not available. */
+    GSIGNOND_ERROR_IDENTITY_NOT_FOUND,          /**< The identity matching this Identity
+                                     object was not found on the service. */
+    GSIGNOND_ERROR_STORE_FAILED,               /**< Storing credentials failed. */
+    GSIGNOND_ERROR_REMOVE_FAILED,              /**< Removing credentials failed. */
+    GSIGNOND_ERROR_SIGN_OUT_FAILED,             /**< SignOut failed. */
+    GSIGNOND_ERROR_IDENTITY_OPERATION_CANCELED, /**< Identity operation was canceled by
+                                     user. */
+    GSIGNOND_ERROR_CREDENTIALS_NOT_AVAILABLE,   /**< Query failed. */
+    GSIGNOND_ERROR_REFERENCE_NOT_FOUND,         /**< Trying to remove nonexistent
+                                     reference. */
+    GSIGNOND_ERROR_AUTH_SESSION_ERR = 300,      /* Placeholder to rearrange enumeration
+                                     - AuthSession/AuthPluginInterface
+                                     specific */
+    GSIGNOND_ERROR_MECHANISM_NOT_AVAILABLE,     /**< The requested mechanism is not
+                                     available. */
+    GSIGNOND_ERROR_MISSING_DATA,               /**< The SessionData object does not contain
+                                        necessary information. */
+    GSIGNOND_ERROR_INVALID_CREDENTIALS,        /**< The supplied credentials are invalid for
+                                        the mechanism implementation. */
+    GSIGNOND_ERROR_NOT_AUTHORIZED,             /**< Authorization failed. */
+    GSIGNOND_ERROR_WRONG_STATE,                /**< An operation method has been called in
+                                        a wrong state. */
+    GSIGNOND_ERROR_OPERATION_NOT_SUPPORTED,     /**< The operation is not supported by the
+                                        mechanism implementation. */
+    GSIGNOND_ERROR_NO_CONNECTION,              /**< No Network connetion. */
+    GSIGNOND_ERROR_NETWORK,                   /**< Network connetion failed. */
+    GSIGNOND_ERROR_SSL,                       /**< Ssl connection failed. */
+    GSIGNOND_ERROR_RUNTIME,                   /**< Casting SessionData into subclass
+                                     failed */
+    GSIGNOND_ERROR_SESSION_CANCELED,           /**< Challenge was cancelled. */
+    GSIGNOND_ERROR_TIMED_OUT,                  /**< Challenge was timed out. */
+    GSIGNOND_ERROR_USER_INTERACTION,           /**< User interaction dialog failed */
+    GSIGNOND_ERROR_OPERATION_FAILED,           /**< Temporary failure in authentication. */
+    GSIGNOND_ERROR_ENCRYPTION_FAILED,          /**< @deprecated Failure during data
+                                     encryption/decryption. */
+    GSIGNOND_ERROR_TOS_NOT_ACCEPTED,            /**< User declined Terms of Service. */
+    GSIGNOND_ERROR_FORGOT_PASSWORD,            /**< User requested reset password
+                                     sequence. */
+    GSIGNOND_ERROR_METHOD_OR_MECHANISM_NOT_ALLOWED, /**< Method or mechanism not allowed for
+                                       this identity. */
+    GSIGNOND_ERROR_INCORRECT_DATE,             /**< Date time incorrect on device. */
+    GSIGNOND_ERROR_USER_ERR = 400                   /* Placeholder to rearrange enumeration
+                                         - User space specific */
+   
 } GSignondError;
 
 #define gsignond_gerr(error, handler) \
index 39e0950..ea849ce 100644 (file)
 
 #include <glib.h>
 #include <glib-object.h>
+#include <gsignond/gsignond-session-data.h>
 
 G_BEGIN_DECLS
 
-#define GSIGNOND_TYPE_PLUGIN                           (gsignond_plugin_get_type ())
-#define GSIGNOND_PLUGIN(obj)                           (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSIGNOND_TYPE_PLUGIN, GSignondPlugin))
-#define GSIGNOND_IS_PLUGIN(obj)                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSIGNOND_TYPE_PLUGIN))
-#define GSIGNOND_PLUGIN_GET_INTERFACE(inst)            (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GSIGNOND_TYPE_PLUGIN, GSignondPluginInterface))
+#define GSIGNOND_TYPE_PLUGIN    (gsignond_plugin_get_type ())
+#define GSIGNOND_PLUGIN(obj)    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSIGNOND_TYPE_PLUGIN, GSignondPlugin))
+#define GSIGNOND_IS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSIGNOND_TYPE_PLUGIN))
+#define GSIGNOND_PLUGIN_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GSIGNOND_TYPE_PLUGIN, GSignondPluginInterface))
 
 typedef struct _GSignondPlugin GSignondPlugin; /* dummy object */
 typedef struct _GSignondPluginInterface GSignondPluginInterface;
@@ -42,11 +43,15 @@ typedef struct _GSignondPluginInterface GSignondPluginInterface;
 struct _GSignondPluginInterface {
     GTypeInterface parent;
 
-    void       (*cancel) (GSignondPlugin *self);
-    void       (*abort) (GSignondPlugin *self);
-    void       (*process) (GSignondPlugin *self, const GVariant *session_data, const gchar *mechanism);
-    void       (*user_action_finished) (GSignondPlugin *self, const GVariant *session_data);
-    void       (*refresh) (GSignondPlugin *self, const GVariant *session_data);
+    void (*cancel) (GSignondPlugin *self);
+    void (*abort) (GSignondPlugin *self);
+    void (*process) (GSignondPlugin *self, 
+                     GSignondSessionData *session_data, 
+                     const gchar *mechanism);
+    void (*user_action_finished) (GSignondPlugin *self, 
+                                  GSignondSessionData *session_data);
+    void (*refresh) (GSignondPlugin *self, 
+                     GSignondSessionData *session_data);
 };
 
 GType gsignond_plugin_get_type (void);
@@ -54,17 +59,27 @@ GType gsignond_plugin_get_type (void);
 /* Methods */
 void gsignond_plugin_cancel (GSignondPlugin *self);
 void gsignond_plugin_abort (GSignondPlugin *self);
-void gsignond_plugin_process (GSignondPlugin *self, const GVariant *session_data, const gchar *mechanism);
-void gsignond_plugin_user_action_finished (GSignondPlugin *self, const GVariant *session_data);
-void gsignond_plugin_refresh (GSignondPlugin *self, const GVariant *session_data);
+void gsignond_plugin_process (GSignondPlugin *self, 
+                              GSignondSessionData *session_data, 
+                              const gchar *mechanism);
+void gsignond_plugin_user_action_finished (GSignondPlugin *self, 
+                                           GSignondSessionData *session_data);
+void gsignond_plugin_refresh (GSignondPlugin *self, 
+                              GSignondSessionData *session_data);
 
 /* Signals */
-void gsignond_plugin_result (GSignondPlugin *self, const GVariant *session_data);
-void gsignond_plugin_store (GSignondPlugin *self, const GVariant *session_data);
-void gsignond_plugin_error (GSignondPlugin *self, int error); //FIXME: what is the error type?
-void gsignond_plugin_user_action_required (GSignondPlugin *self, const GVariant *session_data);
-void gsignond_plugin_refreshed (GSignondPlugin *self, const GVariant *session_data);
-void gsignond_plugin_status_changed (GSignondPlugin *self, const gchar *status, const gchar *message);
+void gsignond_plugin_result (GSignondPlugin *self, 
+                             GSignondSessionData *session_data);
+void gsignond_plugin_store (GSignondPlugin *self, 
+                            GSignondSessionData *session_data);
+void gsignond_plugin_error (GSignondPlugin *self, GError *error);
+void gsignond_plugin_user_action_required (GSignondPlugin *self, 
+                                           GSignondSessionData *session_data);
+void gsignond_plugin_refreshed (GSignondPlugin *self, 
+                                GSignondSessionData *session_data);
+void gsignond_plugin_status_changed (GSignondPlugin *self, 
+                                     const gchar *status, 
+                                     const gchar *message);
 
 G_END_DECLS
 
diff --git a/include/gsignond/gsignond-session-data.h b/include/gsignond/gsignond-session-data.h
new file mode 100644 (file)
index 0000000..b1dab4e
--- /dev/null
@@ -0,0 +1,106 @@
+/* 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 Intel Corporation.
+ *
+ * Contact: Alexander Kanavin <alex.kanavin@gmail.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_SESSION_DATA_H__
+#define __GSIGNOND_SESSION_DATA_H__
+
+#include <gsignond/gsignond-dictionary.h>
+
+G_BEGIN_DECLS
+
+#define GSIGNOND_TYPE_SESSION_DATA (GSIGNOND_TYPE_DICTIONARY)
+
+#define GSIGNOND_SESSION_DATA(obj)  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+                                           GSIGNOND_TYPE_SESSION_DATA, \
+                                           GSignondSessionData))
+#define GSIGNOND_IS_SESSION_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+                                           GSIGNOND_TYPE_SESSION_DATA))
+
+typedef GSignondDictionary GSignondSessionData;
+
+/*!
+ * Error codes for ui interaction.
+ */
+typedef enum {
+    GSIGNOND_QUERY_ERROR_NONE = 0,        /**< No errors. */
+    GSIGNOND_QUERY_ERROR_GENERAL,         /**< Generic error during interaction. */
+    GSIGNOND_QUERY_ERROR_NO_SIGNONUI,     /**< Cannot send request to signon-ui. */
+    GSIGNOND_QUERY_ERROR_BAD_PARAMETERS,  /**< Signon-Ui cannot create dialog based on
+                                   the given UiSessionData. */
+    GSIGNOND_QUERY_ERROR_CANCELED,        /**< User canceled action. Plugin should not
+                                   retry automatically after this. */
+    GSIGNOND_QUERY_ERROR_NOT_AVAILABLE,   /**< Requested ui is not available. For
+                                   example browser cannot be started. */
+    GSIGNOND_QUERY_ERROR_BAD_URL,         /**< Given url was not valid. */
+    GSIGNOND_QUERY_ERROR_BAD_CAPTCHA,     /**< Given captcha image was not valid. */
+    GSIGNOND_QUERY_ERROR_BAD_CAPTCHA_URL, /**< Given url for capctha loading was not
+                                   valid. */
+    GSIGNOND_QUERY_ERROR_REFRESH_FAILED,  /**< Refresh failed. */
+    GSIGNOND_QUERY_ERROR_FORBIDDEN,       /**< Showing ui forbidden by ui policy. */
+    GSIGNOND_QUERY_ERROR_FORGOT_PASSWORD  /**< User pressed forgot password. */
+    //TODO add more errors
+} GSignondQueryError;
+
+
+//FIXME: all the other standard sessiondata and uisessiondata fields 
+//should be added
+const gchar*
+gsignond_session_data_get_username(GSignondSessionData* data);
+
+void
+gsignond_session_data_set_username(GSignondSessionData* data, 
+                                   const gchar* username);
+
+const gchar*
+gsignond_session_data_get_secret(GSignondSessionData* data);
+
+void
+gsignond_session_data_set_secret(GSignondSessionData* data, 
+                                 const gchar* secret);
+
+gboolean
+gsignond_session_data_get_query_username(GSignondSessionData* data);
+
+void
+gsignond_session_data_set_query_username(GSignondSessionData* data, 
+                                         gboolean query_username);
+
+gboolean
+gsignond_session_data_get_query_password(GSignondSessionData* data);
+
+void
+gsignond_session_data_set_query_password(GSignondSessionData* data, 
+                                         gboolean query_password);
+
+GSignondQueryError gsignond_session_data_get_query_error(
+    GSignondSessionData* data);
+
+void
+gsignond_session_data_set_query_error(GSignondSessionData* data, 
+                                         GSignondQueryError error);
+
+G_END_DECLS
+
+#endif /* __GSIGNOND_SESSION_DATA_H__ */
index 3a62918..5816ad7 100644 (file)
@@ -29,6 +29,8 @@ libgsignond_common_la_SOURCES = \
     gsignond-config.c \
     gsignond-error.c \
     gsignond-plugin-interface.c \
+    gsignond-dictionary.c \
+    gsignond-session-data.c \
     $(NULL)
 
 CLEANFILES = 
diff --git a/src/common/gsignond-dictionary.c b/src/common/gsignond-dictionary.c
new file mode 100644 (file)
index 0000000..f176b6c
--- /dev/null
@@ -0,0 +1,197 @@
+/* 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 Intel Corporation.
+ *
+ * Contact: Alexander Kanavin <alex.kanavin@gmail.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 <gsignond/gsignond-dictionary.h>
+
+/**
+ * gsignond_dictionary_new_from_variant:
+ * @variant: instance of #GVariant
+ *
+ * Converts the variant to GSignondDictionary.
+ *
+ * Returns: (transfer full) object if successful, NULL otherwise.
+ */
+GSignondDictionary *
+gsignond_dictionary_new_from_variant (GVariant *variant)
+{
+    GSignondDictionary *dict = NULL;
+    GVariantIter iter;
+    gchar *key = NULL;
+    GVariant *value = NULL;
+
+    g_return_val_if_fail (variant != NULL, NULL);
+
+    dict = gsignond_dictionary_new ();
+    g_variant_iter_init (&iter, variant);
+    while (g_variant_iter_next (&iter, "{sv}", &key, &value))
+    {
+        g_hash_table_insert (dict, key, value);
+    }
+
+    return dict;
+}
+
+/**
+ * gsignond_dictionary_to_variant:
+ * @dict: instance of #GSignondDictionary
+ *
+ * Converts the GSignondDictionary to variant.
+ *
+ * Returns: (transfer full) #GVariant object if successful, NULL otherwise.
+ */
+GVariant *
+gsignond_dictionary_to_variant (GSignondDictionary *dict)
+{
+    GVariantBuilder builder;
+    GHashTableIter iter;
+    GVariant *vdict = NULL;
+    const gchar *key = NULL;
+    GVariant *value = NULL;
+
+    g_return_val_if_fail (dict != NULL, NULL);
+
+    g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+    g_hash_table_iter_init (&iter, dict);
+    while (g_hash_table_iter_next (&iter,
+                                   (gpointer)&key,
+                                   (gpointer)&value))
+    {
+        g_variant_builder_add (&builder, "{sv}",
+                               key,
+                               value);
+    }
+    vdict = g_variant_builder_end (&builder);
+    return vdict;
+}
+
+/**
+ * gsignond_dictionary_new:
+ *
+ * Creates new instance of GSignondDictionary.
+ *
+ * Returns: (transfer full) #GSignondDictionary object if successful,
+ * NULL otherwise.
+ */
+GSignondDictionary *
+gsignond_dictionary_new (void)
+{
+    return g_hash_table_new_full ((GHashFunc)g_str_hash,
+                            (GEqualFunc)g_str_equal,
+                            (GDestroyNotify)g_free,
+                            (GDestroyNotify)g_variant_unref);
+}
+
+/**
+ * gsignond_dictionary_free:
+ * @dict: instance of #GSignondDictionary
+ *
+ * Frees the memory allocated by dict structure.
+ *
+ */
+void
+gsignond_dictionary_free (GSignondDictionary *dict)
+{
+    g_return_if_fail (dict != NULL);
+    g_hash_table_unref (dict);
+}
+
+/**
+ * gsignond_dictionary_get:
+ * @dict: instance of #GSignondDictionary
+ *
+ * Retrieves a value from the dictionary.
+ *
+ * Returns: the value; NULL is returned in case of failure.
+ */
+GVariant *
+gsignond_dictionary_get (GSignondDictionary *dict, gchar *key)
+{
+    g_return_val_if_fail (dict != NULL, NULL);
+    g_return_val_if_fail (key != NULL, NULL);
+
+    return g_hash_table_lookup (dict, key);
+}
+
+/**
+ * gsignond_dictionary_set:
+ * @dict: instance of #GSignondDictionary
+ *
+ * @key: key to be set
+ * @value: value to be set
+ *
+ * Adds or replaces key-value pair in the dictionary.
+ *
+ * Returns: TRUE if successful, FALSE otherwise.
+ */
+void
+gsignond_dictionary_set (GSignondDictionary *dict, 
+    gchar *key, GVariant *value)
+{
+    g_return_if_fail (dict != NULL);
+    g_return_if_fail (key != NULL);
+    g_return_if_fail (value != NULL);
+
+    g_variant_ref_sink(value);
+    
+    g_hash_table_replace (
+            dict,
+            g_strdup(key),
+            value);
+
+    return;
+}
+
+/**
+ * gsignond_dictionary_copy:
+ * @other: instance of #GSignondDictionary
+ *
+ * Creates a copy of the dictionary.
+ *
+ * Returns: (transfer full) #GSignondDictionary object if successful,
+ * NULL otherwise.
+ */
+GSignondDictionary *
+gsignond_dictionary_copy (GSignondDictionary *other)
+{
+    GSignondDictionary *dict = NULL;
+    GHashTableIter iter;
+    gchar *key = NULL;
+    GVariant *value = NULL;
+
+    g_return_val_if_fail (other != NULL, NULL);
+
+    dict = gsignond_dictionary_new ();
+    
+    g_hash_table_iter_init (&iter, other);
+    while (g_hash_table_iter_next (&iter,
+                                   (gpointer)&key,
+                                   (gpointer)&value))
+    {
+        gsignond_dictionary_set (dict, key, value);
+    }
+    
+
+    return dict;
+}
index d5234f9..03149d3 100644 (file)
@@ -32,7 +32,7 @@ gsignond_error_quark (void)
 {
     static GQuark quark = 0;
     if (quark == 0) {
-        quark = g_quark_from_static_string (G_LOG_DOMAIN);
+        quark = g_quark_from_static_string (GSIGNOND_ERROR_DOMAIN);
     }
     return quark;
 }
index 1c6b827..3c21507 100644 (file)
@@ -46,33 +46,38 @@ static void gsignond_plugin_default_init (GSignondPluginInterface *g_class)
 {
     signals[RESULT] = g_signal_new ("result", G_TYPE_FROM_CLASS (g_class),
         G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE,
-        1, G_TYPE_VARIANT);
+        1, GSIGNOND_TYPE_SESSION_DATA);
 
     signals[STORE] = g_signal_new ("store", G_TYPE_FROM_CLASS (g_class),
         G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE,
-        1, G_TYPE_VARIANT);
+        1, GSIGNOND_TYPE_SESSION_DATA);
 
     signals[ERROR] = g_signal_new ("error", G_TYPE_FROM_CLASS (g_class),
         G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE,
-        1, G_TYPE_INT);
+        1, G_TYPE_ERROR);
     
-    signals[USER_ACTION_REQUIRED] = g_signal_new ("user-action-required", G_TYPE_FROM_CLASS (g_class),
+    signals[USER_ACTION_REQUIRED] = g_signal_new ("user-action-required", 
+        G_TYPE_FROM_CLASS (g_class),
         G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE,
-        1, G_TYPE_VARIANT);
+        1, GSIGNOND_TYPE_SESSION_DATA);
 
     signals[REFRESHED] = g_signal_new ("refreshed", G_TYPE_FROM_CLASS (g_class),
         G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE,
-        1, G_TYPE_VARIANT);
+        1, GSIGNOND_TYPE_SESSION_DATA);
 
-    signals[STATUS_CHANGED] = g_signal_new ("status-changed", G_TYPE_FROM_CLASS (g_class),
+    signals[STATUS_CHANGED] = g_signal_new ("status-changed", 
+        G_TYPE_FROM_CLASS (g_class),
         G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE,
         2, G_TYPE_STRING, G_TYPE_STRING);
 
     g_object_interface_install_property (g_class,
-       g_param_spec_string ("type", "Type", "Plugin type", "none", G_PARAM_READABLE));
+       g_param_spec_string ("type", "Type", "Plugin type", "none", 
+                             G_PARAM_READABLE));
 
      g_object_interface_install_property (g_class,
-        g_param_spec_boxed ("mechanisms", "Mechanisms", "List of plugin mechanisms", G_TYPE_STRV, G_PARAM_READABLE));
+        g_param_spec_boxed ("mechanisms", "Mechanisms", 
+                            "List of plugin mechanisms", 
+                            G_TYPE_STRV, G_PARAM_READABLE));
     
 }
 
@@ -90,53 +95,63 @@ void gsignond_plugin_abort (GSignondPlugin *self)
     GSIGNOND_PLUGIN_GET_INTERFACE (self)->abort (self);
 }
 
-void gsignond_plugin_process (GSignondPlugin *self, const GVariant *session_data, const gchar *mechanism)
+void gsignond_plugin_process (GSignondPlugin *self, 
+                              GSignondSessionData *session_data, 
+                              const gchar *mechanism)
 {
     g_return_if_fail (GSIGNOND_IS_PLUGIN (self));
     
     GSIGNOND_PLUGIN_GET_INTERFACE (self)->process (self, session_data, mechanism);
 }
 
-void gsignond_plugin_user_action_finished (GSignondPlugin *self, const GVariant *session_data)
+void gsignond_plugin_user_action_finished (GSignondPlugin *self, 
+                                           GSignondSessionData *session_data)
 {
     g_return_if_fail (GSIGNOND_IS_PLUGIN (self));
     
-    GSIGNOND_PLUGIN_GET_INTERFACE (self)->user_action_finished (self, session_data);
+    GSIGNOND_PLUGIN_GET_INTERFACE (self)->user_action_finished (self, 
+                                                                session_data);
 }
 
-void gsignond_plugin_refresh (GSignondPlugin *self, const GVariant *session_data)
+void gsignond_plugin_refresh (GSignondPlugin *self, 
+                              GSignondSessionData *session_data)
 {
     g_return_if_fail (GSIGNOND_IS_PLUGIN (self));
     
     GSIGNOND_PLUGIN_GET_INTERFACE (self)->refresh (self, session_data);
 }
 
-void gsignond_plugin_result (GSignondPlugin *self, const GVariant *session_data)
+void gsignond_plugin_result (GSignondPlugin *self, 
+                             GSignondSessionData *session_data)
 {
     g_signal_emit (self, signals[RESULT], 0, session_data);
 }
 
-void gsignond_plugin_store (GSignondPlugin *self, const GVariant *session_data)
+void gsignond_plugin_store (GSignondPlugin *self, 
+                            GSignondSessionData *session_data)
 {
     g_signal_emit (self, signals[STORE], 0, session_data);
 }
 
-void gsignond_plugin_error (GSignondPlugin *self, int error)
+void gsignond_plugin_error (GSignondPlugin *self, GError *error)
 {
     g_signal_emit (self, signals[ERROR], 0, error);
 }
 
-void gsignond_plugin_user_action_required (GSignondPlugin *self, const GVariant *session_data)
+void gsignond_plugin_user_action_required (GSignondPlugin *self, 
+                                           GSignondSessionData *session_data)
 {
     g_signal_emit (self, signals[USER_ACTION_REQUIRED], 0, session_data);
 }
 
-void gsignond_plugin_refreshed (GSignondPlugin *self, const GVariant *session_data)
+void gsignond_plugin_refreshed (GSignondPlugin *self, 
+                                GSignondSessionData *session_data)
 {
     g_signal_emit (self, signals[REFRESHED], 0, session_data);
 }
 
-void gsignond_plugin_status_changed (GSignondPlugin *self, const gchar *status, const gchar *message)
+void gsignond_plugin_status_changed (GSignondPlugin *self, const gchar *status, 
+                                     const gchar *message)
 {
     g_signal_emit (self, signals[STATUS_CHANGED], 0, status, message);
 }
diff --git a/src/common/gsignond-session-data.c b/src/common/gsignond-session-data.c
new file mode 100644 (file)
index 0000000..a8e7b74
--- /dev/null
@@ -0,0 +1,110 @@
+/* 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 Intel Corporation.
+ *
+ * Contact: Alexander Kanavin <alex.kanavin@gmail.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 <gsignond/gsignond-session-data.h>
+
+const gchar*
+gsignond_session_data_get_username(GSignondSessionData* data)
+{
+    GVariant* variant = gsignond_dictionary_get(data, "username");
+    if (variant == NULL)
+        return NULL;
+    return g_variant_get_string(variant, NULL);
+}
+
+void
+gsignond_session_data_set_username(GSignondSessionData* data, 
+                                   const gchar* username)
+{
+    gsignond_dictionary_set(data, "username", g_variant_new_string(username));
+}
+
+const gchar*
+gsignond_session_data_get_secret(GSignondSessionData* data)
+{
+    GVariant* variant = gsignond_dictionary_get(data, "secret");
+    if (variant == NULL)
+        return NULL;
+    return g_variant_get_string(variant, NULL);
+    
+}
+
+void
+gsignond_session_data_set_secret(GSignondSessionData* data, 
+                                 const gchar* secret)
+{
+    gsignond_dictionary_set(data, "secret", g_variant_new_string(secret));
+}
+
+gboolean
+gsignond_session_data_get_query_username(GSignondSessionData* data)
+{
+    GVariant* variant = gsignond_dictionary_get(data, "query_username");
+    if (variant == NULL)
+        return FALSE;
+    return g_variant_get_boolean(variant);
+}
+
+void
+gsignond_session_data_set_query_username(GSignondSessionData* data, 
+                                         gboolean query_username)
+{
+    gsignond_dictionary_set(data, "query_username", 
+                            g_variant_new_boolean(query_username));
+}    
+
+gboolean
+gsignond_session_data_get_query_password(GSignondSessionData* data)
+{
+    GVariant* variant = gsignond_dictionary_get(data, "query_password");
+    if (variant == NULL)
+        return FALSE;
+    return g_variant_get_boolean(variant);
+}    
+
+void
+gsignond_session_data_set_query_password(GSignondSessionData* data, 
+                                         gboolean query_password)
+{
+    gsignond_dictionary_set(data, "query_password", 
+                            g_variant_new_boolean(query_password));
+}    
+
+GSignondQueryError gsignond_session_data_get_query_error(
+    GSignondSessionData* data)
+{
+    GVariant* variant = gsignond_dictionary_get(data, "query_error");
+    if (variant == NULL)
+        return GSIGNOND_QUERY_ERROR_NONE;
+    return g_variant_get_int32(variant);
+}    
+
+void
+gsignond_session_data_set_query_error(GSignondSessionData* data, 
+                                         GSignondQueryError error)
+{
+    gsignond_dictionary_set(data, "query_error", 
+                            g_variant_new_int32(error));
+}
index ac6c157..457229f 100644 (file)
@@ -8,8 +8,9 @@ libpasswordplugin_la_CPPFLAGS = \
     $(GSIGNOND_CFLAGS) \
     $(NULL)
 
-libpasswordplugin_la_LIBS = \
-    $(GSIGNOND_LIBS)
+libpasswordplugin_la_LIBADD = \
+    $(top_builddir)/src/common/libgsignond-common.la \
+    $(GSIGNOND_LIBS) \
     $(NULL)
 
 libpasswordplugin_la_SOURCES = \
index 0483e8a..2388d59 100644 (file)
 
 #include <gsignond/gsignond-plugin-interface.h>
 #include "gsignond-password-plugin.h"
+#include <gsignond/gsignond-error.h>
 
 static void gsignond_plugin_interface_init (GSignondPluginInterface *iface);
 
-G_DEFINE_TYPE_WITH_CODE (GSignondPasswordPlugin, gsignond_password_plugin, G_TYPE_OBJECT,
+G_DEFINE_TYPE_WITH_CODE (GSignondPasswordPlugin, gsignond_password_plugin, 
+                         G_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (GSIGNOND_TYPE_PLUGIN,
                                                 gsignond_plugin_interface_init));
 
 static void gsignond_password_plugin_cancel (GSignondPlugin *self)
 {
-//  g_print ("Baz implementation of Ibaz interface Action: 0x%x.\n",
-//           self->instance_member);
+    GError* error = g_error_new(GSIGNOND_ERROR, 
+                                GSIGNOND_ERROR_SESSION_CANCELED,
+                                "Session canceled");
+    gsignond_plugin_error (self, error); 
+    g_error_free(error);
 }
 
 static void gsignond_password_plugin_abort (GSignondPlugin *self)
@@ -43,19 +48,74 @@ static void gsignond_password_plugin_abort (GSignondPlugin *self)
     
 }
 
-static void gsignond_password_plugin_process (GSignondPlugin *self, const GVariant *session_data, const gchar *mechanism)
+static void gsignond_password_plugin_process (
+    GSignondPlugin *self, GSignondSessionData *session_data, 
+    const gchar *mechanism)
 {
+    const gchar* username = gsignond_session_data_get_username(session_data);
+    const gchar* secret = gsignond_session_data_get_secret(session_data);
     
+    if (secret != NULL) {
+        GSignondSessionData *response = gsignond_dictionary_new();
+        if (username != NULL)
+            gsignond_session_data_set_username(response, username);
+        gsignond_session_data_set_secret(response, secret);
+        gsignond_plugin_result(self, response);
+        gsignond_dictionary_free(response);
+        return;
+    }
+    
+    GSignondSessionData *user_action_data = gsignond_dictionary_new();
+    if (username == NULL)
+        gsignond_session_data_set_query_username(user_action_data, TRUE);
+    else
+        gsignond_session_data_set_username(user_action_data, username);
+    gsignond_session_data_set_query_password(user_action_data, TRUE);
+    gsignond_plugin_user_action_required(self, user_action_data);
+    gsignond_dictionary_free(user_action_data);
 }
 
-static void gsignond_password_plugin_user_action_finished (GSignondPlugin *self, const GVariant *session_data)
+static void gsignond_password_plugin_user_action_finished (
+    GSignondPlugin *self, 
+    GSignondSessionData *session_data)
 {
+    GSignondQueryError query_error = gsignond_session_data_get_query_error(
+        session_data);
+    const gchar* username = gsignond_session_data_get_username(session_data);
+    const gchar* secret = gsignond_session_data_get_secret(session_data);
     
+    if (query_error == GSIGNOND_QUERY_ERROR_NONE && 
+        username != NULL && 
+        secret != NULL) {
+        GSignondSessionData *response = gsignond_dictionary_new();
+        gsignond_session_data_set_username(response, username);
+        gsignond_session_data_set_secret(response, secret);
+        gsignond_plugin_result(self, response);
+        gsignond_dictionary_free(response);
+        return;
+    } else if (query_error == GSIGNOND_QUERY_ERROR_CANCELED) {
+        GError* error = g_error_new(GSIGNOND_ERROR, 
+                                GSIGNOND_ERROR_SESSION_CANCELED,
+                                "Session canceled");
+        gsignond_plugin_error (self, error); 
+        g_error_free(error);
+    } else {
+        gchar* error_message = g_strdup_printf("userActionFinished error: %d",
+                                               query_error);
+        GError* error = g_error_new(GSIGNOND_ERROR, 
+                                GSIGNOND_ERROR_USER_INTERACTION,
+                                error_message);
+        gsignond_plugin_error (self, error); 
+        g_free(error_message);
+        g_error_free(error);
+    }
 }
 
-static void gsignond_password_plugin_refresh (GSignondPlugin *self, const GVariant *session_data)
+static void gsignond_password_plugin_refresh (
+    GSignondPlugin *self, 
+    GSignondSessionData *session_data)
 {
-    
+    gsignond_plugin_refreshed(self, session_data);
 }
 
 static void
@@ -85,39 +145,39 @@ enum
 
 static void
 gsignond_password_plugin_set_property (GObject      *object,
-                                      guint         property_id,
-                                      const GValue *value,
-                                      GParamSpec   *pspec)
+                                       guint         property_id,
+                                       const GValue *value,
+                                       GParamSpec   *pspec)
 {
     switch (property_id)
     {
-       default:
-           G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-           break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+            break;
     }
 }
 
 static void
 gsignond_password_plugin_get_property (GObject    *object,
-                                      guint       prop_id,
-                                      GValue     *value,
-                                      GParamSpec *pspec)
+                                       guint       prop_id,
+                                       GValue     *value,
+                                       GParamSpec *pspec)
 {
     GSignondPasswordPlugin *password_plugin = GSIGNOND_PASSWORD_PLUGIN (object);
     gchar *mechanisms[] = { "password", NULL };
     
     switch (prop_id)
     {
-       case PROP_TYPE:
-           g_value_set_string (value, "password");
-           break;
-       case PROP_MECHANISMS:
-           g_value_set_boxed (value, mechanisms);
-           break;
-           
-       default:
-           G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-           break;
+        case PROP_TYPE:
+            g_value_set_string (value, "password");
+            break;
+        case PROP_MECHANISMS:
+            g_value_set_boxed (value, mechanisms);
+            break;
+            
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+            break;
     }
 }
 
@@ -130,5 +190,6 @@ gsignond_password_plugin_class_init (GSignondPasswordPluginClass *klass)
     gobject_class->get_property = gsignond_password_plugin_get_property;
     
     g_object_class_override_property (gobject_class, PROP_TYPE, "type");
-    g_object_class_override_property (gobject_class, PROP_MECHANISMS, "mechanisms");
+    g_object_class_override_property (gobject_class, PROP_MECHANISMS, 
+                                      "mechanisms");
 }
\ No newline at end of file
index 3708d61..c9047b2 100644 (file)
@@ -1 +1 @@
-SUBDIRS = db
+SUBDIRS = db passwordplugin
diff --git a/test/passwordplugin/Makefile.am b/test/passwordplugin/Makefile.am
new file mode 100644 (file)
index 0000000..10f5e93
--- /dev/null
@@ -0,0 +1,14 @@
+TESTS = passwordplugintest
+check_PROGRAMS = passwordplugintest
+passwordplugintest_SOURCES = passwordplugintest.c
+passwordplugintest_CFLAGS = \
+    $(GSIGNOND_CFLAGS) \
+    $(CHECK_CFLAGS) \
+    -I$(top_srcdir)/src/plugins/password \
+    -I$(top_srcdir)/include/ 
+
+passwordplugintest_LDADD = \
+    $(top_builddir)/src/common/libgsignond-common.la \
+    $(top_builddir)/src/plugins/password/libpasswordplugin.la \
+    $(GSIGNOND_LIBS) \
+    $(CHECK_LIBS)
\ No newline at end of file
diff --git a/test/passwordplugin/passwordplugintest.c b/test/passwordplugin/passwordplugintest.c
new file mode 100644 (file)
index 0000000..c1b5384
--- /dev/null
@@ -0,0 +1,333 @@
+/* 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 Intel Corporation.
+ *
+ * Contact: Alexander Kanavin <alex.kanavin@gmail.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-password-plugin.h"
+#include <gsignond/gsignond-session-data.h>
+#include <gsignond/gsignond-plugin-interface.h>
+#include <gsignond/gsignond-error.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);
+    fail_unless(gsignond_session_data_get_query_username(data) == FALSE);
+    fail_unless(gsignond_session_data_get_query_password(data) == FALSE);
+
+    gsignond_session_data_set_username(data, "megauser");
+    gsignond_session_data_set_secret(data, "megapassword");
+    gsignond_session_data_set_query_username(data, TRUE);
+    gsignond_session_data_set_query_password(data, TRUE);
+    
+    fail_unless(g_strcmp0(gsignond_session_data_get_username(data), 
+                          "megauser") == 0);
+    fail_unless(g_strcmp0(gsignond_session_data_get_secret(data), 
+                          "megapassword") == 0);
+    fail_unless(gsignond_session_data_get_query_username(data) == TRUE);
+    fail_unless(gsignond_session_data_get_query_password(data) == TRUE);    
+
+    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);
+    fail_unless(gsignond_session_data_get_query_username(data_from_copy) == TRUE);
+    fail_unless(gsignond_session_data_get_query_password(data_from_copy) == TRUE);    
+
+    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);
+    fail_unless(gsignond_session_data_get_query_username(data_from_variant) == TRUE);
+    fail_unless(gsignond_session_data_get_query_password(data_from_variant) == TRUE);    
+    
+    g_variant_unref(variant);
+    gsignond_dictionary_free(data_from_variant);
+    gsignond_dictionary_free(data_from_copy);
+    gsignond_dictionary_free(data);
+}
+END_TEST
+
+START_TEST (test_passwordplugin_create)
+{
+    gpointer plugin;
+    gchar* type;
+    gchar** mechanisms;
+    
+    plugin = g_object_new(GSIGNOND_TYPE_PASSWORD_PLUGIN, NULL);
+    fail_if(plugin == NULL);
+    
+    g_object_get(plugin, "type", &type, "mechanisms", &mechanisms, NULL);
+    
+    fail_unless(g_strcmp0(type, "password") == 0);
+    fail_unless(g_strcmp0(mechanisms[0], "password") == 0);
+    fail_unless(mechanisms[1] == NULL);
+    
+    g_free(type);
+    g_strfreev(mechanisms);
+    g_object_unref(plugin);
+}
+END_TEST
+
+static void result_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, 
+                                          GSignondSessionData* ui_request, 
+                                          gpointer user_data)
+{
+    GSignondSessionData** user_data_p = user_data;
+    *user_data_p = gsignond_dictionary_copy(ui_request);
+}
+
+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_passwordplugin_process)
+{
+    gpointer plugin;
+    
+    plugin = g_object_new(GSIGNOND_TYPE_PASSWORD_PLUGIN, NULL);
+    fail_if(plugin == NULL);
+
+    GSignondSessionData* result = NULL;
+    GSignondSessionData* ui_action = NULL;
+    GError* error = NULL;
+
+    g_signal_connect(plugin, "result", G_CALLBACK(result_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();
+
+    // username empty, password not empty
+    gsignond_session_data_set_secret(data, "megapassword");
+    gsignond_plugin_process(plugin, data, "password");
+    fail_if(result == NULL);    
+    fail_if(ui_action != NULL);
+    fail_if(error != NULL);
+    fail_if(gsignond_session_data_get_username(result) != NULL);
+    fail_if(g_strcmp0(
+        gsignond_session_data_get_secret(result), "megapassword") != 0);
+    gsignond_dictionary_free(result);
+    result = NULL;
+    
+    // username and password not empty
+    gsignond_session_data_set_username(data, "megauser");
+    gsignond_plugin_process(plugin, data, "password");
+    fail_if(result == NULL);    
+    fail_if(ui_action != NULL);
+    fail_if(error != NULL);
+    fail_if(g_strcmp0(
+        gsignond_session_data_get_username(result), "megauser") != 0);
+    fail_if(g_strcmp0(
+        gsignond_session_data_get_secret(result), "megapassword") != 0);
+    gsignond_dictionary_free(result);
+    result = NULL;
+    
+    //username and password empty
+    gsignond_dictionary_free(data);
+    data = gsignond_dictionary_new();
+    gsignond_plugin_process(plugin, data, "password");
+    fail_if(result != NULL);    
+    fail_if(ui_action == NULL);
+    fail_if(error != NULL);
+    fail_if(gsignond_session_data_get_query_username(ui_action) == FALSE);
+    fail_if(gsignond_session_data_get_query_password(ui_action) == FALSE);
+    gsignond_dictionary_free(ui_action);
+    ui_action = NULL;
+    
+    //username not empty, password empty
+    gsignond_session_data_set_username(data, "megauser");
+    gsignond_plugin_process(plugin, data, "password");
+    fail_if(result != NULL);    
+    fail_if(ui_action == NULL);
+    fail_if(error != NULL);
+    fail_if(gsignond_session_data_get_query_username(ui_action) == TRUE);
+    fail_if(gsignond_session_data_get_query_password(ui_action) == FALSE);
+    gsignond_dictionary_free(ui_action);
+    ui_action = NULL;
+    
+    gsignond_dictionary_free(data);
+    g_object_unref(plugin);
+}
+END_TEST
+
+START_TEST (test_passwordplugin_user_action_finished)
+{
+    gpointer plugin;
+    
+    plugin = g_object_new(GSIGNOND_TYPE_PASSWORD_PLUGIN, NULL);
+    fail_if(plugin == NULL);
+
+    GSignondSessionData* result = NULL;
+    GSignondSessionData* ui_action = NULL;
+    GError* error = NULL;
+
+    g_signal_connect(plugin, "result", G_CALLBACK(result_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();
+    
+    //empty data
+    gsignond_plugin_user_action_finished(plugin, 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
+    gsignond_session_data_set_username(data, "megauser");
+    gsignond_session_data_set_secret(data, "megapassword");
+    gsignond_session_data_set_query_error(data, GSIGNOND_QUERY_ERROR_NONE);
+    gsignond_plugin_user_action_finished(plugin, data);
+    fail_if(result == NULL);    
+    fail_if(ui_action != NULL);
+    fail_if(error != NULL);
+    fail_if(g_strcmp0(
+        gsignond_session_data_get_username(result), "megauser") != 0);
+    fail_if(g_strcmp0(
+        gsignond_session_data_get_secret(result), "megapassword") != 0);
+    gsignond_dictionary_free(result);
+    result = NULL;
+
+    // user canceled
+    gsignond_session_data_set_query_error(data, GSIGNOND_QUERY_ERROR_CANCELED);
+    gsignond_plugin_user_action_finished(plugin, 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_session_data_set_query_error(data, GSIGNOND_QUERY_ERROR_GENERAL);
+    gsignond_plugin_user_action_finished(plugin, 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;
+    
+    gsignond_dictionary_free(data);
+    g_object_unref(plugin);
+}
+END_TEST
+
+START_TEST (test_passwordplugin_refresh)
+{
+    gpointer plugin;
+    
+    plugin = g_object_new(GSIGNOND_TYPE_PASSWORD_PLUGIN, NULL);
+    fail_if(plugin == NULL);
+
+    GSignondSessionData* result = NULL;
+    GError* error = NULL;
+
+    g_signal_connect(plugin, "refreshed", G_CALLBACK(result_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_free(result);
+    result = NULL;
+    
+    gsignond_dictionary_free(data);
+    g_object_unref(plugin);
+}
+END_TEST
+
+
+Suite* passwordplugin_suite (void)
+{
+    Suite *s = suite_create ("Password plugin");
+    
+    /* Core test case */
+    TCase *tc_core = tcase_create ("Tests");
+    tcase_add_test (tc_core, test_session_data);
+    tcase_add_test (tc_core, test_passwordplugin_create);
+    tcase_add_test (tc_core, test_passwordplugin_process);
+    tcase_add_test (tc_core, test_passwordplugin_user_action_finished);
+    tcase_add_test (tc_core, test_passwordplugin_refresh);
+    suite_add_tcase (s, tc_core);
+    return s;
+}
+
+int main (void)
+{
+    int number_failed;
+    
+    g_type_init();
+    
+    Suite *s = passwordplugin_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;
+}
+  
\ No newline at end of file