[evolution] Bug #690177 - Use trust-prompt for certificate verification in WebDAV backends



commit 957ff43705edfb964c5e096fac2e9dda6c132f03
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jan 9 23:05:25 2013 +0100

    Bug #690177 - Use trust-prompt for certificate verification in WebDAV backends

 e-util/e-source-config.c                     |   37 +++++--
 modules/cal-config-caldav/e-caldav-chooser.c |  155 +++++++++++++++++++++++---
 2 files changed, 166 insertions(+), 26 deletions(-)
---
diff --git a/e-util/e-source-config.c b/e-util/e-source-config.c
index aacb48d..3ffd303 100644
--- a/e-util/e-source-config.c
+++ b/e-util/e-source-config.c
@@ -1352,6 +1352,26 @@ secure_to_port_cb (GBinding *binding,
 	return TRUE;
 }
 
+static gboolean
+webdav_source_ssl_trust_to_sensitive_cb (GBinding *binding,
+					 const GValue *source_value,
+					 GValue *target_value,
+					 gpointer user_data)
+{
+	const gchar *ssl_trust = g_value_get_string (source_value);
+
+	g_value_set_boolean (target_value, ssl_trust && *ssl_trust);
+
+	return TRUE;
+}
+
+static void
+webdav_unset_ssl_trust_clicked_cb (GtkWidget *button,
+				   ESourceWebdav *extension)
+{
+	e_source_webdav_set_ssl_trust (extension, NULL);
+}
+
 void
 e_source_config_add_secure_connection_for_webdav (ESourceConfig *config,
                                                   ESource *scratch_source)
@@ -1393,22 +1413,19 @@ e_source_config_add_secure_connection_for_webdav (ESourceConfig *config,
 	extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
 	extension = e_source_get_extension (scratch_source, extension_name);
 
-	label = _("Ignore invalid SSL certificate");
-	widget2 = gtk_check_button_new_with_label (label);
+	widget2 = gtk_button_new_with_mnemonic (_("Unset _trust for SSL certificate"));
 	gtk_widget_set_margin_left (widget2, 24);
 	e_source_config_insert_widget (config, scratch_source, NULL, widget2);
 	gtk_widget_show (widget2);
 
-	g_object_bind_property (
-		widget1, "active",
+	g_object_bind_property_full (
+		extension, "ssl-trust",
 		widget2, "sensitive",
-		G_BINDING_SYNC_CREATE);
+		G_BINDING_SYNC_CREATE,
+		webdav_source_ssl_trust_to_sensitive_cb,
+		NULL, NULL, NULL);
 
-	g_object_bind_property (
-		extension, "ignore-invalid-cert",
-		widget2, "active",
-		G_BINDING_BIDIRECTIONAL |
-		G_BINDING_SYNC_CREATE);
+	g_signal_connect (widget2, "clicked", G_CALLBACK (webdav_unset_ssl_trust_clicked_cb), extension);
 }
 
 void
