GDBus: Avoid use of libdbus-1 in authentication tests

This greatly simplifies the test since everything is now in a single
process and possible bugs / quirks in libdbus-1 will not interfere
with the tests. On the other hand, we no longer test interoperability
with libdbus-1. This is somewhat moot, however, since other tests that
involve a message bus (e.g. GTestDBus users which include most of the
GDBus test suite itself) will test this.

Also ensure that we don't pollute existing D-Bus keyrings for the
DBUS_COOKIE_SHA1 authentication method (e.g. files in the
~/.dbus-keyrings directory) by setting the environment variables
G_DBUS_COOKIE_SHA1_KEYRING_DIR and
G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION.

All in all, this change avoids some thorny issues where the GDBus and
libdbus-1 implementations disagree on whether an item in the D-Bus
keyring is still valid (items have an age etc.). In reality, since the
DBUS_COOKIE_SHA1 authentication method is never used in production,
this is never hit in production. This bug was, however, frequently hit
if you just ran the test suite repeatedly for 15 minutes or so.

Also add TODO items to mention that we currently don't test corner
cases involving

 - DBUS_COOKIE_SHA1 timeouts
 - libdbus-1 interoperability

Signed-off-by: David Zeuthen <zeuthen@gmail.com>
This commit is contained in:
David Zeuthen 2013-01-03 11:57:21 -05:00
parent 03e84f936f
commit 2652dc1357
2 changed files with 168 additions and 144 deletions

View File

@ -194,12 +194,10 @@ gdbus_serialization_CFLAGS = $(DBUS1_CFLAGS)
gdbus_serialization_LDADD = $(LDADD) $(DBUS1_LIBS)
endif
if HAVE_DBUS1
TEST_PROGS += gdbus-auth
gdbus_auth_SOURCES = gdbus-auth.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
gdbus_auth_CFLAGS = $(DBUS1_CFLAGS)
gdbus_auth_LDADD = $(LDADD) $(DBUS1_LIBS)
endif
gdbus_bz627724_SOURCES = gdbus-bz627724.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c

View File

