[evolution-kolab/ek-wip-porting: 11/14] CamelKolabSession: fixups for authentication



commit cecf6129b21e3cdda102b5bfc5c9c487e21c5c22
Author: Christian Hilberg <hilberg kernelconcepts de>
Date:   Tue Mar 13 17:52:52 2012 +0100

    CamelKolabSession: fixups for authentication
    
    * added a dupe of the mail_session_authenticate_sync()
      function from e-mail-session.c in evolution's libemail-engine
      (CamelSession does no longer provide a production-ready
      implementation for this)
    * reworked password handling (needs further cleanup)
    * removed no-longer needed API functions (the ones
      needed are now accessible via virtualized functions)

 src/camel/camel-kolab-session.c |  381 ++++++++++++++++++++++++---------------
 src/camel/camel-kolab-session.h |   31 +---
 2 files changed, 240 insertions(+), 172 deletions(-)
---
diff --git a/src/camel/camel-kolab-session.c b/src/camel/camel-kolab-session.c
index b54210b..081e6e4 100644
--- a/src/camel/camel-kolab-session.c
+++ b/src/camel/camel-kolab-session.c
@@ -51,6 +51,7 @@
 /* Kolab error reporting */
 #include <libekolabutil/kolab-util-error.h>
 
+#include "camel-kolab-imapx-store.h"
 #include "camel-kolab-session.h"
 
 /*----------------------------------------------------------------------------*/
@@ -64,8 +65,6 @@ struct _CamelKolabSessionPrivate {
 	/* TODO these should be retrieved
 	 * from CamelKolabSettings instead
 	 */
-	gchar *data_dir;
-	gchar *config_dir;
 	gchar *passwd;
 
 	/* TODO get rid of this workaround */
@@ -88,8 +87,6 @@ camel_kolab_session_init (CamelKolabSession *self)
 	g_assert (CAMEL_IS_KOLAB_SESSION (self));
 	priv = CAMEL_KOLAB_SESSION_PRIVATE (self);
 
-	priv->data_dir = NULL;
-	priv->config_dir = NULL;
 	priv->nss_tok_pwd = NULL;
 	priv->passwd = NULL;
 	priv->is_initialized = FALSE;
@@ -110,15 +107,9 @@ camel_kolab_session_finalize (GObject *object)
 	CamelKolabSession *self = NULL;
 	CamelKolabSessionPrivate *priv = NULL;
 
-	g_assert (CAMEL_IS_KOLAB_SESSION (self));
-
 	self = CAMEL_KOLAB_SESSION (object);
 	priv = CAMEL_KOLAB_SESSION_PRIVATE (self);
 
-	if (priv->data_dir != NULL)
-		g_free (priv->data_dir);
-	if (priv->config_dir != NULL)
-		g_free (priv->config_dir);
 	if (priv->nss_tok_pwd != NULL)
 		g_free (priv->nss_tok_pwd);
 	if (priv->passwd)
@@ -128,29 +119,8 @@ camel_kolab_session_finalize (GObject *object)
 	G_OBJECT_CLASS (camel_kolab_session_parent_class)->finalize (object);
 }
 
-static void
-camel_kolab_session_class_init (CamelKolabSessionClass *klass)
-{
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-	CamelSessionClass *session_class = CAMEL_SESSION_CLASS (klass);
-	CamelSessionClass *parent_class = CAMEL_SESSION_CLASS (camel_kolab_session_parent_class);
-
-	g_type_class_add_private (klass, sizeof (CamelKolabSessionPrivate));
-
-	object_class->set_property = G_OBJECT_CLASS (parent_class)->set_property;
-	object_class->get_property = G_OBJECT_CLASS (parent_class)->get_property;
-	object_class->dispose = camel_kolab_session_dispose;
-	object_class->finalize = camel_kolab_session_finalize;
-
-	session_class->add_service = parent_class->add_service; /* TODO need to override this */
-
-	session_class->authenticate_sync = parent_class->authenticate_sync;
-	session_class->authenticate = parent_class->authenticate;
-	session_class->authenticate_finish = parent_class->authenticate_finish;
-}
-
 /*----------------------------------------------------------------------------*/