diff --git a/modules/cal-config-caldav/e-caldav-chooser.c b/modules/cal-config-caldav/e-caldav-chooser.c
index 8bb5fae..d5b514d 100644
--- a/modules/cal-config-caldav/e-caldav-chooser.c
+++ b/modules/cal-config-caldav/e-caldav-chooser.c
@@ -57,6 +57,8 @@ struct _ECaldavChooserPrivate {
 
 struct _Context {
 	SoupSession *session;
+	ESourceRegistry *registry;
+	ESource *source;
 
 	GCancellable *cancellable;
 	gulong cancelled_handler_id;
@@ -139,6 +141,8 @@ context_new (ECaldavChooser *chooser,
 
 	context = g_slice_new0 (Context);
 	context->session = g_object_ref (chooser->priv->session);
+	context->registry = g_object_ref (chooser->priv->registry);
+	context->source = g_object_ref (chooser->priv->source);
 
 	if (cancellable != NULL) {
 		context->cancellable = g_object_ref (cancellable);
@@ -157,6 +161,12 @@ context_free (Context *context)
 	if (context->session != NULL)
 		g_object_unref (context->session);
 
+	if (context->registry != NULL)
+		g_object_unref (context->registry);
+
+	if (context->source != NULL)
+		g_object_unref (context->source);
+
 	if (context->cancellable != NULL) {
 		g_cancellable_disconnect (
 			context->cancellable,
@@ -171,6 +181,76 @@ context_free (Context *context)
 	g_slice_free (Context, context);
 }
 
+static ETrustPromptResponse
+trust_prompt_sync (const ENamedParameters *parameters,
+		   GCancellable *cancellable,
+		   GError **error)
+{
+	EUserPrompter *prompter;
+	gint response;
+	gboolean asked = FALSE;
+
+	g_return_val_if_fail (parameters != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN);
+
+	prompter = e_user_prompter_new ();
+	g_return_val_if_fail (prompter != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN);
+
+	/* before libsoup 2.41.3 the certificate was not set on failed requests,
+	   thus do a simple prompt only in such case
+	*/
+	#ifdef SOUP_CHECK_VERSION
+	#if SOUP_CHECK_VERSION(2, 41, 3)
+	asked = TRUE;
+	response = e_user_prompter_extension_prompt_sync (prompter, "ETrustPrompt::trust-prompt", parameters, NULL, cancellable, error);
+	#endif
+	#endif
+
+	if (!asked) {
+		GSList *button_captions = NULL;
+		const gchar *markup;
+		gchar *tmp = NULL;
+
+		button_captions = g_slist_append (button_captions, _("_Reject"));
+		button_captions = g_slist_append (button_captions, _("Accept _Temporarily"));
+		button_captions = g_slist_append (button_captions, _("_Accept Permanently"));
+
+		markup = e_named_parameters_get (parameters, "markup");
+		if (!markup) {
+			gchar *bhost;
+
+			bhost = g_strconcat ("<b>", e_named_parameters_get (parameters, "host"), "</b>", NULL);
+			tmp = g_strdup_printf (_("SSL certificate for '%s' is not trusted. Do you wish to accept it?"), bhost);
+			g_free (bhost);
+
+			markup = tmp;
+		}
+
+		response = e_user_prompter_prompt_sync (prompter, "question", _("Certificate trust..."),
+			markup, NULL, TRUE, button_captions, cancellable, NULL);
+
+		if (response == 1)
+			response = 2;
+		else if (response == 2)
+			response = 1;
+
+		g_slist_free (button_captions);
+		g_free (tmp);
+	}
+
+	g_object_unref (prompter);
+
+	if (response == 0)
+		return E_TRUST_PROMPT_RESPONSE_REJECT;
+	if (response == 1)
+		return E_TRUST_PROMPT_RESPONSE_ACCEPT;
+	if (response == 2)
+		return E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY;
+	if (response == -1)
+		return E_TRUST_PROMPT_RESPONSE_REJECT_TEMPORARILY;
+
+	return E_TRUST_PROMPT_RESPONSE_UNKNOWN;
+}
+
 static void
 caldav_chooser_redirect (SoupMessage *message,
                          SoupSession *session)
@@ -337,20 +417,6 @@ static void
 caldav_chooser_configure_session (ECaldavChooser *chooser,
                                   SoupSession *session)
 {
-	ESource *source;
-	ESourceWebdav *extension;
-	const gchar *extension_name;
-
-	source = e_caldav_chooser_get_source (chooser);
-	extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
-	extension = e_source_get_extension (source, extension_name);
-
-	g_object_bind_property (
-		extension, "ignore-invalid-cert",
-		session, SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE,
-		G_BINDING_SYNC_CREATE |
-		G_BINDING_INVERT_BOOLEAN);
-
 	if (g_getenv ("CALDAV_DEBUG") != NULL) {
 		SoupLogger *logger;
 
@@ -361,7 +427,11 @@ caldav_chooser_configure_session (ECaldavChooser *chooser,
 		g_object_unref (logger);
 	}
 
-	g_object_set (session, SOUP_SESSION_TIMEOUT, 90, NULL);
+	g_object_set (session,
+		SOUP_SESSION_TIMEOUT, 90,
+		SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
+		SOUP_SESSION_SSL_STRICT, TRUE,
+		NULL);
 
 	/* This adds proxy support. */
 	soup_session_add_feature_by_type (
@@ -936,6 +1006,34 @@ caldav_chooser_calendar_home_set_cb (SoupSession *session,
 
 	context = g_simple_async_result_get_op_res_gpointer (simple);
 
+	if (message->status_code == SOUP_STATUS_SSL_FAILED) {
+		ETrustPromptResponse response;
+		ENamedParameters *parameters;
+		ESourceWebdav *extension;
+
+		extension = e_source_get_extension (context->source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
+		parameters = e_named_parameters_new ();
+
+		response = e_source_webdav_prepare_ssl_trust_prompt (extension, message, context->registry, parameters);
+		if (response == E_TRUST_PROMPT_RESPONSE_UNKNOWN) {
+			response = trust_prompt_sync (parameters, context->cancellable, NULL);
+			if (response != E_TRUST_PROMPT_RESPONSE_UNKNOWN)
+				e_source_webdav_store_ssl_trust_prompt (extension, message, response);
+		}
+
+		e_named_parameters_free (parameters);
+
+		if (response == E_TRUST_PROMPT_RESPONSE_ACCEPT ||
+		    response == E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY) {
+			g_object_set (context->session, SOUP_SESSION_SSL_STRICT, FALSE, NULL);
+
+			soup_session_queue_message (
+				context->session, g_object_ref (message), (SoupSessionCallback)
+				caldav_chooser_calendar_home_set_cb, simple);
+			return;
+		}
+	}
+
 	doc = caldav_chooser_parse_xml (message, "multistatus", &error);
 
 	/* If we were cancelled then we're in a GCancellable::cancelled
@@ -1356,7 +1454,32 @@ caldav_chooser_try_password_sync (ESourceAuthenticator *auth,
 			g_object_ref (session),
 			(GDestroyNotify) g_object_unref);
 
-	soup_session_send_message (session, message);
+	g_object_set (session, SOUP_SESSION_SSL_STRICT, TRUE, NULL);
+	g_object_set (chooser->priv->session, SOUP_SESSION_SSL_STRICT, TRUE, NULL);
+
+	if (soup_session_send_message (session, message) == SOUP_STATUS_SSL_FAILED) {
+		ETrustPromptResponse response;
+		ENamedParameters *parameters;
+
+		parameters = e_named_parameters_new ();
+
+		response = e_source_webdav_prepare_ssl_trust_prompt (extension, message, chooser->priv->registry, parameters);
+		if (response == E_TRUST_PROMPT_RESPONSE_UNKNOWN) {
+			response = trust_prompt_sync (parameters, cancellable, NULL);
+			if (response != E_TRUST_PROMPT_RESPONSE_UNKNOWN)
+				e_source_webdav_store_ssl_trust_prompt (extension, message, response);
+		}
+
+		e_named_parameters_free (parameters);
+
+		if (response == E_TRUST_PROMPT_RESPONSE_ACCEPT ||
+		    response == E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY) {
+			g_object_set (session, SOUP_SESSION_SSL_STRICT, FALSE, NULL);
+			g_object_set (chooser->priv->session, SOUP_SESSION_SSL_STRICT, FALSE, NULL);
+			soup_session_send_message (session, message);
+		}
+	}
+	
 
 	if (cancel_id > 0)
 		g_cancellable_disconnect (cancellable, cancel_id);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]