From 1a14025340ba0a33ad93dffad43ad7acef02de30 Mon Sep 17 00:00:00 2001 From: Xan Lopez Date: Mon, 16 Feb 2009 16:52:10 +0200 Subject: [PATCH] 2009-02-16 Xan Lopez Reviewed by NOBODY (OOPS!). https://bugs.webkit.org/show_bug.cgi?id=16947 [GTK] Missing HTTP Auth challenge Add HTTP authentication dialog with optional GNOME Keyring storage. * GNUmakefile.am: * platform/network/soup/ResourceHandleSoup.cpp: (WebCore::ResourceHandle::startHttp): * platform/network/soup/webkit-soup-auth-dialog.c: Added. (webkit_soup_auth_dialog_class_init): (webkit_soup_auth_dialog_init): (webkit_soup_auth_dialog_session_feature_init): (free_authData): (set_password_callback): (response_callback): (show_auth_dialog): (find_password_callback): (session_authenticate): (attach): * platform/network/soup/webkit-soup-auth-dialog.h: Added. --- ChangeLog | 12 + GNUmakefile.am | 4 +- WebCore/ChangeLog | 26 ++ WebCore/GNUmakefile.am | 9 +- .../platform/network/soup/ResourceHandleSoup.cpp | 5 + .../network/soup/webkit-soup-auth-dialog.c | 272 ++++++++++++++++++++ .../network/soup/webkit-soup-auth-dialog.h | 46 ++++ configure.ac | 19 ++ 8 files changed, 391 insertions(+), 2 deletions(-) create mode 100644 WebCore/platform/network/soup/webkit-soup-auth-dialog.c create mode 100644 WebCore/platform/network/soup/webkit-soup-auth-dialog.h diff --git a/ChangeLog b/ChangeLog index b1e5db8..9a9a64c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2009-02-16 Xan Lopez + + Reviewed by NOBODY (OOPS!). + + https://bugs.webkit.org/show_bug.cgi?id=16947 + [GTK] Missing HTTP Auth challenge + + Add gnome-keyring bits to the build system. + + * GNUmakefile.am: + * configure.ac: + 2009-02-12 Gustavo Noronha Silva Reviewed by Eric Seidel. diff --git a/GNUmakefile.am b/GNUmakefile.am index c74e1fa..dd9b72f 100644 --- a/GNUmakefile.am +++ b/GNUmakefile.am @@ -182,7 +182,8 @@ libWebCore_la_CFLAGS = \ $(LIBXSLT_CFLAGS) \ $(COVERAGE_CFLAGS) \ $(HILDON_CFLAGS) \ - $(GEOCLUE_CFLAGS) + $(GEOCLUE_CFLAGS) \ + $(GNOMEKEYRING_CFLAGS) libWebCore_la_CPPFLAGS = \ $(global_cppflags) \ @@ -212,6 +213,7 @@ libWebCore_la_LIBADD = \ $(JPEG_LIBS) \ $(PNG_LIBS) \ $(GEOCLUE_LIBS) \ + $(GNOMEKEYRING_LIBS) \ -lpthread # WebKit diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog index 648e9b3..9023b65 100644 --- a/WebCore/ChangeLog +++ b/WebCore/ChangeLog @@ -1,3 +1,29 @@ +2009-02-16 Xan Lopez + + Reviewed by NOBODY (OOPS!). + + https://bugs.webkit.org/show_bug.cgi?id=16947 + [GTK] Missing HTTP Auth challenge + + Add HTTP authentication dialog with optional GNOME Keyring + storage. + + * GNUmakefile.am: + * platform/network/soup/ResourceHandleSoup.cpp: + (WebCore::ResourceHandle::startHttp): + * platform/network/soup/webkit-soup-auth-dialog.c: Added. + (webkit_soup_auth_dialog_class_init): + (webkit_soup_auth_dialog_init): + (webkit_soup_auth_dialog_session_feature_init): + (free_authData): + (set_password_callback): + (response_callback): + (show_auth_dialog): + (find_password_callback): + (session_authenticate): + (attach): + * platform/network/soup/webkit-soup-auth-dialog.h: Added. + 2009-02-15 David Kilzer Move duplicate caretWidth constants to RenderObject.h diff --git a/WebCore/GNUmakefile.am b/WebCore/GNUmakefile.am index e81c158..3d6967c 100644 --- a/WebCore/GNUmakefile.am +++ b/WebCore/GNUmakefile.am @@ -1830,7 +1830,14 @@ webcore_sources += \ WebCore/platform/network/soup/ResourceError.h \ WebCore/platform/network/soup/ResourceHandleSoup.cpp \ WebCore/platform/network/soup/ResourceRequest.h \ - WebCore/platform/network/soup/ResourceResponse.h + WebCore/platform/network/soup/ResourceResponse.h \ + WebCore/platform/network/soup/webkit-soup-auth-dialog.c \ + WebCore/platform/network/soup/webkit-soup-auth-dialog.h +endif + +if USE_GNOMEKEYRING +webcore_cppflags += \ + -DWTF_USE_GNOMEKEYRING=1 endif # --- diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp index 9ab7b8a..517744d 100644 --- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp +++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp @@ -37,6 +37,7 @@ #include "ResourceHandleInternal.h" #include "ResourceResponse.h" #include "TextEncoding.h" +#include "webkit-soup-auth-dialog.h" #include #include @@ -310,6 +311,10 @@ bool ResourceHandle::startHttp(String urlString) soup_session_add_feature(session, SOUP_SESSION_FEATURE(getCookieJar())); + SoupSessionFeature* authDialog = static_cast(g_object_new(WEBKIT_TYPE_SOUP_AUTH_DIALOG, NULL)); + soup_session_add_feature(session, authDialog); + g_object_unref(authDialog); + const char* soup_debug = g_getenv("WEBKIT_SOUP_LOGGING"); if (soup_debug) { int soup_debug_level = atoi(soup_debug); diff --git a/WebCore/platform/network/soup/webkit-soup-auth-dialog.c b/WebCore/platform/network/soup/webkit-soup-auth-dialog.c new file mode 100644 index 0000000..e500b64 --- /dev/null +++ b/WebCore/platform/network/soup/webkit-soup-auth-dialog.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2009 Igalia S.L., Author: Xan Lopez + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include +#include +#if USE(GNOMEKEYRING) +#include +#endif + +#include "webkit-soup-auth-dialog.h" + +static void webkit_soup_auth_dialog_session_feature_init(SoupSessionFeatureInterface* feature_interface, gpointer interface_data); +static void attach(SoupSessionFeature *manager, SoupSession *session); +static void detach(SoupSessionFeature *manager, SoupSession *session); + +G_DEFINE_TYPE_WITH_CODE(WebKitSoupAuthDialog, webkit_soup_auth_dialog, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(SOUP_TYPE_SESSION_FEATURE, + webkit_soup_auth_dialog_session_feature_init)) + +static void webkit_soup_auth_dialog_class_init(WebKitSoupAuthDialogClass *klass) +{ +} + +static void webkit_soup_auth_dialog_init(WebKitSoupAuthDialog* instance) +{ +} + +static void webkit_soup_auth_dialog_session_feature_init(SoupSessionFeatureInterface *feature_interface, + gpointer interface_data) +{ + feature_interface->attach = attach; + feature_interface->detach = detach; +} + +typedef struct _WebKitAuthData { + SoupMessage* msg; + SoupAuth* auth; + SoupSession* session; + GtkWidget* loginEntry; + GtkWidget* passwordEntry; +#if USE(GNOMEKEYRING) + GtkWidget* checkButton; +#endif +} WebKitAuthData; + +static void free_authData(WebKitAuthData* authData) +{ + g_object_unref(authData->msg); + g_slice_free(WebKitAuthData, authData); +} + +#if USE(GNOMEKEYRING) +static void set_password_callback(GnomeKeyringResult result, guint32 val, gpointer user_data) +{ + /* Dummy callback, gnome_keyring_set_network_password does not accept a NULL one */ +} +#endif + +static void response_callback(GtkDialog* dialog, gint response_id, WebKitAuthData* authData) +{ + const char* login; + const char* password; +#if USE(GNOMEKEYRING) + SoupURI* uri; + gboolean storePassword; +#endif + + switch(response_id) { + case GTK_RESPONSE_ACCEPT: + login = gtk_entry_get_text(GTK_ENTRY(authData->loginEntry)); + password = gtk_entry_get_text(GTK_ENTRY(authData->passwordEntry)); + soup_auth_authenticate(authData->auth, login, password); + +#if USE(GNOMEKEYRING) + storePassword = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(authData->checkButton)); + if (storePassword) { + uri = soup_message_get_uri(authData->msg); + gnome_keyring_set_network_password(NULL, + login, + soup_auth_get_realm(authData->auth), + uri->host, + NULL, + uri->scheme, + soup_auth_get_scheme_name(authData->auth), + uri->port, + password, + (GnomeKeyringOperationGetIntCallback)set_password_callback, + NULL, + NULL); + } +#endif + default: + break; + } + + soup_session_unpause_message(authData->session, authData->msg); + free_authData(authData); + gtk_widget_destroy(GTK_WIDGET(dialog)); +} + +static void show_auth_dialog(WebKitAuthData* authData, const char* login, const char* password) +{ + /* Mimic the UI from Gecko, EmbedPrompter.cpp, LGPL license */ + GtkWidget* dialog; + dialog = gtk_dialog_new_with_buttons("", + NULL, // FIXME: how to get the current toplevel from here? + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, + GTK_RESPONSE_REJECT, + GTK_STOCK_OK, + GTK_RESPONSE_ACCEPT, + NULL); + gtk_window_set_default_size(GTK_WINDOW(dialog), 100, 50); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); + + /* Main hbox for icon and controls */ + GtkWidget* mainHBox = gtk_hbox_new(FALSE, 12); + gtk_container_set_border_width(GTK_CONTAINER(dialog), 6); + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); + + GtkWidget* contentArea = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + gtk_box_set_spacing(GTK_BOX(contentArea), 12); + gtk_container_set_border_width(GTK_CONTAINER(mainHBox), 12); + /* VBox for labels and other controls */ + GtkWidget* contentsVBox = gtk_vbox_new(FALSE, 12); + GtkWidget* icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_AUTHENTICATION, + GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment(GTK_MISC(icon), 0.5, 0.0); + gtk_box_pack_start(GTK_BOX(mainHBox), icon, FALSE, FALSE, 0); + + /* Pack the message label into the VBox */ + SoupURI* uri = soup_message_get_uri(authData->msg); + char* message = g_strdup_printf("A username and password are being requested by %s", + uri->host); + GtkWidget* label = gtk_label_new(message); + g_free(message); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_label_set_selectable(GTK_LABEL(label), TRUE); + gtk_box_pack_start(GTK_BOX(contentsVBox), label, FALSE, FALSE, 0); + + /* Login/Password entries */ + GtkWidget* userPassHBox = gtk_hbox_new(FALSE, 12); + GtkWidget* userPassLabels = gtk_vbox_new(TRUE, 6); + GtkWidget* userPassFields = gtk_vbox_new(TRUE, 6); + + GtkWidget* userLabel = gtk_label_new("User Name:"); + gtk_box_pack_start(GTK_BOX(userPassLabels), userLabel, FALSE, 0, 0); + GtkWidget* loginEntry = gtk_entry_new(); + if (login) + gtk_entry_set_text(GTK_ENTRY(loginEntry), login); + gtk_entry_set_activates_default(GTK_ENTRY(loginEntry), TRUE); + gtk_box_pack_start(GTK_BOX(userPassFields), loginEntry, FALSE, 0, 0); + + GtkWidget* passwordLabel = gtk_label_new("Password:"); + gtk_box_pack_start(GTK_BOX(userPassLabels), passwordLabel, FALSE, 0, 0); + GtkWidget* passwordEntry = gtk_entry_new(); + if (password) + gtk_entry_set_text(GTK_ENTRY(passwordEntry), password); + gtk_entry_set_visibility(GTK_ENTRY(passwordEntry), FALSE); + gtk_entry_set_activates_default(GTK_ENTRY(passwordEntry), TRUE); + gtk_box_pack_start(GTK_BOX(userPassFields), passwordEntry, FALSE, 0, 0); + + gtk_box_pack_start(GTK_BOX(userPassHBox), userPassLabels, FALSE, 0, 0); + gtk_box_pack_start(GTK_BOX(userPassHBox), userPassFields, FALSE, 0, 0); + gtk_box_pack_start(GTK_BOX(contentsVBox), userPassHBox, FALSE, 0, 0); + +#if USE(GNOMEKEYRING) + /* Checkbutton */ + GtkWidget* checkButton = gtk_check_button_new_with_label("Remember password"); + if (login && password) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkButton), TRUE); + gtk_label_set_line_wrap(GTK_LABEL(gtk_bin_get_child(GTK_BIN(checkButton))), TRUE); + gtk_box_pack_start(GTK_BOX(contentsVBox), checkButton, FALSE, 0, 0); +#endif + + /* Pack and go */ + gtk_box_pack_start(GTK_BOX(mainHBox), contentsVBox, FALSE, 0, 0); + gtk_box_pack_start(GTK_BOX(contentArea), mainHBox, FALSE, 0, 0); + + authData->loginEntry = loginEntry; + authData->passwordEntry = passwordEntry; +#if USE(GNOMEKEYRING) + authData->checkButton = checkButton; +#endif + + g_signal_connect(dialog, "response", G_CALLBACK(response_callback), authData); + gtk_widget_show_all(dialog); +} + +#if USE(GNOMEKEYRING) +static void find_password_callback(GnomeKeyringResult result, GList* list, WebKitAuthData* authData) +{ + GList* p; + const char* login = NULL; + const char* password = NULL; + + for (p = list; p; p = p->next) { + /* FIXME: support multiple logins/passwords ? */ + GnomeKeyringNetworkPasswordData* data = (GnomeKeyringNetworkPasswordData*)p->data; + login = data->user; + password = data->password; + break; + } + + show_auth_dialog(authData, login, password); +} +#endif + +static void session_authenticate(SoupSession* session, SoupMessage* msg, SoupAuth* auth, gboolean retrying) +{ + SoupURI* uri; + WebKitAuthData* authData; + + soup_session_pause_message(session, msg); + /* We need to make sure the message sticks around when pausing it */ + g_object_ref(msg); + + uri = soup_message_get_uri(msg); + authData = g_slice_new(WebKitAuthData); + authData->msg = msg; + authData->auth = auth; + authData->session = session; + + /* + * If we have gnome-keyring let's try to find the password first in the ring. + * Otherwise just show the dialog straight away + */ +#if USE(GNOMEKEYRING) + gnome_keyring_find_network_password(NULL, + soup_auth_get_realm(auth), + uri->host, + NULL, + uri->scheme, + soup_auth_get_scheme_name(auth), + uri->port, + (GnomeKeyringOperationGetListCallback)find_password_callback, + authData, + NULL); +#else + show_auth_dialog(authData, NULL, NULL); +#endif +} + +static void attach(SoupSessionFeature *manager, SoupSession *session) +{ + g_signal_connect(session, "authenticate", G_CALLBACK(session_authenticate), NULL); +} + +static void detach(SoupSessionFeature *manager, SoupSession *session) +{ + g_signal_handlers_disconnect_by_func(session, session_authenticate, NULL); +} + + diff --git a/WebCore/platform/network/soup/webkit-soup-auth-dialog.h b/WebCore/platform/network/soup/webkit-soup-auth-dialog.h new file mode 100644 index 0000000..32630e4 --- /dev/null +++ b/WebCore/platform/network/soup/webkit-soup-auth-dialog.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009 Igalia S.L., Author: Xan Lopez + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#ifndef WEBKIT_SOUP_AUTH_DIALOG_H +#define WEBKIT_SOUP_AUTH_DIALOG_H 1 + +G_BEGIN_DECLS + +#define WEBKIT_TYPE_SOUP_AUTH_DIALOG (webkit_soup_auth_dialog_get_type ()) +#define WEBKIT_SOUP_AUTH_DIALOG(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), WEBKIT_TYPE_SOUP_AUTH_DIALOG, WebKitSoupAuthDialog)) +#define WEBKIT_SOUP_AUTH_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_SOUP_AUTH_DIALOG, WebKitSoupAuthDialog)) +#define WEBKIT_IS_SOUP_AUTH_DIALOG(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), WEBKIT_TYPE_SOUP_AUTH_DIALOG)) +#define WEBKIT_IS_SOUP_AUTH_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), WEBKIT_TYPE_SOUP_AUTH_DIALOG)) +#define WEBKIT_SOUP_AUTH_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), WEBKIT_TYPE_SOUP_AUTH_DIALOG, WebKitSoupAuthDialog)) + +typedef struct { + GObject parent_instance; +} WebKitSoupAuthDialog; + +typedef struct { + GObjectClass parent_class; +} WebKitSoupAuthDialogClass; + +GType webkit_soup_auth_dialog_get_type (void); + +G_END_DECLS + +#endif /* WEBKIT_SOUP_AUTH_DIALOG_H */ diff --git a/configure.ac b/configure.ac index 4e5f983..60c0c2a 100644 --- a/configure.ac +++ b/configure.ac @@ -350,6 +350,14 @@ AC_ARG_ENABLE(geolocation, [],[enable_geolocation="no"]) AC_MSG_RESULT([$enable_geolocation]) +# check whether to enable gnomekeyring support +AC_MSG_CHECKING([whether to enable gnomekeyring support]) +AC_ARG_ENABLE(gnomekeyring, + AC_HELP_STRING([--enable-gnomekeyring], + [enable support for gnomekeyring [default=no]]), + [],[enable_gnomekeyring="no"]) +AC_MSG_RESULT([$enable_gnomekeyring]) + # check whether to enable SVG support AC_MSG_CHECKING([whether to enable SVG support]) AC_ARG_ENABLE(svg, @@ -532,6 +540,13 @@ if test "$with_http_backend" = "soup"; then AC_SUBST([LIBSOUP_LIBS]) fi +if test "$enable_gnomekeyring" = "yes"; then + PKG_CHECK_MODULES([GNOMEKEYRING], + [gnome-keyring-1]) + AC_SUBST([GNOMEKEYRING_CFLAGS]) + AC_SUBST([GNOMEKEYRING_LIBS]) +fi + # check if FreeType/FontConfig are available if test "$with_font_backend" = "freetype"; then if test "$with_target" = "directfb"; then @@ -614,6 +629,9 @@ AM_CONDITIONAL([TARGET_DIRECTFB], [test "$with_target" = "directfb"]) AM_CONDITIONAL([USE_CURL], [test "$with_http_backend" = "curl"]) AM_CONDITIONAL([USE_SOUP], [test "$with_http_backend" = "soup"]) +# Auth backend conditionals +AM_CONDITIONAL([USE_GNOMEKEYRING], [test "$enable_gnomekeyring" = "yes"]) + # Font backend conditionals AM_CONDITIONAL([USE_FREETYPE], [test "$with_font_backend" = "freetype"]) AM_CONDITIONAL([USE_PANGO], [test "$with_font_backend" = "pango"]) @@ -683,6 +701,7 @@ Features: WML support : $enable_wml Web Workers support : $enable_web_workers Geolocation support : $enable_geolocation + GNOME Keyring support : $enable_gnomekeyring GTK+ configuration: GDK target : $with_target Hildon UI extensions : $with_hildon -- 1.6.1