[evolution-ews] Check for supported authentication methods by the server
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews] Check for supported authentication methods by the server
- Date: Mon, 23 Sep 2013 20:10:39 +0000 (UTC)
commit d7142c6d00110c5010552d3960e4cc5dfdc35274
Author: Milan Crha <mcrha redhat com>
Date: Mon Sep 23 22:10:08 2013 +0200
Check for supported authentication methods by the server
The EEwsConnection can check for supported authentication methods as
advertised by the server in WWW-Authenticate response headers and
check it against supported authentications by itself. One disadvantage
is that the headers are returned only until the connection is
connected, thus the function can be called on fresh connection only.
src/camel/camel-ews-store.c | 62 ++++++++++++-
src/server/e-ews-connection.c | 209 ++++++++++++++++++++++++++++++++++++++---
src/server/e-ews-connection.h | 20 ++++
3 files changed, 276 insertions(+), 15 deletions(-)
---
diff --git a/src/camel/camel-ews-store.c b/src/camel/camel-ews-store.c
index 8482e73..3afda8e 100644
--- a/src/camel/camel-ews-store.c
+++ b/src/camel/camel-ews-store.c
@@ -1277,14 +1277,70 @@ ews_authenticate_sync (CamelService *service,
return result;
}
-static GList *
+static GList *
ews_store_query_auth_types_sync (CamelService *service,
GCancellable *cancellable,
GError **error)
{
- g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Query for authentication types is
not supported"));
+ EEwsConnection *connection;
+ CamelSettings *settings;
+ CamelEwsSettings *ews_settings;
+ GList *auth_types = NULL;
+ GSList *auth_methods = NULL, *aiter;
+ gchar *hosturl;
+
+ g_return_val_if_fail (CAMEL_IS_EWS_STORE (service), NULL);
+
+ if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (service))) {
+ g_set_error (
+ error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_UNAVAILABLE,
+ _("You must be working online to complete this operation"));
+ return NULL;
+ }
+
+ settings = camel_service_ref_settings (service);
+ ews_settings = CAMEL_EWS_SETTINGS (settings);
+ hosturl = camel_ews_settings_dup_hosturl (ews_settings);
+ connection = e_ews_connection_new_full (hosturl, ews_settings, FALSE);
+ g_free (hosturl);
+ g_object_unref (settings);
+
+ if (e_ews_connection_query_auth_methods_sync (connection, G_PRIORITY_DEFAULT, &auth_methods,
cancellable, error)) {
+ CamelProvider *provider;
+ CamelServiceAuthType *authtype;
+
+ provider = camel_service_get_provider (service);
+ g_return_val_if_fail (provider != NULL, NULL);
+
+ for (aiter = auth_methods; aiter; aiter = aiter->next) {
+ GList *siter;
+ const gchar *auth = aiter->data;
+
+ if (!auth)
+ continue;
+
+ if (g_ascii_strcasecmp (auth, "NTLM") == 0)
+ auth = "";
+ else if (g_ascii_strcasecmp (auth, "Basic") == 0)
+ auth = "PLAIN";
+ else if (g_ascii_strcasecmp (auth, "Negotiate") == 0)
+ auth = "GSSAPI";
+
+ for (siter = provider->authtypes; siter; siter = siter->next) {
+ authtype = siter->data;
+
+ if (g_ascii_strcasecmp (authtype->authproto, auth) == 0)
+ auth_types = g_list_prepend (auth_types, authtype);
+ }
+ }
+
+ g_slist_free_full (auth_methods, g_free);
+ }
+
+ g_object_unref (connection);
- return NULL;
+ return g_list_reverse (auth_types);
}
static CamelFolderInfo * ews_create_folder_sync (CamelStore *store, const gchar *parent_name,const gchar
*folder_name, GCancellable *cancellable, GError **error);
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index ca635d3..91f8d51 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -1830,9 +1830,10 @@ e_ews_connection_find (const gchar *uri,
}
/**
- * e_ews_connection_new
+ * e_ews_connection_new_full
* @uri: Exchange server uri
* @settings: a #CamelEwsSettings
+ * @allow_connection_reuse: whether can return already created connection
*
* This does not authenticate to the server. It merely stores the username and password.
* Authentication happens when a request is made to the server.
@@ -1840,8 +1841,9 @@ e_ews_connection_find (const gchar *uri,
* Returns: EEwsConnection
**/
EEwsConnection *
-e_ews_connection_new (const gchar *uri,
- CamelEwsSettings *settings)
+e_ews_connection_new_full (const gchar *uri,
+ CamelEwsSettings *settings,
+ gboolean allow_connection_reuse)
{
CamelNetworkSettings *network_settings;
EEwsConnection *cnc;
@@ -1859,7 +1861,7 @@ e_ews_connection_new (const gchar *uri,
g_mutex_lock (&connecting);
/* search the connection in our hash table */
- if (loaded_connections_permissions != NULL) {
+ if (allow_connection_reuse && loaded_connections_permissions != NULL) {
cnc = g_hash_table_lookup (
loaded_connections_permissions, hash_key);
@@ -1905,14 +1907,16 @@ e_ews_connection_new (const gchar *uri,
cnc->priv->soup_session, "timeout",
G_BINDING_SYNC_CREATE);
- /* add the connection to the loaded_connections_permissions hash table */
- if (loaded_connections_permissions == NULL)
- loaded_connections_permissions = g_hash_table_new_full (
- g_str_hash, g_str_equal,
- g_free, NULL);
- g_hash_table_insert (
- loaded_connections_permissions,
- g_strdup (cnc->priv->hash_key), cnc);
+ if (allow_connection_reuse) {
+ /* add the connection to the loaded_connections_permissions hash table */
+ if (loaded_connections_permissions == NULL)
+ loaded_connections_permissions = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ g_free, NULL);
+ g_hash_table_insert (
+ loaded_connections_permissions,
+ g_strdup (cnc->priv->hash_key), cnc);
+ }
/* update proxy with set 'uri' */
proxy_settings_changed (cnc->priv->proxy, cnc);
@@ -1923,6 +1927,13 @@ e_ews_connection_new (const gchar *uri,
}
+EEwsConnection *
+e_ews_connection_new (const gchar *uri,
+ CamelEwsSettings *settings)
+{
+ return e_ews_connection_new_full (uri, settings, TRUE);
+}
+
const gchar *
e_ews_connection_get_uri (EEwsConnection *cnc)
{
@@ -8592,3 +8603,177 @@ e_ews_connection_find_folder_sync (EEwsConnection *cnc,
return success;
}
+
+#define EWS_OBJECT_KEY_AUTHS_GATHERED "ews-auths-gathered"
+
+static void
+query_auth_methods_response_cb (ESoapResponse *response,
+ GSimpleAsyncResult *simple)
+{
+ ESoapParameter *param;
+ GError *error = NULL;
+
+ param = e_soap_response_get_first_parameter_by_name (
+ response, "ResponseMessages", &error);
+
+ /* Sanity check */
+ g_return_if_fail (
+ (param != NULL && error == NULL) ||
+ (param == NULL && error != NULL));
+
+ if (error != NULL) {
+ g_simple_async_result_take_error (simple, error);
+ return;
+ }
+
+ /* nothing to read, it should not get this far anyway */
+}
+
+static void
+ews_connection_gather_auth_methods_cb (SoupMessage *message,
+ GSimpleAsyncResult *simple)
+{
+ EwsAsyncData *async_data;
+ const gchar *auths_lst;
+ gchar **auths;
+ gint ii;
+
+ async_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+ g_return_if_fail (async_data != NULL);
+
+ auths_lst = soup_message_headers_get_list (message->response_headers, "WWW-Authenticate");
+ if (!auths_lst)
+ return;
+
+ auths = g_strsplit (auths_lst, ",", -1);
+ for (ii = 0; auths && auths[ii]; ii++) {
+ gchar *auth, *space;
+
+ auth = g_strstrip (g_strdup (auths[ii]));
+ if (auth && *auth) {
+ space = strchr (auth, ' ');
+ if (space)
+ *space = '\0';
+
+ async_data->items = g_slist_prepend (async_data->items, auth);
+ } else {
+ g_free (auth);
+ }
+ }
+
+ g_strfreev (auths);
+
+ g_object_set_data (G_OBJECT (simple), EWS_OBJECT_KEY_AUTHS_GATHERED, GINT_TO_POINTER (1));
+
+ soup_message_set_status_full (message, SOUP_STATUS_CANCELLED, "EWS auths gathered");
+}
+
+/* Note: This only works if the connection is not connected yet */
+void
+e_ews_connection_query_auth_methods (EEwsConnection *cnc,
+ gint pri,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ ESoapMessage *msg;
+ GSimpleAsyncResult *simple;
+ EwsAsyncData *async_data;
+
+ g_return_if_fail (cnc != NULL);
+
+ /* use some simple operation to get WWW-Authenticate headers from the server */
+ msg = e_ews_message_new_with_header (
+ cnc->priv->uri,
+ cnc->priv->impersonate_user,
+ "GetFolder",
+ NULL,
+ NULL,
+ cnc->priv->version,
+ E_EWS_EXCHANGE_2007_SP1,
+ TRUE);
+
+ e_soap_message_start_element (msg, "FolderShape", "messages", NULL);
+ e_ews_message_write_string_parameter (msg, "BaseShape", NULL, "IdOnly");
+ e_soap_message_end_element (msg);
+
+ e_soap_message_start_element (msg, "FolderIds", "messages", NULL);
+ e_ews_message_write_string_parameter_with_attribute (msg, "DistinguishedFolderId", NULL, NULL, "Id",
"inbox");
+ e_soap_message_end_element (msg);
+
+ e_ews_message_write_footer (msg);
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (cnc), callback, user_data,
+ e_ews_connection_query_auth_methods);
+
+ async_data = g_new0 (EwsAsyncData, 1);
+ g_simple_async_result_set_op_res_gpointer (
+ simple, async_data, (GDestroyNotify) async_data_free);
+
+ soup_message_add_header_handler (SOUP_MESSAGE (msg), "got_body", "WWW-Authenticate",
+ G_CALLBACK (ews_connection_gather_auth_methods_cb), simple);
+
+ e_ews_connection_queue_request (
+ cnc, msg, query_auth_methods_response_cb,
+ pri, cancellable, simple);
+
+ g_object_unref (simple);
+}
+
+gboolean
+e_ews_connection_query_auth_methods_finish (EEwsConnection *cnc,
+ GAsyncResult *result,
+ GSList **auth_methods,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ EwsAsyncData *async_data;
+
+ g_return_val_if_fail (cnc != NULL, FALSE);
+ g_return_val_if_fail (auth_methods != NULL, FALSE);
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (cnc), e_ews_connection_query_auth_methods),
+ FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ async_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (simple), EWS_OBJECT_KEY_AUTHS_GATHERED)) != 1 &&
+ g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ *auth_methods = g_slist_reverse (async_data->items);
+
+ return TRUE;
+}
+
+/* Note: This only works if the connection is not connected yet */
+gboolean
+e_ews_connection_query_auth_methods_sync (EEwsConnection *cnc,
+ gint pri,
+ GSList **auth_methods,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gboolean success;
+
+ g_return_val_if_fail (cnc != NULL, FALSE);
+
+ closure = e_async_closure_new ();
+
+ e_ews_connection_query_auth_methods (cnc, pri, cancellable, e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ success = e_ews_connection_query_auth_methods_finish (
+ cnc, result, auth_methods, error);
+
+ e_async_closure_free (closure);
+
+ return success;
+}
diff --git a/src/server/e-ews-connection.h b/src/server/e-ews-connection.h
index 53d3fc7..0d72bd1 100644
--- a/src/server/e-ews-connection.h
+++ b/src/server/e-ews-connection.h
@@ -214,6 +214,9 @@ void e_ews_connection_utils_unref_in_thread
GType e_ews_connection_get_type (void);
EEwsConnection *e_ews_connection_new (const gchar *uri,
CamelEwsSettings *settings);
+EEwsConnection *e_ews_connection_new_full (const gchar *uri,
+ CamelEwsSettings *settings,
+ gboolean allow_connection_reuse);
const gchar * e_ews_connection_get_uri (EEwsConnection *cnc);
const gchar * e_ews_connection_get_password (EEwsConnection *cnc);
gchar * e_ews_connection_dup_password (EEwsConnection *cnc);
@@ -1022,6 +1025,23 @@ gboolean e_ews_connection_find_folder_sync
GSList **folders,
GCancellable *cancellable,
GError **error);
+void e_ews_connection_query_auth_methods
+ (EEwsConnection *cnc,
+ gint pri,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_ews_connection_query_auth_methods_finish
+ (EEwsConnection *cnc,
+ GAsyncResult *result,
+ GSList **auth_methods,
+ GError **error);
+gboolean e_ews_connection_query_auth_methods_sync
+ (EEwsConnection *cnc,
+ gint pri,
+ GSList **auth_methods,
+ GCancellable *cancellable,
+ GError **error);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]