Merge lp:~osomon/webbrowser-app/http-auth into lp:webbrowser-app

Proposed by Olivier Tilloy
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 1013
Merged at revision: 1178
Proposed branch: lp:~osomon/webbrowser-app/http-auth
Merge into: lp:webbrowser-app
Diff against target: 283 lines (+172/-5)
7 files modified
debian/control (+3/-3)
src/Ubuntu/Web/UbuntuWebView02.qml (+1/-1)
src/app/HttpAuthenticationDialog.qml (+76/-0)
src/app/WebViewImpl.qml (+5/-1)
tests/autopilot/webbrowser_app/emulators/browser.py (+18/-0)
tests/autopilot/webbrowser_app/tests/http_server.py (+20/-0)
tests/autopilot/webbrowser_app/tests/test_basic_authentication.py (+49/-0)
To merge this branch: bzr merge lp:~osomon/webbrowser-app/http-auth
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Riccardo Padovani (community) Approve
Ubuntu Phablet Team Pending
Review via email: mp+263561@code.launchpad.net

Commit message

Handle HTTP authentication requests by showing an authentication dialog.

This bumps the build dependency as well as runtime dependency of webbrowser-app and qtdeclarative5-ubuntu-web-plugin on liboxideqt-qmlplugin to 1.9.

Description of the change

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Riccardo Padovani (rpadovani) wrote :

I tested with http://studiare.unife.it and works very well \o/
I hope it lands with OTA-5, I need to be able to take a look to my uni website when I'm on the phone, so thank you very much :-)

The only thing that could be improved it's the support for the 'tab' key to switch between fields. Anyway, this isn't prioritary, so it's a green light for me!

(as usual, I didn't review tests, they looks good but you know I don't know python)

review: Approve
Revision history for this message
Olivier Tilloy (osomon) wrote :

Unfortunately no it won’t land in OTA-5, as it depends on oxide 1.9, to be released in ~ 6 weeks from now.

lp:~osomon/webbrowser-app/http-auth updated
1010. By Olivier Tilloy

Merge the latest changes from trunk and resolve a few minor conflicts.

1011. By Olivier Tilloy

Update imports.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~osomon/webbrowser-app/http-auth updated
1012. By Olivier Tilloy

Merge the latest changes from trunk and resolve a few conflicts.

1013. By Olivier Tilloy

