Merge lp:~osomon/webbrowser-app/http-auth into lp:webbrowser-app
- http-auth
- Merge into trunk
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 |
Related bugs: |
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-
Description of the change
Note: this supersedes https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
Riccardo Padovani (rpadovani) wrote : | # |
I tested with http://
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)
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.
- 1010. By Olivier Tilloy
-
Merge the latest changes from trunk and resolve a few minor conflicts.
- 1011. By Olivier Tilloy
-
Update imports.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1011
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 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.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1013
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1013
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1013
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
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 | 6 | debhelper (>= 9), | 6 | debhelper (>= 9), |
6 | 7 | dh-translations, | 7 | dh-translations, |
7 | 8 | hardening-wrapper, | 8 | hardening-wrapper, |
9 | 9 | liboxideqt-qmlplugin (>= 1.8), | 9 | liboxideqt-qmlplugin (>= 1.9), |
10 | 10 | libqt5sql5-sqlite, | 10 | libqt5sql5-sqlite, |
11 | 11 | python3-all, | 11 | python3-all, |
12 | 12 | python3-flake8, | 12 | python3-flake8, |
13 | @@ -35,7 +35,7 @@ | |||
14 | 35 | Depends: ${misc:Depends}, | 35 | Depends: ${misc:Depends}, |
15 | 36 | ${shlibs:Depends}, | 36 | ${shlibs:Depends}, |
16 | 37 | fonts-liberation, | 37 | fonts-liberation, |
18 | 38 | liboxideqt-qmlplugin (>= 1.8), | 38 | liboxideqt-qmlplugin (>= 1.9), |
19 | 39 | libqt5sql5-sqlite, | 39 | libqt5sql5-sqlite, |
20 | 40 | qml-module-qt-labs-folderlistmodel, | 40 | qml-module-qt-labs-folderlistmodel, |
21 | 41 | qml-module-qt-labs-settings, | 41 | qml-module-qt-labs-settings, |
22 | @@ -97,7 +97,7 @@ | |||
23 | 97 | Pre-Depends: ${misc:Pre-Depends} | 97 | Pre-Depends: ${misc:Pre-Depends} |
24 | 98 | Depends: ${misc:Depends}, | 98 | Depends: ${misc:Depends}, |
25 | 99 | ${shlibs:Depends}, | 99 | ${shlibs:Depends}, |
27 | 100 | liboxideqt-qmlplugin (>= 1.8), | 100 | liboxideqt-qmlplugin (>= 1.9), |
28 | 101 | qml-module-qtquick2 (>= 5.4), | 101 | qml-module-qtquick2 (>= 5.4), |
29 | 102 | qml-module-qtquick-window2 (>= 5.3), | 102 | qml-module-qtquick-window2 (>= 5.3), |
30 | 103 | qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3), | 103 | qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3), |
31 | 104 | 104 | ||
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 | 18 | 18 | ||
37 | 19 | import QtQuick 2.4 | 19 | import QtQuick 2.4 |
38 | 20 | import QtQuick.Window 2.2 | 20 | import QtQuick.Window 2.2 |
40 | 21 | import com.canonical.Oxide 1.8 as Oxide | 21 | import com.canonical.Oxide 1.9 as Oxide |
41 | 22 | import Ubuntu.Components 1.3 | 22 | import Ubuntu.Components 1.3 |
42 | 23 | import Ubuntu.Components.Popups 1.3 | 23 | import Ubuntu.Components.Popups 1.3 |
43 | 24 | import "." // QTBUG-34418 | 24 | import "." // QTBUG-34418 |
44 | 25 | 25 | ||
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 | 1 | /* | ||
50 | 2 | * Copyright 2015 Canonical Ltd. | ||
51 | 3 | * | ||
52 | 4 | * This file is part of webbrowser-app. | ||
53 | 5 | * | ||
54 | 6 | * webbrowser-app is free software; you can redistribute it and/or modify | ||
55 | 7 | * it under the terms of the GNU General Public License as published by | ||
56 | 8 | * the Free Software Foundation; version 3. | ||
57 | 9 | * | ||
58 | 10 | * webbrowser-app is distributed in the hope that it will be useful, | ||
59 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
60 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
61 | 13 | * GNU General Public License for more details. | ||
62 | 14 | * | ||
63 | 15 | * You should have received a copy of the GNU General Public License | ||
64 | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
65 | 17 | */ | ||
66 | 18 | |||
67 | 19 | import QtQuick 2.4 | ||
68 | 20 | import Ubuntu.Components 1.3 | ||
69 | 21 | import Ubuntu.Components.Popups 1.3 as Popups | ||
70 | 22 | |||
71 | 23 | Popups.Dialog { | ||
72 | 24 | id: dialog | ||
73 | 25 | title: i18n.tr("Authentication required.") | ||
74 | 26 | // 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 | 27 | text: request ? i18n.tr('The website at %1 requires authentication. The website says "%2"').arg(request.host).arg(request.realm) : "" | ||
76 | 28 | |||
77 | 29 | property QtObject request: null | ||
78 | 30 | |||
79 | 31 | Connections { | ||
80 | 32 | target: request | ||
81 | 33 | onCancelled: PopupUtils.close(dialog) | ||
82 | 34 | } | ||
83 | 35 | |||
84 | 36 | TextField { | ||
85 | 37 | id: usernameInput | ||
86 | 38 | objectName: "username" | ||
87 | 39 | placeholderText: i18n.tr("Username") | ||
88 | 40 | onAccepted: { | ||
89 | 41 | request.allow(usernameInput.text, passwordInput.text) | ||
90 | 42 | PopupUtils.close(dialog) | ||
91 | 43 | } | ||
92 | 44 | } | ||
93 | 45 | |||
94 | 46 | TextField { | ||
95 | 47 | id: passwordInput | ||
96 | 48 | objectName: "password" | ||
97 | 49 | placeholderText: i18n.tr("Password") | ||
98 | 50 | echoMode: TextInput.Password | ||
99 | 51 | onAccepted: { | ||
100 | 52 | request.allow(usernameInput.text, passwordInput.text) | ||
101 | 53 | PopupUtils.close(dialog) | ||
102 | 54 | } | ||
103 | 55 | } | ||
104 | 56 | |||
105 | 57 | Button { | ||
106 | 58 | objectName: "allow" | ||
107 | 59 | text: i18n.tr("OK") | ||
108 | 60 | color: UbuntuColors.green | ||
109 | 61 | onClicked: { | ||
110 | 62 | request.allow(usernameInput.text, passwordInput.text) | ||
111 | 63 | PopupUtils.close(dialog) | ||
112 | 64 | } | ||
113 | 65 | } | ||
114 | 66 | |||
115 | 67 | Button { | ||
116 | 68 | objectName: "deny" | ||
117 | 69 | text: i18n.tr("Cancel") | ||
118 | 70 | color: UbuntuColors.coolGrey | ||
119 | 71 | onClicked: { | ||
120 | 72 | request.deny() | ||
121 | 73 | PopupUtils.close(dialog) | ||
122 | 74 | } | ||
123 | 75 | } | ||
124 | 76 | } | ||
125 | 0 | 77 | ||
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 | 29 | property var currentWebview: webview | 29 | property var currentWebview: webview |
131 | 30 | 30 | ||
132 | 31 | /*experimental.certificateVerificationDialog: CertificateVerificationDialog {} | 31 | /*experimental.certificateVerificationDialog: CertificateVerificationDialog {} |
133 | 32 | experimental.authenticationDialog: AuthenticationDialog {} | ||
134 | 33 | experimental.proxyAuthenticationDialog: ProxyAuthenticationDialog {}*/ | 32 | experimental.proxyAuthenticationDialog: ProxyAuthenticationDialog {}*/ |
135 | 34 | alertDialog: AlertDialog {} | 33 | alertDialog: AlertDialog {} |
136 | 35 | confirmDialog: ConfirmDialog {} | 34 | confirmDialog: ConfirmDialog {} |
137 | @@ -82,6 +81,11 @@ | |||
138 | 82 | } | 81 | } |
139 | 83 | } | 82 | } |
140 | 84 | 83 | ||
141 | 84 | onHttpAuthenticationRequested: { | ||
142 | 85 | PopupUtils.open(Qt.resolvedUrl("HttpAuthenticationDialog.qml"), | ||
143 | 86 | webview.currentWebview, {"request": request}) | ||
144 | 87 | } | ||
145 | 88 | |||
146 | 85 | Loader { | 89 | Loader { |
147 | 86 | id: filePickerLoader | 90 | id: filePickerLoader |
148 | 87 | source: formFactor == "desktop" ? "FilePickerDialog.qml" : "ContentPickerDialog.qml" | 91 | source: formFactor == "desktop" ? "FilePickerDialog.qml" : "ContentPickerDialog.qml" |
149 | 88 | 92 | ||
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 | 115 | def get_geolocation_dialog(self): | 115 | def get_geolocation_dialog(self): |
155 | 116 | return self.wait_select_single(GeolocationPermissionRequest) | 116 | return self.wait_select_single(GeolocationPermissionRequest) |
156 | 117 | 117 | ||
157 | 118 | def get_http_auth_dialog(self): | ||
158 | 119 | return self.wait_select_single(HttpAuthenticationDialog) | ||
159 | 120 | |||
160 | 118 | def get_tabs_view(self): | 121 | def get_tabs_view(self): |
161 | 119 | return self.wait_select_single(TabsList, visible=True) | 122 | return self.wait_select_single(TabsList, visible=True) |
162 | 120 | 123 | ||
163 | @@ -323,6 +326,21 @@ | |||
164 | 323 | return self.select_single("Button", objectName="allow") | 326 | return self.select_single("Button", objectName="allow") |
165 | 324 | 327 | ||
166 | 325 | 328 | ||
167 | 329 | class HttpAuthenticationDialog(uitk.UbuntuUIToolkitCustomProxyObjectBase): | ||
168 | 330 | |||
169 | 331 | def get_deny_button(self): | ||
170 | 332 | return self.select_single("Button", objectName="deny") | ||
171 | 333 | |||
172 | 334 | def get_allow_button(self): | ||
173 | 335 | return self.select_single("Button", objectName="allow") | ||
174 | 336 | |||
175 | 337 | def get_username_field(self): | ||
176 | 338 | return self.select_single("TextField", objectName="username") | ||
177 | 339 | |||
178 | 340 | def get_password_field(self): | ||
179 | 341 | return self.select_single("TextField", objectName="password") | ||
180 | 342 | |||
181 | 343 | |||
182 | 326 | class TabPreview(uitk.UbuntuUIToolkitCustomProxyObjectBase): | 344 | class TabPreview(uitk.UbuntuUIToolkitCustomProxyObjectBase): |
183 | 327 | 345 | ||
184 | 328 | @autopilot.logging.log_action(logger.info) | 346 | @autopilot.logging.log_action(logger.info) |
185 | 329 | 347 | ||
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 | 6 | # under the terms of the GNU General Public License version 3, as published | 6 | # under the terms of the GNU General Public License version 3, as published |
191 | 7 | # by the Free Software Foundation. | 7 | # by the Free Software Foundation. |
192 | 8 | 8 | ||
193 | 9 | from base64 import b64decode | ||
194 | 9 | import http.server as http | 10 | import http.server as http |
195 | 10 | import json | 11 | import json |
196 | 11 | import logging | 12 | import logging |
197 | @@ -37,6 +38,12 @@ | |||
198 | 37 | self.end_headers() | 38 | self.end_headers() |
199 | 38 | self.wfile.write(html.encode()) | 39 | self.wfile.write(html.encode()) |
200 | 39 | 40 | ||
201 | 41 | def send_auth_request(self): | ||
202 | 42 | self.send_response(401) | ||
203 | 43 | self.send_header("WWW-Authenticate", "Basic realm=\"Enter Password\"") | ||
204 | 44 | self.end_headers() | ||
205 | 45 | self.send_html("Not Authorized") | ||
206 | 46 | |||
207 | 40 | def do_GET(self): | 47 | def do_GET(self): |
208 | 41 | if self.path == "/ping": | 48 | if self.path == "/ping": |
209 | 42 | self.send_response(200) | 49 | self.send_response(200) |
210 | @@ -183,6 +190,19 @@ | |||
211 | 183 | self.send_response(200) | 190 | self.send_response(200) |
212 | 184 | name = self.path[len("/tab/"):] | 191 | name = self.path[len("/tab/"):] |
213 | 185 | self.send_html('<html><body>' + name + '</body></html>') | 192 | self.send_html('<html><body>' + name + '</body></html>') |
214 | 193 | elif self.path.startswith("/basicauth"): | ||
215 | 194 | login = "user" | ||
216 | 195 | password = "pass" | ||
217 | 196 | if "Authorization" in self.headers: | ||
218 | 197 | header = self.headers.get("Authorization") | ||
219 | 198 | credentials = str(b64decode(header[len("Basic "):])).split(":") | ||
220 | 199 | if credentials[0] == login and credentials[1] == password: | ||
221 | 200 | self.send_response(200) | ||
222 | 201 | self.send_html("Authentication Successful !") | ||
223 | 202 | else: | ||
224 | 203 | self.send_auth_request() | ||
225 | 204 | else: | ||
226 | 205 | self.send_auth_request() | ||
227 | 186 | else: | 206 | else: |
228 | 187 | self.send_error(404) | 207 | self.send_error(404) |
229 | 188 | 208 | ||
230 | 189 | 209 | ||
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 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
236 | 2 | # | ||
237 | 3 | # Copyright 2015 Canonical | ||
238 | 4 | # | ||
239 | 5 | # This program is free software: you can redistribute it and/or modify it | ||
240 | 6 | # under the terms of the GNU General Public License version 3, as published | ||
241 | 7 | # by the Free Software Foundation. | ||
242 | 8 | # | ||
243 | 9 | # This program is distributed in the hope that it will be useful, | ||
244 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
245 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
246 | 12 | # GNU General Public License for more details. | ||
247 | 13 | # | ||
248 | 14 | # You should have received a copy of the GNU General Public License | ||
249 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
250 | 16 | |||
251 | 17 | from webbrowser_app.tests import StartOpenRemotePageTestCaseBase | ||
252 | 18 | |||
253 | 19 | |||
254 | 20 | class TestBasicAuthentication(StartOpenRemotePageTestCaseBase): | ||
255 | 21 | |||
256 | 22 | def setUp(self): | ||
257 | 23 | super(TestBasicAuthentication, self).setUp() | ||
258 | 24 | self.main_window.go_to_url(self.base_url + "/basicauth") | ||
259 | 25 | self.dialog = self.main_window.get_http_auth_dialog() | ||
260 | 26 | self.username = "user" | ||
261 | 27 | self.password = "pass" | ||
262 | 28 | |||
263 | 29 | def test_cancel(self): | ||
264 | 30 | self.pointing_device.click_object(self.dialog.get_deny_button()) | ||
265 | 31 | self.dialog.wait_until_destroyed() | ||
266 | 32 | |||
267 | 33 | def test_right_credentials(self): | ||
268 | 34 | username = self.dialog.get_username_field() | ||
269 | 35 | username.write(self.username) | ||
270 | 36 | password = self.dialog.get_password_field() | ||
271 | 37 | password.write(self.password) | ||
272 | 38 | self.pointing_device.click_object(self.dialog.get_allow_button()) | ||
273 | 39 | self.dialog.wait_until_destroyed() | ||
274 | 40 | |||
275 | 41 | def test_wrong_credentials(self): | ||
276 | 42 | username = self.dialog.get_username_field() | ||
277 | 43 | username.write("x") | ||
278 | 44 | password = self.dialog.get_password_field() | ||
279 | 45 | password.write("x") | ||
280 | 46 | self.pointing_device.click_object(self.dialog.get_allow_button()) | ||
281 | 47 | self.dialog.wait_until_destroyed() | ||
282 | 48 | # verify that a new dialog has been displayed | ||
283 | 49 | self.main_window.get_http_auth_dialog() |
FAILED: Continuous integration, rev:1009 jenkins. qa.ubuntu. com/job/ webbrowser- app-ci/ 1944/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 3347/console jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- amd64-ci/ 701/console jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- armhf-ci/ 701/console jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- i386-ci/ 701/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 3345/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/webbrowser- app-ci/ 1944/rebuild
http://