@ -1,6 +1,6 @@
/* GLib testing framework examples and tests
*
* Copyright (C) 2008-2012 Red Hat, Inc.
* Copyright (C) 2008-2013 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -39,138 +39,28 @@
/* ---------------------------------------------------------------------------------------------------- */
static gboolean
on_allow_mechanism (GDBusAuthObserver *observer,
const gchar *mechanism,
gpointer user_data)
server_on_allow_mechanism (GDBusAuthObserver *observer,
const gchar *mechanism,
gpointer user_data)
{
const gchar *mechanism_to_allow = user_data;
if (g_strcmp0 (mechanism, mechanism_to_allow) == 0)
const gchar *allowed_mechanism = user_data;
if (allowed_mechanism == NULL || g_strcmp0 (mechanism, allowed_mechanism) == 0)
return TRUE;
else
return FALSE;
}
static void
auth_client_mechanism (const gchar *mechanism)
{
gchar *address = NULL;
GDBusConnection *c = NULL;
GError *error = NULL;
GDBusAuthObserver *auth_observer;
address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, NULL, &error);
g_assert_no_error (error);
g_assert (address != NULL);
auth_observer = g_dbus_auth_observer_new ();
g_signal_connect (auth_observer,
"allow-mechanism",
G_CALLBACK (on_allow_mechanism),
(gpointer) mechanism);
c = g_dbus_connection_new_for_address_sync (address,
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
auth_observer,
NULL,
&error);
g_assert_no_error (error);
g_assert (c != NULL);
g_free (address);
g_object_unref (c);
g_object_unref (auth_observer);
}
static void
auth_client_external (void)
{
auth_client_mechanism ("EXTERNAL");
}
static void
auth_client_dbus_cookie_sha1 (void)
{
auth_client_mechanism ("DBUS_COOKIE_SHA1");
}
/* ---------------------------------------------------------------------------------------------------- */
static gboolean
on_new_connection (GDBusServer *server,
GDBusConnection *connection,
gpointer user_data)
{
GMainLoop *loop = user_data;
g_main_loop_quit (loop);
return FALSE;
}
static gboolean
on_timeout (gpointer user_data)
{
g_error ("Timeout waiting for client");
g_assert_not_reached ();
return FALSE;
}
static gpointer
dbus_1_client_thread_func (gpointer user_data)
{
const gchar *address = user_data;
gchar *str_stdout;
gchar *str_stderr;
gint exit_status;
gboolean rc;
gchar *command_line;
GError *error;
// For the dbus part, just use dbus-monitor to connect(1)
command_line = g_strdup_printf ("dbus-monitor --address %s", address);
error = NULL;
rc = g_spawn_command_line_sync (command_line,
&str_stdout,
&str_stderr,
&exit_status,
&error);
g_assert_no_error (error);
g_assert (rc);
g_free (str_stdout);
g_free (str_stderr);
g_free (command_line);
return NULL;
}
static void
auth_server_mechanism (const gchar *mechanism)
/* pass NULL to allow any mechanism */
static GDBusServer *
server_new_for_mechanism (const gchar *allowed_mechanism)
{
gchar *addr;
gchar *guid;
GDBusServer *server;
GDBusAuthObserver *auth_observer;
GMainLoop *loop;
GError *error;
GThread *client_thread;
GDBusServerFlags flags;
/* Skip DBUS_COOKIE_SHA1 test unless we have a sufficiently new version of dbus-1 */
if (g_strcmp0 (mechanism, "DBUS_COOKIE_SHA1") == 0)
{
int dbus_major, dbus_minor, dbus_micro;
dbus_get_version (&dbus_major, &dbus_minor, &dbus_micro);
if (!((dbus_major == 1 && dbus_minor == 4 && dbus_micro >= 21) ||
(dbus_major == 1 && dbus_minor == 5 && dbus_micro >= 13) ||
(dbus_major == 1 && dbus_minor > 5) ||
(dbus_major > 1)))
{
g_print ("Your libdbus-1 library is too old (version %d.%d.%d) so skipping DBUS_COOKIE_SHA1 test. See https://bugs.freedesktop.org/show_bug.cgi?id=48580 for more details.\n",
dbus_major, dbus_minor, dbus_micro);
return;
}
}
guid = g_dbus_generate_guid ();
#ifdef G_OS_UNIX
@ -189,12 +79,10 @@ auth_server_mechanism (const gchar *mechanism)
addr = g_strdup ("nonce-tcp:");
#endif
loop = g_main_loop_new (NULL, FALSE);
auth_observer = g_dbus_auth_observer_new ();
flags = G_DBUS_SERVER_FLAGS_NONE;
if (g_strcmp0 (mechanism, "ANONYMOUS") == 0)
if (g_strcmp0 (allowed_mechanism, "ANONYMOUS") == 0)
flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
error = NULL;
@ -209,51 +97,184 @@ auth_server_mechanism (const gchar *mechanism)
g_signal_connect (auth_observer,
"allow-mechanism",
G_CALLBACK (on_allow_mechanism),
(gpointer) mechanism);
G_CALLBACK (server_on_allow_mechanism),
(gpointer) allowed_mechanism);
g_free (addr);
g_free (guid);
g_object_unref (auth_observer);
return server;
}
/* ---------------------------------------------------------------------------------------------------- */
static gboolean
test_auth_on_new_connection (GDBusServer *server,
GDBusConnection *connection,
gpointer user_data)
{
GMainLoop *loop = user_data;
g_main_loop_quit (loop);
return FALSE;
}
static gboolean
test_auth_on_timeout (gpointer user_data)
{
g_error ("Timeout waiting for client");
g_assert_not_reached ();
return FALSE;
}
typedef struct
{
const gchar *address;
const gchar *allowed_client_mechanism;
const gchar *allowed_server_mechanism;
} TestAuthData;
static gpointer
test_auth_client_thread_func (gpointer user_data)
{
TestAuthData *data = user_data;
GDBusConnection *c = NULL;
GError *error = NULL;
GDBusAuthObserver *auth_observer = NULL;
auth_observer = g_dbus_auth_observer_new ();
g_signal_connect (auth_observer,
"allow-mechanism",
G_CALLBACK (server_on_allow_mechanism),
(gpointer) data->allowed_client_mechanism);
c = g_dbus_connection_new_for_address_sync (data->address,
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
auth_observer,
NULL, /* GCancellable */
&error);
g_assert_no_error (error);
g_assert (c != NULL);
g_clear_object (&c);
g_clear_object (&auth_observer);
return NULL;
}
static void
test_auth_mechanism (const gchar *allowed_client_mechanism,
const gchar *allowed_server_mechanism)
{
GDBusServer *server;
GMainLoop *loop;
GThread *client_thread;
TestAuthData data;
server = server_new_for_mechanism (allowed_server_mechanism);
loop = g_main_loop_new (NULL, FALSE);
g_signal_connect (server,
"new-connection",
G_CALLBACK (on_new_connection),
G_CALLBACK (test_auth_on_new_connection),
loop);
g_timeout_add_seconds (5, test_auth_on_timeout, NULL);
data.allowed_client_mechanism = allowed_client_mechanism;
data.allowed_server_mechanism = allowed_server_mechanism;
data.address = g_dbus_server_get_client_address (server);
/* run the D-Bus client in a thread */
client_thread = g_thread_new ("gdbus-client-thread",
test_auth_client_thread_func,
&data);
g_dbus_server_start (server);
g_timeout_add_seconds (5, on_timeout, NULL);
/* run the libdbus-1 client in a thread */
client_thread = g_thread_new ("dbus-1-client-thread",
dbus_1_client_thread_func,
(gpointer) g_dbus_server_get_client_address (server));
g_main_loop_run (loop);
g_dbus_server_stop (server);
g_thread_join (client_thread);
g_free (addr);
g_free (guid);
g_object_unref (auth_observer);
g_object_unref (server);
}
/* ---------------------------------------------------------------------------------------------------- */
static void
auth_client_external (void)
{
test_auth_mechanism ("EXTERNAL", NULL);
}
static void
auth_client_dbus_cookie_sha1 (void)
{
test_auth_mechanism ("DBUS_COOKIE_SHA1", NULL);
}
static void
auth_server_anonymous (void)
{
auth_server_mechanism ("ANONYMOUS");
test_auth_mechanism (NULL, "ANONYMOUS");
}
static void
auth_server_external (void)
{
auth_server_mechanism ("EXTERNAL");
test_auth_mechanism (NULL, "EXTERNAL");
}
static void
auth_server_dbus_cookie_sha1 (void)
{
auth_server_mechanism ("DBUS_COOKIE_SHA1");
test_auth_mechanism (NULL, "DBUS_COOKIE_SHA1");
}
/* ---------------------------------------------------------------------------------------------------- */
static gchar *temp_dbus_keyrings_dir = NULL;
static void
temp_dbus_keyrings_setup (void)
{
GError *error = NULL;
g_assert (temp_dbus_keyrings_dir == NULL);
temp_dbus_keyrings_dir = g_dir_make_tmp ("gdbus-test-dbus-keyrings-XXXXXX", &error);
g_assert_no_error (error);
g_assert (temp_dbus_keyrings_dir != NULL);
g_setenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR", temp_dbus_keyrings_dir, TRUE);
g_setenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION", "1", TRUE);
}
static void
temp_dbus_keyrings_teardown (void)
{
GDir *dir;
GError *error = NULL;
const gchar *name;
g_assert (temp_dbus_keyrings_dir != NULL);
dir = g_dir_open (temp_dbus_keyrings_dir, 0, &error);
g_assert_no_error (error);
g_assert (dir != NULL);
while ((name = g_dir_read_name (dir)) != NULL)
{
gchar *path = g_build_filename (temp_dbus_keyrings_dir, name, NULL);
g_assert (unlink (path) == 0);
g_free (path);
}
g_dir_close (dir);
g_assert (rmdir (temp_dbus_keyrings_dir) == 0);
temp_dbus_keyrings_dir = NULL;
g_setenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR", NULL, TRUE);
g_setenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION", NULL, TRUE);
}
/* ---------------------------------------------------------------------------------------------------- */
@ -266,9 +287,9 @@ main (int argc,
setlocale (LC_ALL, "C");
g_test_init (&argc, &argv, NULL);
temp_dbus_keyrings_setup ();
session_bus_up ();
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/gdbus/auth/client/EXTERNAL", auth_client_external);
g_test_add_func ("/gdbus/auth/client/DBUS_COOKIE_SHA1", auth_client_dbus_cookie_sha1);
@ -276,10 +297,15 @@ main (int argc,
g_test_add_func ("/gdbus/auth/server/EXTERNAL", auth_server_external);
g_test_add_func ("/gdbus/auth/server/DBUS_COOKIE_SHA1", auth_server_dbus_cookie_sha1);
/* TODO: we currently don't have tests for
*
* - DBUS_COOKIE_SHA1 timeouts (and clock changes etc)
* - interoperability with libdbus-1 implementations of authentication methods (both client and server)
*/
ret = g_test_run();
/* tear down bus */
session_bus_down ();
temp_dbus_keyrings_teardown ();
return ret;
}