diff options
author | Christian Kellner <gicmo@gnome.org> | 2008-02-26 13:38:03 +0000 |
---|---|---|
committer | Christian Kellner <gicmo@src.gnome.org> | 2008-02-26 13:38:03 +0000 |
commit | 9777d1d32afc04549edfbd8212ded3ca69f328d9 (patch) | |
tree | 22890af1259925e184a4ed602939cb16c345149b /daemon/gvfsbackenddav.c | |
parent | 6a3e2cbdf48f3c60c0cb580a9340778ae1a499fc (diff) | |
download | gvfs-9777d1d32afc04549edfbd8212ded3ca69f328d9.tar.gz |
Redo authentication and implement keyring support. Based on a patch by
2008-02-26 Christian Kellner <gicmo@gnome.org>
* daemon/gvfsbackenddav.c:
Redo authentication and implement keyring support. Based
on a patch by Carlos Garcia Campos.
svn path=/trunk/; revision=1394
Diffstat (limited to 'daemon/gvfsbackenddav.c')
-rw-r--r-- | daemon/gvfsbackenddav.c | 250 |
1 files changed, 162 insertions, 88 deletions
diff --git a/daemon/gvfsbackenddav.c b/daemon/gvfsbackenddav.c index 06c547fb..1224dc54 100644 --- a/daemon/gvfsbackenddav.c +++ b/daemon/gvfsbackenddav.c @@ -43,6 +43,8 @@ #include <libxml/xpathInternals.h> #include "gvfsbackenddav.h" +#include "gvfskeyring.h" + #include "gvfsjobmount.h" #include "gvfsjobopenforread.h" #include "gvfsjobread.h" @@ -60,23 +62,28 @@ #include "soup-input-stream.h" #include "soup-output-stream.h" -typedef struct _MountAuthInfo MountAuthInfo; +typedef struct _MountAuthData MountAuthData; + +static void mount_auth_info_free (MountAuthData *info); + +typedef struct _AuthInfo { + + /* for server authentication */ + char *username; + char *password; + char *realm; -static void mount_auth_info_free (MountAuthInfo *info); + GPasswordSave pw_save; -struct _MountAuthInfo { +} AuthInfo; + +struct _MountAuthData { SoupSession *session; GMountSource *mount_source; - /* for server authentication */ - char *username; - char *password; - char *last_realm; - - /* for proxy authentication */ - char *proxy_user; - char *proxy_password; + AuthInfo server_auth; + AuthInfo proxy_auth; }; @@ -86,7 +93,7 @@ struct _GVfsBackendDav { GVfsBackendHttp parent_instance; - MountAuthInfo auth_info; + MountAuthData auth_info; }; G_DEFINE_TYPE (GVfsBackendDav, g_vfs_backend_dav, G_VFS_TYPE_BACKEND_HTTP) @@ -918,16 +925,17 @@ stat_location (GVfsBackend *backend, /* */ static void -mount_auth_info_free (MountAuthInfo *data) +mount_auth_info_free (MountAuthData *data) { if (data->mount_source) g_object_unref (data->mount_source); - g_free (data->username); - g_free (data->password); - g_free (data->last_realm); - g_free (data->proxy_user); - g_free (data->proxy_password); + g_free (data->server_auth.username); + g_free (data->server_auth.password); + g_free (data->server_auth.realm); + + g_free (data->proxy_auth.username); + g_free (data->proxy_auth.password); } @@ -938,21 +946,23 @@ soup_authenticate_from_data (SoupSession *session, gboolean retrying, gpointer user_data) { - MountAuthInfo *data; + MountAuthData *data; + AuthInfo *info; g_print ("+ soup_authenticate_from_data (%s) \n", retrying ? "retrying" : "first auth"); - data = (MountAuthInfo *) user_data; - if (retrying) return; + data = (MountAuthData *) user_data; + if (soup_auth_is_for_proxy (auth)) - soup_auth_authenticate (auth, data->proxy_user, data->proxy_password); + info = &data->proxy_auth; else - soup_auth_authenticate (auth, data->username, data->password); + info = &data->server_auth; + soup_auth_authenticate (auth, info->username, info->password); } static void @@ -962,94 +972,148 @@ soup_authenticate_interactive (SoupSession *session, gboolean retrying, gpointer user_data) { - MountAuthInfo *data; - const char *username; - const char *password; - gboolean res; - gboolean aborted; - char *new_username; - char *new_password; - char *prompt; + MountAuthData *data; + AuthInfo *info; + GAskPasswordFlags pw_ask_flags; + GPasswordSave pw_save; + const char *realm; + gboolean res; + gboolean aborted; + gboolean is_proxy; + gboolean have_auth; + char *new_username; + char *new_password; + char *prompt; g_print ("+ soup_authenticate_interactive (%s) \n", retrying ? "retrying" : "first auth"); - data = (MountAuthInfo *) user_data; + data = (MountAuthData *) user_data; new_username = NULL; new_password = NULL; + realm = NULL; + pw_ask_flags = G_ASK_PASSWORD_NEED_PASSWORD; - if (soup_auth_is_for_proxy (auth)) - { - username = data->proxy_user; - password = retrying ? NULL : data->proxy_password; - } + is_proxy = soup_auth_is_for_proxy (auth); + realm = soup_auth_get_realm (auth); + + if (is_proxy) + info = &(data->proxy_auth); else + info = &(data->server_auth); + + if (realm && info->realm == NULL) + info->realm = g_strdup (realm); + else if (realm && info->realm && !g_str_equal (realm, info->realm)) + return; + + have_auth = info->username && info->password; + + if (have_auth == FALSE && g_vfs_keyring_is_available ()) { - username = data->username; - password = retrying ? NULL : data->password; + const SoupURI *uri; + SoupURI *uri_free = NULL; + + pw_ask_flags |= G_ASK_PASSWORD_SAVING_SUPPORTED; + + if (is_proxy) + { + g_object_get (session, SOUP_SESSION_PROXY_URI, &uri_free, NULL); + uri = uri_free; + } + else + uri = soup_message_get_uri (msg); + + res = g_vfs_keyring_lookup_password (info->username, + uri->host, + NULL, + "http", + realm, + is_proxy ? "proxy" : "basic", + uri->port, + &new_username, + NULL, + &new_password); + + if (res == TRUE) + { + have_auth = TRUE; + g_free (info->username); + g_free (info->password); + info->username = new_username; + info->password = new_password; + } + + if (uri_free) + soup_uri_free (uri_free); } - if (username && password) + if (retrying == FALSE && have_auth) { - soup_auth_authenticate (auth, username, password); + soup_auth_authenticate (auth, info->username, info->password); return; } - if (soup_auth_is_for_proxy (auth)) + if (is_proxy == FALSE) { - prompt = g_strdup (_("Please enter proxy password")); + if (realm == NULL) + realm = _("WebDAV share"); + + prompt = g_strdup_printf (_("Enter password for %s"), realm); } else - { - const char *auth_realm; - - auth_realm = soup_auth_get_realm (auth); - - if (auth_realm == NULL) - auth_realm = _("WebDAV share"); + prompt = g_strdup (_("Please enter proxy password")); - prompt = g_strdup_printf (_("Enter password for %s"), auth_realm); - } + if (info->username == NULL) + pw_ask_flags |= G_ASK_PASSWORD_NEED_USERNAME; res = g_mount_source_ask_password (data->mount_source, prompt, - username, + info->username, NULL, - G_ASK_PASSWORD_NEED_PASSWORD | - G_ASK_PASSWORD_NEED_USERNAME, + pw_ask_flags, &aborted, &new_password, &new_username, NULL, - NULL); - - if (res && !aborted) { - - soup_auth_authenticate (auth, new_username, new_password); + &pw_save); - if (soup_auth_is_for_proxy (auth)) - { - g_free (data->proxy_user); - g_free (data->proxy_password); - - data->proxy_password = new_password; - data->proxy_user = new_username; - } - else - { - g_free (data->username); - g_free (data->password); + if (res && !aborted) + { + soup_auth_authenticate (auth, new_username, new_password); - data->username = new_username; - data->password = new_password; - } - } + g_free (info->username); + g_free (info->password); + info->username = new_username; + info->password = new_password; + info->pw_save = pw_save; + } + else + soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED); g_print ("- soup_authenticate \n"); g_free (prompt); } +static void +keyring_save_authinfo (AuthInfo *info, + SoupURI *uri, + gboolean is_proxy) +{ + const char *type = is_proxy ? "proxy" : "basic"; + + g_vfs_keyring_save_password (info->username, + uri->host, + NULL, + "http", + info->realm, + type, + uri->port, + info->password, + info->pw_save); +} + static inline GMountSpec * g_mount_spec_dup_known (GMountSpec *spec) { @@ -1080,7 +1144,7 @@ do_mount (GVfsBackend *backend, GMountSource *mount_source, gboolean is_automount) { - MountAuthInfo *info; + MountAuthData *data; SoupSession *session; SoupMessage *msg_opts; SoupMessage *msg_stat; @@ -1093,7 +1157,7 @@ do_mount (GVfsBackend *backend, gulong signal_id; guint status; gboolean is_success; - gboolean is_dav; + gboolean is_webdav; gboolean res; char *last_good_path; @@ -1131,13 +1195,15 @@ do_mount (GVfsBackend *backend, session = G_VFS_BACKEND_HTTP (backend)->session; G_VFS_BACKEND_HTTP (backend)->mount_base = mount_base; - info = &(G_VFS_BACKEND_DAV (backend)->auth_info); - info->mount_source = g_object_ref (mount_source); - info->username = g_strdup (user); + data = &(G_VFS_BACKEND_DAV (backend)->auth_info); + data->mount_source = g_object_ref (mount_source); + data->server_auth.username = g_strdup (user); + data->server_auth.pw_save = G_PASSWORD_SAVE_NEVER; + data->proxy_auth.pw_save = G_PASSWORD_SAVE_NEVER; signal_id = g_signal_connect (session, "authenticate", G_CALLBACK (soup_authenticate_interactive), - info); + data); last_good_path = NULL; msg_opts = message_new_from_uri (SOUP_METHOD_OPTIONS, mount_base); @@ -1147,12 +1213,12 @@ do_mount (GVfsBackend *backend, status = soup_session_send_message (session, msg_opts); is_success = SOUP_STATUS_IS_SUCCESSFUL (status); - is_dav = is_success && sm_has_header (msg_opts, "DAV"); + is_webdav = is_success && sm_has_header (msg_opts, "DAV"); soup_message_headers_clear (msg_opts->response_headers); soup_message_body_truncate (msg_opts->response_body); - if (is_dav) + if (is_webdav) { GFileType file_type; SoupURI *cur_uri; @@ -1176,7 +1242,7 @@ do_mount (GVfsBackend *backend, soup_message_body_truncate (msg_stat->response_body); } - } while (is_dav && mount_base->path != NULL); + } while (is_webdav && mount_base->path != NULL); /* we have reached the end of paths we are allowed to * chdir up to (or couldn't chdir up at all) */ @@ -1184,11 +1250,13 @@ do_mount (GVfsBackend *backend, /* check if we at all have a good path */ if (last_good_path == NULL) { + + /* TODO: set correct error in case of cancellation */ if (!is_success) g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED, _("HTTP Error: %s"), msg_opts->reason_phrase); - else if (!is_dav) + else if (!is_webdav) g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED, _("Not a WebDAV enabled share")); @@ -1200,6 +1268,12 @@ do_mount (GVfsBackend *backend, return; } + /* Success! We are mounted */ + /* Save the auth info in the keyring */ + + keyring_save_authinfo (&(data->server_auth), mount_base, FALSE); + /* TODO: save proxy auth */ + /* Set the working path in mount path */ g_free (mount_base->path); mount_base->path = last_good_path; @@ -1220,12 +1294,12 @@ do_mount (GVfsBackend *backend, g_signal_handler_disconnect (session, signal_id); g_signal_connect (session, "authenticate", G_CALLBACK (soup_authenticate_from_data), - info); + data); /* also auth the workaround async session we need for SoupInputStream */ g_signal_connect (G_VFS_BACKEND_HTTP (backend)->session_async, "authenticate", G_CALLBACK (soup_authenticate_from_data), - info); + data); g_vfs_job_succeeded (G_VFS_JOB (job)); g_print ("- mount\n"); |