[glib/wip/danw/clicert: 1/3] Add a request_certificate virtual method to GTlsInteraction
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/danw/clicert: 1/3] Add a request_certificate virtual method to GTlsInteraction
- Date: Sat, 19 Oct 2013 15:51:05 +0000 (UTC)
commit 5c2d2c8e1f1edf0b27d73361a1d5e898018369fa
Author: Stef Walter <stefw gnome org>
Date: Wed Nov 28 22:01:21 2012 +0100
Add a request_certificate virtual method to GTlsInteraction
This allows GTlsConnection implementations to request a certificate
from the user.
https://bugzilla.gnome.org/show_bug.cgi?id=637257
docs/reference/gio/gio-sections.txt | 6 +-
gio/gtlsinteraction.c | 353 +++++++++++++++++++++---
gio/gtlsinteraction.h | 47 +++-
gio/tests/Makefile.am | 2 +
gio/tests/tls-interaction.c | 508 +++++++++++++++++++++++++++++++----
5 files changed, 815 insertions(+), 101 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index fe1c8a9..d7638ca 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -3551,10 +3551,14 @@ G_TYPE_TLS_PASSWORD_FLAGS
<TITLE>GTlsInteraction</TITLE>
GTlsInteraction
GTlsInteractionResult
+g_tls_interaction_invoke_ask_password
+g_tls_interaction_invoke_request_certificate
g_tls_interaction_ask_password
g_tls_interaction_ask_password_async
g_tls_interaction_ask_password_finish
-g_tls_interaction_invoke_ask_password
+g_tls_interaction_request_certificate
+g_tls_interaction_request_certificate_async
+g_tls_interaction_request_certificate_finish
<SUBSECTION Standard>
GTlsInteractionClass
G_IS_TLS_INTERACTION
diff --git a/gio/gtlsinteraction.c b/gio/gtlsinteraction.c
index 0701ddb..b4800a1 100644
--- a/gio/gtlsinteraction.c
+++ b/gio/gtlsinteraction.c
@@ -24,6 +24,8 @@
#include <string.h>
+#include "gtlscertificate.h"
+#include "gtlsconnection.h"
#include "gtlsinteraction.h"
#include "gtlspassword.h"
#include "gasyncresult.h"
@@ -182,6 +184,55 @@ invoke_closure_wait_and_free (InvokeClosure *closure,
return result;
}
+static GTlsInteractionResult
+invoke_closure_complete_and_free (GTlsInteraction *interaction,
+ InvokeClosure *closure,
+ GError **error)
+{
+ GTlsInteractionResult result;
+ gboolean complete;
+
+ /*
+ * Handle the case where we've been called from within the main context
+ * or in the case where the main context is not running. This approximates
+ * the behavior of a modal dialog.
+ */
+ if (g_main_context_acquire (interaction->priv->context))
+ {
+ for (;;)
+ {
+ g_mutex_lock (&closure->mutex);
+ complete = closure->complete;
+ g_mutex_unlock (&closure->mutex);
+ if (complete)
+ break;
+ g_main_context_iteration (interaction->priv->context, TRUE);
+ }
+
+ g_main_context_release (interaction->priv->context);
+
+ if (closure->error)
+ {
+ g_propagate_error (error, closure->error);
+ closure->error = NULL;
+ }
+
+ result = closure->result;
+ invoke_closure_free (closure);
+ }
+
+ /*
+ * Handle the case where we're in a different thread than the main
+ * context and a main loop is running.
+ */
+ else
+ {
+ result = invoke_closure_wait_and_free (closure, error);
+ }
+
+ return result;
+}
+
static void
g_tls_interaction_init (GTlsInteraction *interaction)
{
@@ -231,9 +282,9 @@ on_invoke_ask_password_sync (gpointer user_data)
}
static void
-on_async_as_sync_complete (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
+on_ask_password_complete (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
{
InvokeClosure *closure = user_data;
GTlsInteractionClass *klass;
@@ -266,7 +317,7 @@ on_invoke_ask_password_async_as_sync (gpointer user_data)
klass->ask_password_async (closure->interaction,
G_TLS_PASSWORD (closure->argument),
closure->cancellable,
- on_async_as_sync_complete,
+ on_ask_password_complete,
closure);
/* Note that we've used these */
@@ -318,7 +369,6 @@ g_tls_interaction_invoke_ask_password (GTlsInteraction *interaction,
GTlsInteractionResult result;
InvokeClosure *closure;
GTlsInteractionClass *klass;
- gboolean complete;
g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
g_return_val_if_fail (G_IS_TLS_PASSWORD (password), G_TLS_INTERACTION_UNHANDLED);
@@ -339,43 +389,7 @@ g_tls_interaction_invoke_ask_password (GTlsInteraction *interaction,
g_main_context_invoke (interaction->priv->context,
on_invoke_ask_password_async_as_sync, closure);
- /*
- * Handle the case where we've been called from within the main context
- * or in the case where the main context is not running. This approximates
- * the behavior of a modal dialog.
- */
- if (g_main_context_acquire (interaction->priv->context))
- {
- for (;;)
- {
- g_mutex_lock (&closure->mutex);
- complete = closure->complete;
- g_mutex_unlock (&closure->mutex);
- if (complete)
- break;
- g_main_context_iteration (interaction->priv->context, TRUE);
- }
-
- g_main_context_release (interaction->priv->context);
-
- if (closure->error)
- {
- g_propagate_error (error, closure->error);
- closure->error = NULL;
- }
-
- result = closure->result;
- invoke_closure_free (closure);
- }
-
- /*
- * Handle the case where we're in a different thread than the main
- * context and a main loop is running.
- */
- else
- {
- result = invoke_closure_wait_and_free (closure, error);
- }
+ result = invoke_closure_complete_and_free (interaction, closure, error);
}
else
{
@@ -386,7 +400,6 @@ g_tls_interaction_invoke_ask_password (GTlsInteraction *interaction,
return result;
}
-
/**
* g_tls_interaction_ask_password:
* @interaction: a #GTlsInteraction object
@@ -531,3 +544,257 @@ g_tls_interaction_ask_password_finish (GTlsInteraction *interaction,
return g_task_propagate_int (G_TASK (result), error);
}
}
+
+static gboolean
+on_invoke_request_certificate_sync (gpointer user_data)
+{
+ InvokeClosure *closure = user_data;
+ GTlsInteractionClass *klass;
+
+ g_mutex_lock (&closure->mutex);
+
+ klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
+ g_assert (klass->request_certificate != NULL);
+
+ closure->result = klass->request_certificate (closure->interaction,
+ G_TLS_CONNECTION (closure->argument),
+ 0,
+ closure->cancellable,
+ &closure->error);
+
+ closure->complete = TRUE;
+ g_cond_signal (&closure->cond);
+ g_mutex_unlock (&closure->mutex);
+
+ return FALSE; /* don't call again */
+}
+
+static void
+on_request_certificate_complete (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ InvokeClosure *closure = user_data;
+ GTlsInteractionClass *klass;
+
+ g_mutex_lock (&closure->mutex);
+
+ klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
+ g_assert (klass->request_certificate_finish != NULL);
+
+ closure->result = klass->request_certificate_finish (closure->interaction,
+ result, &closure->error);
+
+ closure->complete = TRUE;
+ g_cond_signal (&closure->cond);
+ g_mutex_unlock (&closure->mutex);
+}
+
+static gboolean
+on_invoke_request_certificate_async_as_sync (gpointer user_data)
+{
+ InvokeClosure *closure = user_data;
+ GTlsInteractionClass *klass;
+
+ g_mutex_lock (&closure->mutex);
+
+ klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
+ g_assert (klass->request_certificate_async);
+
+ klass->request_certificate_async (closure->interaction,
+ G_TLS_CONNECTION (closure->argument), 0,
+ closure->cancellable,
+ on_request_certificate_complete,
+ closure);
+
+ /* Note that we've used these */
+ closure->callback = NULL;
+ closure->user_data = NULL;
+
+ g_mutex_unlock (&closure->mutex);
+
+ return FALSE; /* don't call again */
+}
+
+GTlsInteractionResult
+g_tls_interaction_invoke_request_certificate (GTlsInteraction *interaction,
+ GTlsConnection *connection,
+ gint unused_flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GTlsInteractionResult result;
+ InvokeClosure *closure;
+ GTlsInteractionClass *klass;
+
+ g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
+ g_return_val_if_fail (G_IS_TLS_CONNECTION (connection), G_TLS_INTERACTION_UNHANDLED);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED);
+
+ closure = invoke_closure_new (interaction, G_OBJECT (connection), cancellable);
+
+ klass = G_TLS_INTERACTION_GET_CLASS (interaction);
+ if (klass->request_certificate)
+ {
+ g_main_context_invoke (interaction->priv->context,
+ on_invoke_request_certificate_sync, closure);
+ result = invoke_closure_wait_and_free (closure, error);
+ }
+ else if (klass->request_certificate_async)
+ {
+ g_return_val_if_fail (klass->request_certificate_finish, G_TLS_INTERACTION_UNHANDLED);
+ g_main_context_invoke (interaction->priv->context,
+ on_invoke_request_certificate_async_as_sync, closure);
+
+ result = invoke_closure_complete_and_free (interaction, closure, error);
+ }
+ else
+ {
+ result = G_TLS_INTERACTION_UNHANDLED;
+ invoke_closure_free (closure);
+ }
+
+ return result;
+}
+
+/**
+ * g_tls_interaction_request_certificate:
+ * @interaction: a #GTlsInteraction object
+ * @connection: a #GTlsConnection object
+ * @cancellable: an optional #GCancellable cancellation object
+ * @error: an optional location to place an error on failure
+ *
+ * Run synchronous interaction to ask the user to choose a certificate to use
+ * with the connection. In general, g_tls_interaction_invoke_request_certificate()
+ * should be used instead of this function.
+ *
+ * Derived subclasses usually implement a certificate selector, although they may
+ * also choose to provide a certificate from elsewhere. Alternatively the user may
+ * abort this certificate request, which will usually abort the TLS connection.
+ *
+ * If %G_TLS_INTERACTION_HANDLED is returned, then the #GTlsConnection passed
+ * to g_tls_interaction_request_certificate() will have its certificate filled in.
+ *
+ * If the interaction is cancelled by the cancellation object, or by the
+ * user then %G_TLS_INTERACTION_FAILED will be returned with an error that
+ * contains a %G_IO_ERROR_CANCELLED error code. Certain implementations may
+ * not support immediate cancellation.
+ *
+ * Returns: The status of the request certificate interaction.
+ *
+ * Since: 2.36
+ */
+GTlsInteractionResult
+g_tls_interaction_request_certificate (GTlsInteraction *interaction,
+ GTlsConnection *connection,
+ gint unused_flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GTlsInteractionClass *klass;
+
+ g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
+ g_return_val_if_fail (G_IS_TLS_CONNECTION (connection), G_TLS_INTERACTION_UNHANDLED);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED);
+
+ klass = G_TLS_INTERACTION_GET_CLASS (interaction);
+ if (klass->request_certificate)
+ return (klass->request_certificate) (interaction, connection, unused_flags, cancellable, error);
+ else
+ return G_TLS_INTERACTION_UNHANDLED;
+}
+
+/**
+ * g_tls_interaction_request_certificate_async:
+ * @interaction: a #GTlsInteraction object
+ * @connection: a #GTlsConnection object
+ * @cancellable: an optional #GCancellable cancellation object
+ * @callback: (allow-none): will be called when the interaction completes
+ * @user_data: (allow-none): data to pass to the @callback
+ *
+ * Run asynchronous interaction to ask the user for a certificate to use with
+ * the connection. In general, g_tls_interaction_invoke_request_certificate() should
+ * be used instead of this function.
+ *
+ * Derived subclasses usually implement a certificate selector, although they may
+ * also choose to provide a certificate from elsewhere. @callback will be called
+ * when the operation completes. Alternatively the user may abort this certificate
+ * request, which will usually abort the TLS connection.
+ *
+ * Since: 2.36
+ */
+void
+g_tls_interaction_request_certificate_async (GTlsInteraction *interaction,
+ GTlsConnection *connection,
+ gint unused_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTlsInteractionClass *klass;
+ GTask *task;
+
+ g_return_if_fail (G_IS_TLS_INTERACTION (interaction));
+ g_return_if_fail (G_IS_TLS_CONNECTION (connection));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ klass = G_TLS_INTERACTION_GET_CLASS (interaction);
+ if (klass->request_certificate_async)
+ {
+ g_return_if_fail (klass->request_certificate_finish);
+ (klass->request_certificate_async) (interaction, connection, unused_flags,
+ cancellable, callback, user_data);
+ }
+ else
+ {
+ task = g_task_new (interaction, cancellable, callback, user_data);
+ g_task_set_source_tag (task, g_tls_interaction_request_certificate_async);
+ g_task_return_int (task, G_TLS_INTERACTION_UNHANDLED);
+ g_object_unref (task);
+ }
+}
+
+/**
+ * g_tls_interaction_request_certificate_finish:
+ * @interaction: a #GTlsInteraction object
+ * @result: the result passed to the callback
+ * @error: an optional location to place an error on failure
+ *
+ * Complete an request certificate user interaction request. This should be once
+ * the g_tls_interaction_request_certificate_async() completion callback is called.
+ *
+ * If %G_TLS_INTERACTION_HANDLED is returned, then the #GTlsConnection passed
+ * to g_tls_interaction_request_certificate() will have its certificate filled in.
+ *
+ * If the interaction is cancelled by the cancellation object, or by the
+ * user then %G_TLS_INTERACTION_FAILED will be returned with an error that
+ * contains a %G_IO_ERROR_CANCELLED error code.
+ *
+ * Returns: The status of the request certificate interaction.
+ *
+ * Since: 2.36
+ */
+GTlsInteractionResult
+g_tls_interaction_request_certificate_finish (GTlsInteraction *interaction,
+ GAsyncResult *result,
+ GError **error)
+{
+ GTlsInteractionClass *klass;
+
+ g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), G_TLS_INTERACTION_UNHANDLED);
+
+ klass = G_TLS_INTERACTION_GET_CLASS (interaction);
+ if (klass->request_certificate_finish)
+ {
+ g_return_val_if_fail (klass->request_certificate_async != NULL, G_TLS_INTERACTION_UNHANDLED);
+
+ return (klass->request_certificate_finish) (interaction, result, error);
+ }
+ else
+ {
+ g_return_val_if_fail (g_async_result_is_tagged (result, g_tls_interaction_request_certificate_async),
G_TLS_INTERACTION_UNHANDLED);
+
+ return g_task_propagate_int (G_TASK (result), error);
+ }
+}
diff --git a/gio/gtlsinteraction.h b/gio/gtlsinteraction.h
index 283464e..7b2e761 100644
--- a/gio/gtlsinteraction.h
+++ b/gio/gtlsinteraction.h
@@ -69,9 +69,26 @@ struct _GTlsInteractionClass
GAsyncResult *result,
GError **error);
+ GTlsInteractionResult (* request_certificate) (GTlsInteraction *interaction,
+ GTlsConnection *connection,
+ gint unused_flags,
+ GCancellable *cancellable,
+ GError **error);
+
+ void (* request_certificate_async) (GTlsInteraction *interaction,
+ GTlsConnection *connection,
+ gint unused_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+ GTlsInteractionResult (* request_certificate_finish) (GTlsInteraction *interaction,
+ GAsyncResult *result,
+ GError **error);
+
/*< private >*/
/* Padding for future expansion */
- gpointer padding[24];
+ gpointer padding[21];
};
GLIB_AVAILABLE_IN_ALL
@@ -83,7 +100,6 @@ GTlsInteractionResult g_tls_interaction_invoke_ask_password (GTlsInteraction
GCancellable *cancellable,
GError **error);
-
GLIB_AVAILABLE_IN_ALL
GTlsInteractionResult g_tls_interaction_ask_password (GTlsInteraction *interaction,
GTlsPassword *password,
@@ -102,6 +118,33 @@ GTlsInteractionResult g_tls_interaction_ask_password_finish (GTlsInteraction
GAsyncResult *result,
GError **error);
+GLIB_AVAILABLE_IN_2_36
+GTlsInteractionResult g_tls_interaction_invoke_request_certificate (GTlsInteraction *interaction,
+ GTlsConnection *connection,
+ gint unused_flags,
+ GCancellable *cancellable,
+ GError **error);
+
+GLIB_AVAILABLE_IN_2_36
+GTlsInteractionResult g_tls_interaction_request_certificate (GTlsInteraction *interaction,
+ GTlsConnection *connection,
+ gint unused_flags,
+ GCancellable *cancellable,
+ GError **error);
+
+GLIB_AVAILABLE_IN_2_36
+void g_tls_interaction_request_certificate_async (GTlsInteraction *interaction,
+ GTlsConnection *connection,
+ gint unused_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GLIB_AVAILABLE_IN_2_36
+GTlsInteractionResult g_tls_interaction_request_certificate_finish (GTlsInteraction *interaction,
+ GAsyncResult *result,
+ GError **error);
+
G_END_DECLS
#endif /* __G_TLS_INTERACTION_H__ */
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 0194685..62ff885 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -385,6 +385,8 @@ CLEANFILES += gdbus-test-codegen-generated.[ch] gdbus-test-codegen-generated-doc
endif # OS_UNIX
endif # HAVE_DBUS_DAEMON
+tls_interaction_SOURCES = tls-interaction.c gtesttlsbackend.c gtesttlsbackend.h
+
# -----------------------------------------------------------------------------
if OS_WIN32
diff --git a/gio/tests/tls-interaction.c b/gio/tests/tls-interaction.c
index a34ff29..ce2aa88 100644
--- a/gio/tests/tls-interaction.c
+++ b/gio/tests/tls-interaction.c
@@ -24,11 +24,18 @@
#include <gio/gio.h>
+#include "gtesttlsbackend.h"
+
+static GPtrArray *fixtures = NULL;
+
typedef struct {
/* Class virtual interaction methods */
gpointer ask_password_func;
gpointer ask_password_async_func;
gpointer ask_password_finish_func;
+ gpointer request_certificate_func;
+ gpointer request_certificate_async_func;
+ gpointer request_certificate_finish_func;
/* Expected results */
GTlsInteractionResult result;
@@ -40,6 +47,7 @@ typedef struct {
typedef struct {
GTlsInteraction *interaction;
GTlsPassword *password;
+ GTlsConnection *connection;
GMainLoop *loop;
GThread *interaction_thread;
GThread *test_thread;
@@ -213,6 +221,155 @@ test_interaction_ask_password_sync_failure (GTlsInteraction *interaction,
return G_TLS_INTERACTION_FAILED;
}
+static void
+test_interaction_request_certificate_async_success (GTlsInteraction *interaction,
+ GTlsConnection *connection,
+ gint unused_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ TestInteraction *self;
+
+ g_assert (TEST_IS_INTERACTION (interaction));
+ self = TEST_INTERACTION (interaction);
+
+ g_assert (g_thread_self () == self->test->interaction_thread);
+
+ g_assert (G_IS_TLS_CONNECTION (connection));
+ g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ g_assert (unused_flags == 0);
+
+ task = g_task_new (self, cancellable, callback, user_data);
+
+ /*
+ * IRL would call g_tls_connection_set_certificate(). But here just touch
+ * the connection in a detectable way.
+ */
+ g_object_set_data (G_OBJECT (connection), "chosen-certificate", "my-certificate");
+ g_task_return_int (task, G_TLS_INTERACTION_HANDLED);
+ g_object_unref (task);
+}
+
+static GTlsInteractionResult
+test_interaction_request_certificate_finish_success (GTlsInteraction *interaction,
+ GAsyncResult *result,
+ GError **error)
+{
+ TestInteraction *self;
+
+ g_assert (TEST_IS_INTERACTION (interaction));
+ self = TEST_INTERACTION (interaction);
+
+ g_assert (g_thread_self () == self->test->interaction_thread);
+
+ g_assert (g_task_is_valid (result, interaction));
+ g_assert (error != NULL);
+ g_assert (*error == NULL);
+
+ return g_task_propagate_int (G_TASK (result), error);
+}
+
+static void
+test_interaction_request_certificate_async_failure (GTlsInteraction *interaction,
+ GTlsConnection *connection,
+ gint unused_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ TestInteraction *self;
+
+ g_assert (TEST_IS_INTERACTION (interaction));
+ self = TEST_INTERACTION (interaction);
+
+ g_assert (g_thread_self () == self->test->interaction_thread);
+
+ g_assert (G_IS_TLS_CONNECTION (connection));
+ g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ g_assert (unused_flags == 0);
+
+ task = g_task_new (self, cancellable, callback, user_data);
+
+ g_task_return_new_error (task, G_FILE_ERROR, G_FILE_ERROR_NOENT, "Another message");
+ g_object_unref (task);
+}
+
+static GTlsInteractionResult
+test_interaction_request_certificate_finish_failure (GTlsInteraction *interaction,
+ GAsyncResult *result,
+ GError **error)
+{
+ TestInteraction *self;
+
+ g_assert (TEST_IS_INTERACTION (interaction));
+ self = TEST_INTERACTION (interaction);
+
+ g_assert (g_thread_self () == self->test->interaction_thread);
+
+ g_assert (g_task_is_valid (result, interaction));
+ g_assert (error != NULL);
+ g_assert (*error == NULL);
+
+ if (g_task_propagate_int (G_TASK (result), error) != -1)
+ g_assert_not_reached ();
+
+ return G_TLS_INTERACTION_FAILED;
+}
+
+static GTlsInteractionResult
+test_interaction_request_certificate_sync_success (GTlsInteraction *interaction,
+ GTlsConnection *connection,
+ gint unused_flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TestInteraction *self;
+
+ g_assert (TEST_IS_INTERACTION (interaction));
+ self = TEST_INTERACTION (interaction);
+
+ g_assert (g_thread_self () == self->test->interaction_thread);
+
+ g_assert (G_IS_TLS_CONNECTION (connection));
+ g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ g_assert (error != NULL);
+ g_assert (*error == NULL);
+
+ /*
+ * IRL would call g_tls_connection_set_certificate(). But here just touch
+ * the connection in a detectable way.
+ */
+ g_object_set_data (G_OBJECT (connection), "chosen-certificate", "my-certificate");
+ return G_TLS_INTERACTION_HANDLED;
+}
+
+static GTlsInteractionResult
+test_interaction_request_certificate_sync_failure (GTlsInteraction *interaction,
+ GTlsConnection *connection,
+ gint unused_flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TestInteraction *self;
+
+ g_assert (TEST_IS_INTERACTION (interaction));
+ self = TEST_INTERACTION (interaction);
+
+ g_assert (g_thread_self () == self->test->interaction_thread);
+
+ g_assert (G_IS_TLS_CONNECTION (connection));
+ g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ g_assert (unused_flags == 0);
+ g_assert (error != NULL);
+ g_assert (*error == NULL);
+
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT, "Another message");
+ return G_TLS_INTERACTION_FAILED;
+}
+
/* ----------------------------------------------------------------------------
* ACTUAL TESTS
*/
@@ -344,6 +501,133 @@ test_ask_password (Test *test,
g_main_loop_quit (test->loop);
}
+static void
+on_request_certificate_async_call (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Test *test = user_data;
+ GTlsInteractionResult res;
+ GError *error = NULL;
+
+ g_assert (G_IS_TLS_INTERACTION (source));
+ g_assert (G_TLS_INTERACTION (source) == test->interaction);
+
+ /* Check that this callback is being run in the right place */
+ g_assert (g_thread_self () == test->interaction_thread);
+
+ res = g_tls_interaction_request_certificate_finish (test->interaction, result, &error);
+
+ /* Check that the results match the fixture */
+ g_assert_cmpuint (test->fixture->result, ==, res);
+ switch (test->fixture->result)
+ {
+ case G_TLS_INTERACTION_HANDLED:
+ g_assert_no_error (error);
+ g_assert_cmpstr (g_object_get_data (G_OBJECT (test->connection), "chosen-certificate"), ==,
"my-certificate");
+ break;
+ case G_TLS_INTERACTION_FAILED:
+ g_assert_error (error, test->fixture->error_domain, test->fixture->error_code);
+ g_assert_cmpstr (error->message, ==, test->fixture->error_message);
+ g_clear_error (&error);
+ break;
+ case G_TLS_INTERACTION_UNHANDLED:
+ g_assert_no_error (error);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ /* Signal the end of the test */
+ g_main_loop_quit (test->loop);
+}
+
+static void
+test_request_certificate_async (Test *test,
+ gconstpointer unused)
+{
+ /* This test only works with a main loop */
+ g_assert (test->loop);
+
+ g_tls_interaction_request_certificate_async (test->interaction,
+ test->connection, 0, NULL,
+ on_request_certificate_async_call,
+ test);
+
+ /* teardown waits until g_main_loop_quit(). called from callback */
+}
+
+static void
+test_invoke_request_certificate (Test *test,
+ gconstpointer unused)
+{
+ GTlsInteractionResult res;
+ GError *error = NULL;
+
+ res = g_tls_interaction_invoke_request_certificate (test->interaction,
+ test->connection,
+ 0, NULL, &error);
+
+ /* Check that the results match the fixture */
+ g_assert_cmpuint (test->fixture->result, ==, res);
+ switch (test->fixture->result)
+ {
+ case G_TLS_INTERACTION_HANDLED:
+ g_assert_no_error (error);
+ g_assert_cmpstr (g_object_get_data (G_OBJECT (test->connection), "chosen-certificate"), ==,
"my-certificate");
+ break;
+ case G_TLS_INTERACTION_FAILED:
+ g_assert_error (error, test->fixture->error_domain, test->fixture->error_code);
+ g_assert_cmpstr (error->message, ==, test->fixture->error_message);
+ g_clear_error (&error);
+ break;
+ case G_TLS_INTERACTION_UNHANDLED:
+ g_assert_no_error (error);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ /* This allows teardown to stop if running with loop */
+ if (test->loop)
+ g_main_loop_quit (test->loop);
+}
+
+static void
+test_request_certificate (Test *test,
+ gconstpointer unused)
+{
+ GTlsInteractionResult res;
+ GError *error = NULL;
+
+ res = g_tls_interaction_request_certificate (test->interaction, test->connection,
+ 0, NULL, &error);
+
+ /* Check that the results match the fixture */
+ g_assert_cmpuint (test->fixture->result, ==, res);
+ switch (test->fixture->result)
+ {
+ case G_TLS_INTERACTION_HANDLED:
+ g_assert_no_error (error);
+ g_assert_cmpstr (g_object_get_data (G_OBJECT (test->connection), "chosen-certificate"), ==,
"my-certificate");
+ break;
+ case G_TLS_INTERACTION_FAILED:
+ g_assert_error (error, test->fixture->error_domain, test->fixture->error_code);
+ g_assert_cmpstr (error->message, ==, test->fixture->error_message);
+ g_clear_error (&error);
+ break;
+ case G_TLS_INTERACTION_UNHANDLED:
+ g_assert_no_error (error);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ /* This allows teardown to stop if running with loop */
+ if (test->loop)
+ g_main_loop_quit (test->loop);
+}
+
/* ----------------------------------------------------------------------------
* TEST SETUP
*/
@@ -354,6 +638,9 @@ setup_without_loop (Test *test,
{
const Fixture *fixture = user_data;
GTlsInteractionClass *klass;
+ GTlsBackend *backend;
+ GError *error = NULL;
+
test->fixture = fixture;
test->interaction = g_object_new (TEST_TYPE_INTERACTION, NULL);
@@ -365,6 +652,14 @@ setup_without_loop (Test *test,
klass->ask_password = fixture->ask_password_func;
klass->ask_password_async = fixture->ask_password_async_func;
klass->ask_password_finish = fixture->ask_password_finish_func;
+ klass->request_certificate = fixture->request_certificate_func;
+ klass->request_certificate_async = fixture->request_certificate_async_func;
+ klass->request_certificate_finish = fixture->request_certificate_finish_func;
+
+ backend = g_object_new (G_TYPE_TEST_TLS_BACKEND, NULL);
+ test->connection = g_object_new (g_tls_backend_get_server_connection_type (backend), NULL);
+ g_assert_no_error (error);
+ g_object_unref (backend);
test->password = g_tls_password_new (0, "Description");
test->test_thread = g_thread_self ();
@@ -384,6 +679,8 @@ teardown_without_loop (Test *test,
g_object_add_weak_pointer (weak_pointer, &weak_pointer);
+ g_object_unref (test->connection);
+
g_object_unref (test->password);
g_object_unref (test->interaction);
@@ -507,11 +804,10 @@ teardown_with_normal_loop (Test *test,
typedef void (*TestFunc) (Test *test, gconstpointer data);
static void
-test_with_async_ask_password_implementations (const gchar *name,
- TestFunc setup,
- TestFunc func,
- TestFunc teardown,
- GPtrArray *fixtures)
+test_with_async_ask_password (const gchar *name,
+ TestFunc setup,
+ TestFunc func,
+ TestFunc teardown)
{
gchar *test_name;
Fixture *fixture;
@@ -541,12 +837,12 @@ test_with_async_ask_password_implementations (const gchar *name,
g_free (test_name);
g_ptr_array_add (fixtures, fixture);
}
+
static void
-test_with_unhandled_ask_password_implementations (const gchar *name,
- TestFunc setup,
- TestFunc func,
- TestFunc teardown,
- GPtrArray *fixtures)
+test_with_unhandled_ask_password (const gchar *name,
+ TestFunc setup,
+ TestFunc func,
+ TestFunc teardown)
{
gchar *test_name;
Fixture *fixture;
@@ -564,11 +860,10 @@ test_with_unhandled_ask_password_implementations (const gchar *name,
}
static void
-test_with_sync_ask_password_implementations (const gchar *name,
+test_with_sync_ask_password (const gchar *name,
TestFunc setup,
TestFunc func,
- TestFunc teardown,
- GPtrArray *fixtures)
+ TestFunc teardown)
{
gchar *test_name;
Fixture *fixture;
@@ -599,11 +894,122 @@ test_with_sync_ask_password_implementations (const gchar *name,
g_ptr_array_add (fixtures, fixture);
}
+static void
+test_with_all_ask_password (const gchar *name,
+ TestFunc setup,
+ TestFunc func,
+ TestFunc teardown)
+{
+ test_with_unhandled_ask_password (name, setup, func, teardown);
+ test_with_async_ask_password (name, setup, func, teardown);
+ test_with_sync_ask_password (name, setup, func, teardown);
+}
+
+static void
+test_with_async_request_certificate (const gchar *name,
+ TestFunc setup,
+ TestFunc func,
+ TestFunc teardown)
+{
+ gchar *test_name;
+ Fixture *fixture;
+
+ /* Async implementation that succeeds */
+ fixture = g_new0 (Fixture, 1);
+ fixture->request_certificate_async_func = test_interaction_request_certificate_async_success;
+ fixture->request_certificate_finish_func = test_interaction_request_certificate_finish_success;
+ fixture->request_certificate_func = NULL;
+ fixture->result = G_TLS_INTERACTION_HANDLED;
+ test_name = g_strdup_printf ("%s/async-implementation-success", name);
+ g_test_add (test_name, Test, fixture, setup, func, teardown);
+ g_free (test_name);
+ g_ptr_array_add (fixtures, fixture);
+
+ /* Async implementation that fails */
+ fixture = g_new0 (Fixture, 1);
+ fixture->request_certificate_async_func = test_interaction_request_certificate_async_failure;
+ fixture->request_certificate_finish_func = test_interaction_request_certificate_finish_failure;
+ fixture->request_certificate_func = NULL;
+ fixture->result = G_TLS_INTERACTION_FAILED;
+ fixture->error_domain = G_FILE_ERROR;
+ fixture->error_code = G_FILE_ERROR_NOENT;
+ fixture->error_message = "Another message";
+ test_name = g_strdup_printf ("%s/async-implementation-failure", name);
+ g_test_add (test_name, Test, fixture, setup, func, teardown);
+ g_free (test_name);
+ g_ptr_array_add (fixtures, fixture);
+}
+
+static void
+test_with_unhandled_request_certificate (const gchar *name,
+ TestFunc setup,
+ TestFunc func,
+ TestFunc teardown)
+{
+ gchar *test_name;
+ Fixture *fixture;
+
+ /* Unhandled implementation */
+ fixture = g_new0 (Fixture, 1);
+ fixture->request_certificate_async_func = NULL;
+ fixture->request_certificate_finish_func = NULL;
+ fixture->request_certificate_func = NULL;
+ fixture->result = G_TLS_INTERACTION_UNHANDLED;
+ test_name = g_strdup_printf ("%s/unhandled-implementation", name);
+ g_test_add (test_name, Test, fixture, setup, func, teardown);
+ g_free (test_name);
+ g_ptr_array_add (fixtures, fixture);
+}
+
+static void
+test_with_sync_request_certificate (const gchar *name,
+ TestFunc setup,
+ TestFunc func,
+ TestFunc teardown)
+{
+ gchar *test_name;
+ Fixture *fixture;
+
+ /* Sync implementation that succeeds */
+ fixture = g_new0 (Fixture, 1);
+ fixture->request_certificate_async_func = NULL;
+ fixture->request_certificate_finish_func = NULL;
+ fixture->request_certificate_func = test_interaction_request_certificate_sync_success;
+ fixture->result = G_TLS_INTERACTION_HANDLED;
+ test_name = g_strdup_printf ("%s/sync-implementation-success", name);
+ g_test_add (test_name, Test, fixture, setup, func, teardown);
+ g_free (test_name);
+ g_ptr_array_add (fixtures, fixture);
+
+ /* Async implementation that fails */
+ fixture = g_new0 (Fixture, 1);
+ fixture->request_certificate_async_func = NULL;
+ fixture->request_certificate_finish_func = NULL;
+ fixture->request_certificate_func = test_interaction_request_certificate_sync_failure;
+ fixture->result = G_TLS_INTERACTION_FAILED;
+ fixture->error_domain = G_FILE_ERROR;
+ fixture->error_code = G_FILE_ERROR_NOENT;
+ fixture->error_message = "Another message";
+ test_name = g_strdup_printf ("%s/sync-implementation-failure", name);
+ g_test_add (test_name, Test, fixture, setup, func, teardown);
+ g_free (test_name);
+ g_ptr_array_add (fixtures, fixture);
+}
+
+static void
+test_with_all_request_certificate (const gchar *name,
+ TestFunc setup,
+ TestFunc func,
+ TestFunc teardown)
+{
+ test_with_unhandled_request_certificate (name, setup, func, teardown);
+ test_with_async_request_certificate (name, setup, func, teardown);
+ test_with_sync_request_certificate (name, setup, func, teardown);
+}
int
main (int argc,
char *argv[])
{
- GPtrArray *fixtures;
gint ret;
g_test_init (&argc, &argv, NULL);
@@ -611,52 +1017,44 @@ main (int argc,
fixtures = g_ptr_array_new_with_free_func (g_free);
/* Tests for g_tls_interaction_invoke_ask_password */
+ test_with_all_ask_password ("/tls-interaction/ask-password/invoke-with-loop",
+ setup_with_thread_loop, test_invoke_ask_password, teardown_with_thread_loop);
+ test_with_all_ask_password ("/tls-interaction/ask-password/invoke-without-loop",
+ setup_without_loop, test_invoke_ask_password, teardown_without_loop);
+ test_with_all_ask_password ("/tls-interaction/ask-password/invoke-in-loop",
+ setup_with_normal_loop, test_invoke_ask_password,
teardown_with_normal_loop);
+
+ /* Tests for g_tls_interaction_ask_password */
+ test_with_unhandled_ask_password ("/tls-interaction/ask-password/sync",
+ setup_without_loop, test_ask_password, teardown_without_loop);
+ test_with_sync_ask_password ("/tls-interaction/ask-password/sync",
+ setup_without_loop, test_ask_password, teardown_without_loop);
- test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/invoke-with-loop",
- setup_with_thread_loop, test_invoke_ask_password,
- teardown_with_thread_loop, fixtures);
- test_with_async_ask_password_implementations ("/tls-interaction/ask-password/invoke-with-loop",
- setup_with_thread_loop, test_invoke_ask_password,
- teardown_with_thread_loop, fixtures);
- test_with_sync_ask_password_implementations ("/tls-interaction/ask-password/invoke-with-loop",
- setup_with_thread_loop, test_invoke_ask_password,
- teardown_with_thread_loop, fixtures);
-
- test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/invoke-without-loop",
- setup_without_loop, test_invoke_ask_password,
- teardown_without_loop, fixtures);
- test_with_async_ask_password_implementations ("/tls-interaction/ask-password/invoke-without-loop",
- setup_without_loop, test_invoke_ask_password,
- teardown_without_loop, fixtures);
- test_with_sync_ask_password_implementations ("/tls-interaction/ask-password/invoke-without-loop",
- setup_without_loop, test_invoke_ask_password,
- teardown_without_loop, fixtures);
-
- test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/invoke-in-loop",
- setup_with_normal_loop, test_invoke_ask_password,
- teardown_with_normal_loop, fixtures);
- test_with_async_ask_password_implementations ("/tls-interaction/ask-password/invoke-in-loop",
- setup_with_normal_loop, test_invoke_ask_password,
- teardown_with_normal_loop, fixtures);
- test_with_sync_ask_password_implementations ("/tls-interaction/ask-password/invoke-in-loop",
- setup_with_normal_loop, test_invoke_ask_password,
- teardown_with_normal_loop, fixtures);
+ /* Tests for g_tls_interaction_ask_password_async */
+ test_with_unhandled_ask_password ("/tls-interaction/ask-password/async",
+ setup_with_normal_loop, test_ask_password_async,
teardown_with_normal_loop);
+ test_with_async_ask_password ("/tls-interaction/ask-password/async",
+ setup_with_normal_loop, test_ask_password_async, teardown_with_normal_loop);
+
+ /* Tests for g_tls_interaction_invoke_request_certificate */
+ test_with_all_request_certificate ("/tls-interaction/request-certificate/invoke-with-loop",
+ setup_with_thread_loop, test_invoke_request_certificate,
teardown_with_thread_loop);
+ test_with_all_request_certificate ("/tls-interaction/request-certificate/invoke-without-loop",
+ setup_without_loop, test_invoke_request_certificate,
teardown_without_loop);
+ test_with_all_request_certificate ("/tls-interaction/request-certificate/invoke-in-loop",
+ setup_with_normal_loop, test_invoke_request_certificate,
teardown_with_normal_loop);
/* Tests for g_tls_interaction_ask_password */
- test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/sync",
- setup_without_loop, test_ask_password,
- teardown_without_loop, fixtures);
- test_with_sync_ask_password_implementations ("/tls-interaction/ask-password/sync",
- setup_without_loop, test_ask_password,
- teardown_without_loop, fixtures);
+ test_with_unhandled_request_certificate ("/tls-interaction/request-certificate/sync",
+ setup_without_loop, test_request_certificate,
teardown_without_loop);
+ test_with_sync_request_certificate ("/tls-interaction/request-certificate/sync",
+ setup_without_loop, test_request_certificate, teardown_without_loop);
/* Tests for g_tls_interaction_ask_password_async */
- test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/async",
- setup_with_normal_loop, test_ask_password_async,
- teardown_with_normal_loop, fixtures);
- test_with_async_ask_password_implementations ("/tls-interaction/ask-password/async",
- setup_with_normal_loop, test_ask_password_async,
- teardown_with_normal_loop, fixtures);
+ test_with_unhandled_request_certificate ("/tls-interaction/request-certificate/async",
+ setup_with_normal_loop, test_request_certificate_async,
teardown_with_normal_loop);
+ test_with_async_request_certificate ("/tls-interaction/request-certificate/async",
+ setup_with_normal_loop, test_request_certificate_async,
teardown_with_normal_loop);
ret = g_test_run();
g_ptr_array_free (fixtures, TRUE);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]