Factor out common code in autopilot tests.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2015-08-25 13:56:58 +0000
3+++ debian/control 2015-09-01 07:19:36 +0000
4@@ -6,7 +6,7 @@
5 debhelper (>= 9),
6 dh-translations,
7 hardening-wrapper,
8- liboxideqt-qmlplugin (>= 1.8),
9+ liboxideqt-qmlplugin (>= 1.9),
10 libqt5sql5-sqlite,
11 python3-all,
12 python3-flake8,
13@@ -35,7 +35,7 @@
14 Depends: ${misc:Depends},
15 ${shlibs:Depends},
16 fonts-liberation,
17- liboxideqt-qmlplugin (>= 1.8),
18+ liboxideqt-qmlplugin (>= 1.9),
19 libqt5sql5-sqlite,
20 qml-module-qt-labs-folderlistmodel,
21 qml-module-qt-labs-settings,
22@@ -97,7 +97,7 @@
23 Pre-Depends: ${misc:Pre-Depends}
24 Depends: ${misc:Depends},
25 ${shlibs:Depends},
26- liboxideqt-qmlplugin (>= 1.8),
27+ liboxideqt-qmlplugin (>= 1.9),
28 qml-module-qtquick2 (>= 5.4),
29 qml-module-qtquick-window2 (>= 5.3),
30 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3),
31
32=== modified file 'src/Ubuntu/Web/UbuntuWebView02.qml'
33--- src/Ubuntu/Web/UbuntuWebView02.qml 2015-08-27 11:36:25 +0000
34+++ src/Ubuntu/Web/UbuntuWebView02.qml 2015-09-01 07:19:36 +0000
35@@ -18,7 +18,7 @@
36
37 import QtQuick 2.4
38 import QtQuick.Window 2.2
39-import com.canonical.Oxide 1.8 as Oxide
40+import com.canonical.Oxide 1.9 as Oxide
41 import Ubuntu.Components 1.3
42 import Ubuntu.Components.Popups 1.3
43 import "." // QTBUG-34418
44
45=== added file 'src/app/HttpAuthenticationDialog.qml'
46--- src/app/HttpAuthenticationDialog.qml 1970-01-01 00:00:00 +0000
47+++ src/app/HttpAuthenticationDialog.qml 2015-09-01 07:19:36 +0000
48@@ -0,0 +1,76 @@
49+/*
50+ * Copyright 2015 Canonical Ltd.
51+ *
52+ * This file is part of webbrowser-app.
53+ *
54+ * webbrowser-app is free software; you can redistribute it and/or modify
55+ * it under the terms of the GNU General Public License as published by
56+ * the Free Software Foundation; version 3.
57+ *
58+ * webbrowser-app is distributed in the hope that it will be useful,
59+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
60+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
61+ * GNU General Public License for more details.
62+ *
63+ * You should have received a copy of the GNU General Public License
64+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
65+ */
66+
67+import QtQuick 2.4
68+import Ubuntu.Components 1.3
69+import Ubuntu.Components.Popups 1.3 as Popups
70+
71+Popups.Dialog {
72+ id: dialog
73+ title: i18n.tr("Authentication required.")
74+ // TRANSLATORS: %1 refers to the URL of the current website and %2 is a string that the website sends with more information about the authentication challenge (technically called "realm")
75+ text: request ? i18n.tr('The website at %1 requires authentication. The website says "%2"').arg(request.host).arg(request.realm) : ""
76+
77+ property QtObject request: null
78+
79+ Connections {
80+ target: request
81+ onCancelled: PopupUtils.close(dialog)
82+ }
83+
84+ TextField {
85+ id: usernameInput
86+ objectName: "username"
87+ placeholderText: i18n.tr("Username")
88+ onAccepted: {
89+ request.allow(usernameInput.text, passwordInput.text)
90+ PopupUtils.close(dialog)
91+ }
92+ }
93+
94+ TextField {
95+ id: passwordInput
96+ objectName: "password"
97+ placeholderText: i18n.tr("Password")
98+ echoMode: TextInput.Password
99+ onAccepted: {
100+ request.allow(usernameInput.text, passwordInput.text)
101+ PopupUtils.close(dialog)
102+ }
103+ }
104+
105+ Button {
106+ objectName: "allow"
107+ text: i18n.tr("OK")
108+ color: UbuntuColors.green
109+ onClicked: {
110+ request.allow(usernameInput.text, passwordInput.text)
111+ PopupUtils.close(dialog)
112+ }
113+ }
114+
115+ Button {
116+ objectName: "deny"
117+ text: i18n.tr("Cancel")
118+ color: UbuntuColors.coolGrey
119+ onClicked: {
120+ request.deny()
121+ PopupUtils.close(dialog)
122+ }
123+ }
124+}
125
126=== modified file 'src/app/WebViewImpl.qml'
127--- src/app/WebViewImpl.qml 2015-08-27 14:00:49 +0000
128+++ src/app/WebViewImpl.qml 2015-09-01 07:19:36 +0000
129@@ -29,7 +29,6 @@
130 property var currentWebview: webview
131
132 /*experimental.certificateVerificationDialog: CertificateVerificationDialog {}
133- experimental.authenticationDialog: AuthenticationDialog {}
134 experimental.proxyAuthenticationDialog: ProxyAuthenticationDialog {}*/
135 alertDialog: AlertDialog {}
136 confirmDialog: ConfirmDialog {}
137@@ -82,6 +81,11 @@
138 }
139 }
140
141+ onHttpAuthenticationRequested: {
142+ PopupUtils.open(Qt.resolvedUrl("HttpAuthenticationDialog.qml"),
143+ webview.currentWebview, {"request": request})
144+ }
145+
146 Loader {
147 id: filePickerLoader
148 source: formFactor == "desktop" ? "FilePickerDialog.qml" : "ContentPickerDialog.qml"
149
150=== modified file 'tests/autopilot/webbrowser_app/emulators/browser.py'
151--- tests/autopilot/webbrowser_app/emulators/browser.py 2015-08-25 13:56:58 +0000
152+++ tests/autopilot/webbrowser_app/emulators/browser.py 2015-09-01 07:19:36 +0000
153@@ -115,6 +115,9 @@
154 def get_geolocation_dialog(self):
155 return self.wait_select_single(GeolocationPermissionRequest)
156
157+ def get_http_auth_dialog(self):
158+ return self.wait_select_single(HttpAuthenticationDialog)
159+
160 def get_tabs_view(self):
161 return self.wait_select_single(TabsList, visible=True)
162
163@@ -323,6 +326,21 @@
164 return self.select_single("Button", objectName="allow")
165
166
167+class HttpAuthenticationDialog(uitk.UbuntuUIToolkitCustomProxyObjectBase):
168+
169+ def get_deny_button(self):
170+ return self.select_single("Button", objectName="deny")
171+
172+ def get_allow_button(self):
173+ return self.select_single("Button", objectName="allow")
174+
175+ def get_username_field(self):
176+ return self.select_single("TextField", objectName="username")
177+
178+ def get_password_field(self):
179+ return self.select_single("TextField", objectName="password")
180+
181+
182 class TabPreview(uitk.UbuntuUIToolkitCustomProxyObjectBase):
183
184 @autopilot.logging.log_action(logger.info)
185
186=== modified file 'tests/autopilot/webbrowser_app/tests/http_server.py'
187--- tests/autopilot/webbrowser_app/tests/http_server.py 2015-08-24 09:27:53 +0000
188+++ tests/autopilot/webbrowser_app/tests/http_server.py 2015-09-01 07:19:36 +0000
189@@ -6,6 +6,7 @@
190 # under the terms of the GNU General Public License version 3, as published
191 # by the Free Software Foundation.
192
193+from base64 import b64decode
194 import http.server as http
195 import json
196 import logging
197@@ -37,6 +38,12 @@
198 self.end_headers()
199 self.wfile.write(html.encode())
200
201+ def send_auth_request(self):
202+ self.send_response(401)
203+ self.send_header("WWW-Authenticate", "Basic realm=\"Enter Password\"")
204+ self.end_headers()
205+ self.send_html("Not Authorized")
206+
207 def do_GET(self):
208 if self.path == "/ping":
209 self.send_response(200)
210@@ -183,6 +190,19 @@
211 self.send_response(200)
212 name = self.path[len("/tab/"):]
213 self.send_html('<html><body>' + name + '</body></html>')
214+ elif self.path.startswith("/basicauth"):
215+ login = "user"
216+ password = "pass"
217+ if "Authorization" in self.headers:
218+ header = self.headers.get("Authorization")
219+ credentials = str(b64decode(header[len("Basic "):])).split(":")
220+ if credentials[0] == login and credentials[1] == password:
221+ self.send_response(200)
222+ self.send_html("Authentication Successful !")
223+ else:
224+ self.send_auth_request()
225+ else:
226+ self.send_auth_request()
227 else:
228 self.send_error(404)
229
230
231=== added file 'tests/autopilot/webbrowser_app/tests/test_basic_authentication.py'
232--- tests/autopilot/webbrowser_app/tests/test_basic_authentication.py 1970-01-01 00:00:00 +0000
233+++ tests/autopilot/webbrowser_app/tests/test_basic_authentication.py 2015-09-01 07:19:36 +0000
234@@ -0,0 +1,49 @@
235+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
236+#
237+# Copyright 2015 Canonical
238+#
239+# This program is free software: you can redistribute it and/or modify it
240+# under the terms of the GNU General Public License version 3, as published
241+# by the Free Software Foundation.
242+#
243+# This program is distributed in the hope that it will be useful,
244+# but WITHOUT ANY WARRANTY; without even the implied warranty of
245+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
246+# GNU General Public License for more details.
247+#
248+# You should have received a copy of the GNU General Public License
249+# along with this program. If not, see <http://www.gnu.org/licenses/>.
250+
251+from webbrowser_app.tests import StartOpenRemotePageTestCaseBase
252+
253+
254+class TestBasicAuthentication(StartOpenRemotePageTestCaseBase):
255+
256+ def setUp(self):
257+ super(TestBasicAuthentication, self).setUp()
258+ self.main_window.go_to_url(self.base_url + "/basicauth")
259+ self.dialog = self.main_window.get_http_auth_dialog()
260+ self.username = "user"
261+ self.password = "pass"
262+
263+ def test_cancel(self):
264+ self.pointing_device.click_object(self.dialog.get_deny_button())
265+ self.dialog.wait_until_destroyed()
266+
267+ def test_right_credentials(self):
268+ username = self.dialog.get_username_field()
269+ username.write(self.username)
270+ password = self.dialog.get_password_field()
271+ password.write(self.password)
272+ self.pointing_device.click_object(self.dialog.get_allow_button())
273+ self.dialog.wait_until_destroyed()
274+
275+ def test_wrong_credentials(self):
276+ username = self.dialog.get_username_field()
277+ username.write("x")
278+ password = self.dialog.get_password_field()
279+ password.write("x")
280+ self.pointing_device.click_object(self.dialog.get_allow_button())
281+ self.dialog.wait_until_destroyed()
282+ # verify that a new dialog has been displayed
283+ self.main_window.get_http_auth_dialog()

Subscribers

People subscribed via source and target branches

to status/vote changes: