From 6b4d7b648415df0f9b86bd6b752cf4c080ab783f Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Sun, 25 Sep 2011 22:59:43 +0200 Subject: [PATCH] Testing of gsecret_service_ensure and friends --- Makefile.am | 5 +- library/gsecret-service.c | 53 +++++++-- library/gsecret-service.h | 4 + library/tests/mock-service-only-plain.py | 7 ++ library/tests/mock/service.py | 19 +++- library/tests/test-session.c | 138 +++++++++++++++++++++-- po/gsecret.pot | 6 +- 7 files changed, 204 insertions(+), 28 deletions(-) create mode 100644 library/tests/mock-service-only-plain.py diff --git a/Makefile.am b/Makefile.am index 05042e1..c4087b9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,16 +24,15 @@ dist-hook: fi if WITH_COVERAGE -check-coverage: clear-coverage check coverage - coverage: mkdir -p coverage $(LCOV) --directory . --capture --output-file coverage/coverage.info - $(GENHTML) --output-directory coverage/coverage coverage/coverage.info + $(GENHTML) --output-directory coverage coverage/coverage.info $(LCOV) --directory . --zerocounters @echo "file://$(abs_top_builddir)/coverage/index.html" clear-coverage: $(LCOV) --directory . --zerocounters +.PHONY: coverage endif diff --git a/library/gsecret-service.c b/library/gsecret-service.c index bb84178..35cf5f5 100644 --- a/library/gsecret-service.c +++ b/library/gsecret-service.c @@ -34,8 +34,12 @@ EGG_SECURE_GLIB_DEFINITIONS (); EGG_SECURE_DECLARE (secret_service); +#define ALGORITHMS_AES "dh-ietf1024-sha256-aes128-cbc-pkcs7" +#define ALGORITHMS_PLAIN "plain" + typedef struct { gchar *path; + const gchar *algorithms; #ifdef WITH_GCRYPT gcry_mpi_t prime; gcry_mpi_t privat; @@ -156,6 +160,28 @@ _gsecret_service_bare_instance (GDBusConnection *connection, return service; } +const gchar * +gsecret_service_get_session_algorithms (GSecretService *self) +{ + GSecretSession *session; + + g_return_val_if_fail (GSECRET_IS_SERVICE (self), NULL); + + session = g_atomic_pointer_get (&self->pv->session); + return session ? session->algorithms : NULL; +} + +const gchar * +gsecret_service_get_session_path (GSecretService *self) +{ + GSecretSession *session; + + g_return_val_if_fail (GSECRET_IS_SERVICE (self), NULL); + + session = g_atomic_pointer_get (&self->pv->session); + return session ? session->path : NULL; +} + #ifdef WITH_GCRYPT static GVariant * @@ -186,7 +212,7 @@ request_open_session_aes (GSecretSession *session) buffer, n_buffer, TRUE, gcry_free, buffer); - return g_variant_new ("sv", "dh-ietf1024-sha256-aes128-cbc-pkcs7", argument); + return g_variant_new ("(sv)", ALGORITHMS_AES, argument); } static gboolean @@ -195,20 +221,23 @@ response_open_session_aes (GSecretSession *session, { gconstpointer buffer; GVariant *argument; + const gchar *sig; gsize n_buffer; gcry_mpi_t peer; gcry_error_t gcry; gpointer ikm; gsize n_ikm; - if (G_VARIANT_TYPE ("vo") != g_variant_get_type (response)) { - g_warning ("invalid OpenSession() response from daemon with signature: %s", - g_variant_get_type_string (response)); + sig = g_variant_get_type_string (response); + g_return_val_if_fail (sig != NULL, FALSE); + + if (!g_str_equal (sig, "(vo)")) { + g_warning ("invalid OpenSession() response from daemon with signature: %s", sig); return FALSE; } g_assert (session->path == NULL); - g_variant_get (response, "vo", &argument, &session->path); + g_variant_get (response, "(vo)", &argument, &session->path); buffer = g_variant_get_fixed_array (argument, &n_buffer, sizeof (guchar)); gcry = gcry_mpi_scan (&peer, GCRYMPI_FMT_USG, buffer, n_buffer, NULL); @@ -232,6 +261,7 @@ response_open_session_aes (GSecretSession *session, g_return_val_if_reached (FALSE); egg_secure_free (ikm); + session->algorithms = ALGORITHMS_AES; return TRUE; } @@ -241,7 +271,7 @@ static GVariant * request_open_session_plain (GSecretSession *session) { GVariant *argument = g_variant_new_string (""); - return g_variant_new ("sv", "plain", argument); + return g_variant_new ("(sv)", "plain", argument); } static gboolean @@ -249,20 +279,25 @@ response_open_session_plain (GSecretSession *session, GVariant *response) { GVariant *argument; + const gchar *sig; - if (G_VARIANT_TYPE ("vo") != g_variant_get_type (response)) { + sig = g_variant_get_type_string (response); + g_return_val_if_fail (sig != NULL, FALSE); + + if (!g_str_equal (sig, "(vo)")) { g_warning ("invalid OpenSession() response from daemon with signature: %s", g_variant_get_type_string (response)); return FALSE; } g_assert (session->path == NULL); - g_variant_get (response, "vo", &argument, &session->path); + g_variant_get (response, "(vo)", &argument, &session->path); g_variant_unref (argument); g_assert (session->key == NULL); g_assert (session->n_key == 0); + session->algorithms = ALGORITHMS_PLAIN; return TRUE; } @@ -395,7 +430,7 @@ gsecret_service_ensure_session (GSecretService *self, closure = g_new (OpenSessionClosure, 1); closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable; - closure->session = g_new (GSecretSession, 1); + closure->session = g_new0 (GSecretSession, 1); g_simple_async_result_set_op_res_gpointer (res, closure, open_session_closure_free); g_dbus_proxy_call (G_DBUS_PROXY (self), "OpenSession", diff --git a/library/gsecret-service.h b/library/gsecret-service.h index 5a00df5..5f8ec25 100644 --- a/library/gsecret-service.h +++ b/library/gsecret-service.h @@ -72,6 +72,10 @@ GSecretService * gsecret_service_instance_sync (GDBusConnection *c GError **error); #endif +const gchar * gsecret_service_get_session_algorithms (GSecretService *self); + +const gchar * gsecret_service_get_session_path (GSecretService *self); + void gsecret_service_ensure_session (GSecretService *self, GCancellable *cancellable, GAsyncReadyCallback callback, diff --git a/library/tests/mock-service-only-plain.py b/library/tests/mock-service-only-plain.py new file mode 100644 index 0000000..e06b9ba --- /dev/null +++ b/library/tests/mock-service-only-plain.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +import mock + +service = mock.SecretService() +service.algorithms = { "plain": mock.PlainAlgorithm() } +service.listen() \ No newline at end of file diff --git a/library/tests/mock/service.py b/library/tests/mock/service.py index 5547ff1..4b5db12 100644 --- a/library/tests/mock/service.py +++ b/library/tests/mock/service.py @@ -31,6 +31,10 @@ class NotSupported(dbus.exceptions.DBusException): def __init__(self, msg): dbus.exceptions.DBusException.__init__(self, msg, name="org.freedesktop.DBus.Error.NotSupported") +class InvalidArgs(dbus.exceptions.DBusException): + def __init__(self, msg): + dbus.exceptions.DBusException.__init__(self, msg, name="org.freedesktop.DBus.Error.InvalidArgs") + unique_identifier = 0 def next_identifier(): global unique_identifier @@ -39,11 +43,15 @@ def next_identifier(): class PlainAlgorithm(): def negotiate(self, service, sender, param): + if type (param) != dbus.String: + raise InvalidArgs("invalid argument passed to OpenSession") session = SecretSession(service, sender, None) return (dbus.String("", variant_level=1), session) class AesAlgorithm(): def negotiate(self, service, sender, param): + if type (param) != dbus.ByteArray: + raise InvalidArgs("invalid argument passed to OpenSession") publi, privat = dh.generate_pair() peer = dh.bytes_to_number(param) ikm = dh.derive_key(privat, peer) @@ -72,9 +80,11 @@ class SecretService(dbus.service.Object): "dh-ietf1024-sha256-aes128-cbc-pkcs7": AesAlgorithm(), } - def __init__(self, name=bus_name): - bus = bus = dbus.SessionBus() - self.bus_name = dbus.service.BusName(name) + def __init__(self, name=None): + if name == None: + name = bus_name + bus = dbus.SessionBus() + self.bus_name = dbus.service.BusName(name, allow_replacement=True, replace_existing=True) dbus.service.Object.__init__(self, self.bus_name, '/org/freedesktop/secrets') self.sessions = { } @@ -102,7 +112,6 @@ class SecretService(dbus.service.Object): @dbus.service.method('org.freedesktop.Secret.Service', byte_arrays=True, sender_keyword='sender') def OpenSession(self, algorithm, param, sender=None): assert type(algorithm) == dbus.String - assert type(param) == dbus.ByteArray if algorithm not in self.algorithms: raise NotSupported("algorithm %s is not supported" % algorithm) @@ -123,4 +132,4 @@ def parse_options(args): assert False, "unhandled option" return args -parse_options(sys.argv[1:]) \ No newline at end of file +parse_options(sys.argv[1:]) diff --git a/library/tests/test-session.c b/library/tests/test-session.c index ee47c1a..e68649e 100644 --- a/library/tests/test-session.c +++ b/library/tests/test-session.c @@ -17,6 +17,8 @@ #include "gsecret-service.h" #include "gsecret-private.h" +#include "egg/egg-testing.h" + #include #include @@ -31,18 +33,20 @@ typedef struct { } Test; static void -setup_normal (Test *test, - gconstpointer unused) +setup (Test *test, + gconstpointer data) { GError *error = NULL; + const gchar *mock_script = data; gchar *argv[] = { - "python", "./mock-service-normal.py", + "python", (gchar *)mock_script, "--name", MOCK_NAME, NULL }; g_spawn_async (SRCDIR, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &test->pid, &error); g_assert_no_error (error); + g_usleep (100 * 1000); test->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); g_assert_no_error (error); @@ -64,16 +68,130 @@ teardown (Test *test, } static void -test_ensure_sync (Test *test, - gconstpointer unused) +test_ensure (Test *test, + gconstpointer unused) { GError *error = NULL; const gchar *path; + g_assert_cmpstr (gsecret_service_get_session_path (test->service), ==, NULL); + g_assert_cmpstr (gsecret_service_get_session_algorithms (test->service), ==, NULL); + path = gsecret_service_ensure_session_sync (test->service, NULL, &error); g_assert_no_error (error); g_assert (path != NULL); - g_printerr ("%s", path); + g_assert_cmpstr (gsecret_service_get_session_path (test->service), ==, path); + g_assert_cmpstr (gsecret_service_get_session_algorithms (test->service), ==, "dh-ietf1024-sha256-aes128-cbc-pkcs7"); +} + +static void +test_ensure_twice (Test *test, + gconstpointer unused) +{ + GError *error = NULL; + const gchar *path; + + g_assert_cmpstr (gsecret_service_get_session_path (test->service), ==, NULL); + g_assert_cmpstr (gsecret_service_get_session_algorithms (test->service), ==, NULL); + + path = gsecret_service_ensure_session_sync (test->service, NULL, &error); + g_assert_no_error (error); + g_assert (path != NULL); + g_assert_cmpstr (gsecret_service_get_session_path (test->service), ==, path); + g_assert_cmpstr (gsecret_service_get_session_algorithms (test->service), ==, "dh-ietf1024-sha256-aes128-cbc-pkcs7"); + + path = gsecret_service_ensure_session_sync (test->service, NULL, &error); + g_assert_no_error (error); + g_assert (path != NULL); + g_assert_cmpstr (gsecret_service_get_session_path (test->service), ==, path); + g_assert_cmpstr (gsecret_service_get_session_algorithms (test->service), ==, "dh-ietf1024-sha256-aes128-cbc-pkcs7"); +} + +static void +test_ensure_plain (Test *test, + gconstpointer unused) +{ + GError *error = NULL; + const gchar *path; + + g_assert_cmpstr (gsecret_service_get_session_path (test->service), ==, NULL); + g_assert_cmpstr (gsecret_service_get_session_algorithms (test->service), ==, NULL); + + path = gsecret_service_ensure_session_sync (test->service, NULL, &error); + g_assert_no_error (error); + + g_assert (path != NULL); + g_assert_cmpstr (gsecret_service_get_session_path (test->service), ==, path); + g_assert_cmpstr (gsecret_service_get_session_algorithms (test->service), ==, "plain"); +} + +static void +on_complete_get_result (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GAsyncResult **ret = user_data; + g_assert (ret != NULL); + g_assert (*ret == NULL); + *ret = g_object_ref (result); +} + +static void +test_ensure_async (Test *test, + gconstpointer unused) +{ + GAsyncResult *result = NULL; + GError *error = NULL; + const gchar *path; + + gsecret_service_ensure_session (test->service, NULL, on_complete_get_result, &result); + egg_test_wait_until (500); + + g_assert (G_IS_ASYNC_RESULT (result)); + path = gsecret_service_ensure_session_finish (test->service, result, &error); + g_assert_no_error (error); + + g_assert (path != NULL); + g_assert_cmpstr (gsecret_service_get_session_path (test->service), ==, path); + g_assert_cmpstr (gsecret_service_get_session_algorithms (test->service), ==, "plain"); + + g_object_unref (result); +} + +static void +test_ensure_async_twice (Test *test, + gconstpointer unused) +{ + GAsyncResult *result = NULL; + GError *error = NULL; + const gchar *path; + + gsecret_service_ensure_session (test->service, NULL, on_complete_get_result, &result); + egg_test_wait_until (500); + + g_assert (G_IS_ASYNC_RESULT (result)); + path = gsecret_service_ensure_session_finish (test->service, result, &error); + g_assert_no_error (error); + + g_assert (path != NULL); + g_assert_cmpstr (gsecret_service_get_session_path (test->service), ==, path); + g_assert_cmpstr (gsecret_service_get_session_algorithms (test->service), ==, "plain"); + + g_object_unref (result); + result = NULL; + + gsecret_service_ensure_session (test->service, NULL, on_complete_get_result, &result); + egg_test_wait_until (500); + + g_assert (G_IS_ASYNC_RESULT (result)); + path = gsecret_service_ensure_session_finish (test->service, result, &error); + g_assert_no_error (error); + + g_assert (path != NULL); + g_assert_cmpstr (gsecret_service_get_session_path (test->service), ==, path); + g_assert_cmpstr (gsecret_service_get_session_algorithms (test->service), ==, "plain"); + + g_object_unref (result); } int @@ -83,7 +201,11 @@ main (int argc, char **argv) g_set_prgname ("test-session"); g_type_init (); - g_test_add ("/session/ensure-sync", Test, NULL, setup_normal, test_ensure_sync, teardown); + g_test_add ("/session/ensure-aes", Test, "mock-service-normal.py", setup, test_ensure, teardown); + g_test_add ("/session/ensure-twice", Test, "mock-service-normal.py", setup, test_ensure_twice, teardown); + g_test_add ("/session/ensure-plain", Test, "mock-service-only-plain.py", setup, test_ensure_plain, teardown); + g_test_add ("/session/ensure-async", Test, "mock-service-only-plain.py", setup, test_ensure_async, teardown); + g_test_add ("/session/ensure-async-twice", Test, "mock-service-only-plain.py", setup, test_ensure_async_twice, teardown); - return g_test_run (); + return egg_tests_run_in_thread_with_loop (); } diff --git a/po/gsecret.pot b/po/gsecret.pot index 19499ab..35d950b 100644 --- a/po/gsecret.pot +++ b/po/gsecret.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-09-25 21:16+0200\n" +"POT-Creation-Date: 2011-09-25 22:56+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -22,8 +22,8 @@ msgstr "" msgid "Received invalid secret from the secret storage" msgstr "" -#: ../library/gsecret-service.c:308 ../library/gsecret-service.c:348 -#: ../library/gsecret-service.c:508 +#: ../library/gsecret-service.c:343 ../library/gsecret-service.c:383 +#: ../library/gsecret-service.c:543 #, c-format msgid "Couldn't communicate with the secret storage" msgstr ""