-/* password callbacks */
+/* local statics */
 
 /* NSS token pin callback */
 static gchar* PR_CALLBACK
@@ -169,185 +139,283 @@ pk11_password (PK11SlotInfo *slot,
 }
 
 /*----------------------------------------------------------------------------*/
-
-gboolean
-camel_kolab_session_bringup (CamelKolabSession *self,
-                             GCancellable *cancellable,
-                             GError **err)
+/* class functions */
+
+static gchar*
+kolab_session_get_password (CamelSession *self,
+                            CamelService *service,
+                            const gchar *prompt,
+                            const gchar *item,
+                            guint32 flags,
+                            GError **err)
 {
-	/* TODO rework to use GInitable */
+	/* TODO rework to CamelSettings */
 
+	CamelKolabSession *myself = NULL;
 	CamelKolabSessionPrivate *priv = NULL;
 
 	g_assert (CAMEL_IS_KOLAB_SESSION (self));
-	(void)cancellable; /* FIXME */ /* cancellable may be NULL */
-	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
-
-	priv = CAMEL_KOLAB_SESSION_PRIVATE (self);
+	g_assert (CAMEL_IS_KOLAB_IMAPX_STORE (service));
+	g_return_val_if_fail (err == NULL || *err == NULL, NULL);
 
-	if (priv->is_initialized)
-		return TRUE;
+	(void)prompt;
+	(void)item;
+	(void)flags;
 
-	/* TODO need to supply (parts of) storage paths here so the imap
-	 *	objects for the backends will store their files in their
-	 *	own respective directories
-	 */
+	myself = CAMEL_KOLAB_SESSION (self);
+	priv = CAMEL_KOLAB_SESSION_PRIVATE (myself);
 
-	/* TODO check whether this is The Right Way to
-	 *	initialize the session parent
-	 */
-	if (priv->data_dir == NULL) {
-		g_set_error (err,
-		             KOLAB_CAMEL_KOLAB_ERROR,
-		             KOLAB_CAMEL_KOLAB_ERROR_GENERIC,
-		             _("Camel data directory not configured"));
-		return FALSE;
-	}
-
-	/* TODO junk settings */
-
-	/* setup further NSS bits here */
-	PK11_SetPasswordFunc (pk11_password);
-
-	priv->is_initialized = TRUE;
-	g_debug ("%s: camel session initialized",
-	         __func__);
-
-	return TRUE;
+	return g_strdup (priv->passwd);
 }
 
-gboolean
-camel_kolab_session_shutdown (CamelKolabSession *self,
-                              GCancellable *cancellable,
-                              GError **err)
+static void
+kolab_session_forget_password (CamelSession *self,
+                               CamelService *service,
+                               const gchar *item,
+                               GError **err)
 {
+	/* TODO rework to CamelSettings */
+
+	CamelKolabSession *myself = NULL;
 	CamelKolabSessionPrivate *priv = NULL;
 
 	g_assert (CAMEL_IS_KOLAB_SESSION (self));
-	(void)cancellable; /* FIXME */ /* cancellable may be NULL */
-	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+	g_assert (CAMEL_IS_KOLAB_IMAPX_STORE (service));
+	g_return_if_fail (err == NULL || *err == NULL);
 
-	priv = CAMEL_KOLAB_SESSION_PRIVATE (self);
-
-	if (! priv->is_initialized)
-		return TRUE;
+	(void)item;
 
-	g_debug ("%s: camel session shut down",
-	         __func__);
+	myself = CAMEL_KOLAB_SESSION (self);
+	priv = CAMEL_KOLAB_SESSION_PRIVATE (myself);
 
-	return TRUE;
+	if (priv->passwd != NULL) {
+		g_free (priv->passwd);
+		priv->passwd = NULL;
+	}
 }
 
-/*----------------------------------------------------------------------------*/
-
-void
-camel_kolab_session_set_data_dir (CamelKolabSession *self,
-                                  gchar *datadir)
+static gboolean
+kolab_session_authenticate_sync (CamelSession *session,
+                                 CamelService *service,
+                                 const gchar *mechanism,
+                                 GCancellable *cancellable,
+                                 GError **error)
 {
-	/* TODO rework to use CamelSettings */
+	CamelServiceAuthType *authtype = NULL;
+	CamelAuthenticationResult result;
+	CamelProvider *provider;
+	CamelSettings *settings;
+	const gchar *password;
+	guint32 password_flags;
+	GError *local_error = NULL;
+
+	/* this is a dupe of mail_session_authenticate_sync()
+	 * from e-mail-session.c in evolution's libemail-engine.
+	 *
+	 * Once libemail-engine becomes part of E-D-S, we
+	 * might be able to just drop this dupe and use
+	 * the original function from there directly
+	 */
 
-	CamelKolabSessionPrivate *priv = NULL;
+	/* Do not chain up.  Camel's default method is only an example for
+	 * subclasses to follow.  Instead we mimic most of its logic here. */
+
+	provider = camel_service_get_provider (service);
+	settings = camel_service_get_settings (service);
+
+	/* APOP is one case where a non-SASL mechanism name is passed, so
+	 * don't bail if the CamelServiceAuthType struct comes back NULL. */
+	if (mechanism != NULL)
+		authtype = camel_sasl_authtype (mechanism);
+
+	/* If the SASL mechanism does not involve a user
+	 * password, then it gets one shot to authenticate. */
+	if (authtype != NULL && !authtype->need_password) {
+		result = camel_service_authenticate_sync (
+			service, mechanism, cancellable, error);
+		if (result == CAMEL_AUTHENTICATION_REJECTED)
+			g_set_error (
+				error, CAMEL_SERVICE_ERROR,
+				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+				_("%s authentication failed"), mechanism);
+		return (result == CAMEL_AUTHENTICATION_ACCEPTED);
+	}
 
-	g_assert (CAMEL_IS_KOLAB_SESSION (self));
-	g_assert (datadir != NULL);
+	/* Some SASL mechanisms can attempt to authenticate without a
+	 * user password being provided (e.g. single-sign-on credentials),
+	 * but can fall back to a user password.  Handle that case next. */
+	if (mechanism != NULL) {
+		CamelProvider *provider;
+		CamelSasl *sasl;
+		const gchar *service_name;
+		gboolean success = FALSE;
+
+		provider = camel_service_get_provider (service);
+		service_name = provider->protocol;
+
+		/* XXX Would be nice if camel_sasl_try_empty_password_sync()
+		 *     returned CamelAuthenticationResult so it's easier to
+		 *     detect errors. */
+		sasl = camel_sasl_new (service_name, mechanism, service);
+		if (sasl != NULL) {
+			success = camel_sasl_try_empty_password_sync (
+				sasl, cancellable, &local_error);
+			g_object_unref (sasl);
+		}
+
+		if (success)
+			return TRUE;
+	}
 
-	priv = CAMEL_KOLAB_SESSION_PRIVATE (self);
+	/* Abort authentication if we got cancelled.
+	 * Otherwise clear any errors and press on. */
+	if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+		return FALSE;
 
-	if (priv->data_dir != NULL)
-		g_free (priv->data_dir);
+	g_clear_error (&local_error);
 
-	priv->data_dir = datadir;
-}
+	password_flags = CAMEL_SESSION_PASSWORD_SECRET;
 
-const gchar*
-camel_kolab_session_get_data_dir (CamelKolabSession *self)
-{
-	/* TODO rework to use CamelSettings */
+retry:
+	password = camel_service_get_password (service);
 
-	CamelKolabSessionPrivate *priv = NULL;
+	if (password == NULL) {
+		CamelNetworkSettings *network_settings;
+		const gchar *host;
+		const gchar *user;
+		gchar *prompt;
+		gchar *new_passwd;
 
-	g_assert (CAMEL_IS_KOLAB_SESSION (self));
-	priv = CAMEL_KOLAB_SESSION_PRIVATE (self);
+		network_settings = CAMEL_NETWORK_SETTINGS (settings);
+		host = camel_network_settings_get_host (network_settings);
+		user = camel_network_settings_get_user (network_settings);
 
-	return priv->data_dir;
-}
+		prompt = camel_session_build_password_prompt (
+			provider->name, user, host);
 
-void
-camel_kolab_session_set_config_dir (CamelKolabSession *self,
-                                    const gchar *configdir)
-{
-	/* TODO rework to use CamelSettings */
+		new_passwd = camel_session_get_password (
+			session, service, prompt, "password",
+			password_flags, &local_error);
+		camel_service_set_password (service, new_passwd);
+		password = camel_service_get_password (service);
+		g_free (new_passwd);
 
-	CamelKolabSessionPrivate *priv = NULL;
+		g_free (prompt);
 
-	g_assert (CAMEL_IS_KOLAB_SESSION (self));
-	g_assert (configdir != NULL);
+		if (local_error != NULL) {
+			g_propagate_error (error, local_error);
+			return FALSE;
+		}
 
-	priv = CAMEL_KOLAB_SESSION_PRIVATE (self);
+		if (password == NULL) {
+			g_set_error (
+				error, CAMEL_SERVICE_ERROR,
+				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+				_("No password was provided"));
+			return FALSE;
+		}
+	}
 
-	if (priv->config_dir != NULL)
-		g_free (priv->config_dir);
+	result = camel_service_authenticate_sync (
+		service, mechanism, cancellable, error);
 
-	priv->config_dir = g_strdup (configdir);
+	if (result == CAMEL_AUTHENTICATION_REJECTED) {
+		password_flags |= CAMEL_SESSION_PASSWORD_REPROMPT;
+		camel_service_set_password (service, NULL);
+		goto retry;
+	}
+
+	return (result == CAMEL_AUTHENTICATION_ACCEPTED);
 }
 
-const gchar*
-camel_kolab_session_get_config_dir (CamelKolabSession *self)
+/*----------------------------------------------------------------------------*/
+/* class init */
+
+static void
+camel_kolab_session_class_init (CamelKolabSessionClass *klass)
 {
-	/* TODO rework to use CamelSettings */
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	CamelSessionClass *session_class = CAMEL_SESSION_CLASS (klass);
+	CamelSessionClass *parent_class = CAMEL_SESSION_CLASS (camel_kolab_session_parent_class);
 
-	CamelKolabSessionPrivate *priv = NULL;
+	g_type_class_add_private (klass, sizeof (CamelKolabSessionPrivate));
 
-	g_assert (CAMEL_IS_KOLAB_SESSION (self));
-	priv = CAMEL_KOLAB_SESSION_PRIVATE (self);
+	object_class->set_property = G_OBJECT_CLASS (parent_class)->set_property;
+	object_class->get_property = G_OBJECT_CLASS (parent_class)->get_property;
+	object_class->dispose = camel_kolab_session_dispose;
+	object_class->finalize = camel_kolab_session_finalize;
 
-	return priv->config_dir;
+	session_class->add_service = parent_class->add_service;
+	session_class->get_password = kolab_session_get_password;
+	session_class->forget_password = kolab_session_forget_password;
+#if 0
+	session_class->alert_user = kolab_session_alert_user;
+	session_class->get_filter_driver = kolab_session_get_filter_driver;
+	session_class->lookup_addressbook = kolab_session_lookup_addressbook;
+	session_class->forward_to = kolab_session_forward_to;
+	session_class->get_socks_proxy = kolab_session_get_socks_proxy;
+#endif
+	session_class->authenticate_sync = kolab_session_authenticate_sync;
 }
 
-const gchar*
-camel_kolab_session_get_password (CamelKolabSession *self)
+/*----------------------------------------------------------------------------*/
+/* public API */
+
+gboolean
+camel_kolab_session_bringup (CamelKolabSession *self,
+                             GCancellable *cancellable,
+                             GError **err)
 {
-	/* TODO rework to CamelSettings */
+	/* TODO rework to use GInitable */
 
 	CamelKolabSessionPrivate *priv = NULL;
 
 	g_assert (CAMEL_IS_KOLAB_SESSION (self));
+	(void)cancellable; /* FIXME */ /* cancellable may be NULL */
+	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
 	priv = CAMEL_KOLAB_SESSION_PRIVATE (self);
 
-	return priv->passwd;
-}
+	if (priv->is_initialized)
+		return TRUE;
 
-void
-camel_kolab_session_forget_password (CamelKolabSession *self)
-{
-	/* TODO rework to CamelSettings */
+	/* TODO need to supply (parts of) storage paths here so the imap
+	 *	objects for the backends will store their files in their
+	 *	own respective directories
+	 */
 
-	CamelKolabSessionPrivate *priv = NULL;
+	/* TODO junk settings */
 
-	g_assert (CAMEL_IS_KOLAB_SESSION (self));
-	priv = CAMEL_KOLAB_SESSION_PRIVATE (self);
+	/* setup further NSS bits here */
+	PK11_SetPasswordFunc (pk11_password);
 
-	if (priv->passwd != NULL) {
-		g_free (priv->passwd);
-		priv->passwd = NULL;
-	}
+	priv->is_initialized = TRUE;
+	g_debug ("%s: camel session initialized",
+	         __func__);
+
+	return TRUE;
 }
 
-void
-camel_kolab_session_set_password (CamelKolabSession *self,
-                                  const gchar *passwd)
+gboolean
+camel_kolab_session_shutdown (CamelKolabSession *self,
+                              GCancellable *cancellable,
+                              GError **err)
 {
-	/* TODO rework to CamelSettings */
-
 	CamelKolabSessionPrivate *priv = NULL;
 
 	g_assert (CAMEL_IS_KOLAB_SESSION (self));
+	(void)cancellable; /* FIXME */ /* cancellable may be NULL */
+	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
 	priv = CAMEL_KOLAB_SESSION_PRIVATE (self);
 
-	if (priv->passwd != NULL)
-		g_free (priv->passwd);
+	if (! priv->is_initialized)
+		return TRUE;
 
-	priv->passwd = g_strdup (passwd);
+	g_debug ("%s: camel session shut down",
+	         __func__);
+
+	return TRUE;
 }
 
 void
@@ -371,4 +439,21 @@ camel_kolab_session_set_token_pin (CamelKolabSession *self,
 	nss_tok_pin = g_strdup (pin);
 }
 
+void
+camel_kolab_session_set_password (CamelKolabSession *self,
+                                  const gchar *passwd)
+{
+	/* TODO rework to CamelSettings */
+
+	CamelKolabSessionPrivate *priv = NULL;
+
+	g_assert (CAMEL_IS_KOLAB_SESSION (self));
+	priv = CAMEL_KOLAB_SESSION_PRIVATE (self);
+
+	if (priv->passwd != NULL)
+		g_free (priv->passwd);
+
+	priv->passwd = g_strdup (passwd);
+}
+
 /*----------------------------------------------------------------------------*/
diff --git a/src/camel/camel-kolab-session.h b/src/camel/camel-kolab-session.h
index 03c1323..78be880 100644
--- a/src/camel/camel-kolab-session.h
+++ b/src/camel/camel-kolab-session.h
@@ -47,6 +47,11 @@
 #include <libekolabutil/camel-system-headers.h>
 
 /*----------------------------------------------------------------------------*/
+
+#define CAMEL_KOLAB_SESSION_PROP_DATA_DIR  "user-data-dir"
+#define CAMEL_KOLAB_SESSION_PROP_CACHE_DIR "user-cache-dir"
+
+/*----------------------------------------------------------------------------*/
 /* Standard GObject macros */
 
 #define CAMEL_TYPE_KOLAB_SESSION	  \
@@ -95,34 +100,12 @@ camel_kolab_session_shutdown (CamelKolabSession *self,
                               GError **err);
 
 void
-camel_kolab_session_set_password (CamelKolabSession *self,
-                                  const gchar *passwd);
-
-void
 camel_kolab_session_set_token_pin (CamelKolabSession *self,
                                    const gchar *pin);
 
 void
-camel_kolab_session_set_data_dir (CamelKolabSession *self,
-                                  gchar *datadir);
-
-const gchar*
-camel_kolab_session_get_data_dir (CamelKolabSession *self);
-
-void
-camel_kolab_session_set_config_dir (CamelKolabSession *self,
-                                    const gchar *configdir);
-
-const gchar*
-camel_kolab_session_get_config_dir (CamelKolabSession *self);
-
-const gchar*
-camel_kolab_session_get_password (CamelKolabSession *self);
-
-void
-camel_kolab_session_forget_password (CamelKolabSession *self);
-
-
+camel_kolab_session_set_password (CamelKolabSession *self,
+                                  const gchar *passwd);
 
 G_END_DECLS
 



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