Merge lp:~gary-wzl77/account-plugins/mcloud-plugin-lp1587282 into lp:account-plugins
- mcloud-plugin-lp1587282
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 171 |
Proposed branch: | lp:~gary-wzl77/account-plugins/mcloud-plugin-lp1587282 |
Merge into: | lp:account-plugins |
Prerequisite: | lp:~mardy/account-plugins/owncloud-1570986 |
Diff against target: |
594 lines (+493/-0) 11 files modified
.bzrignore (+1/-0) Makefile.am (+2/-0) configure.ac (+15/-0) data/providers/mcloud.provider.in.in (+29/-0) debian/account-plugin-mcloud.install (+4/-0) debian/control (+8/-0) debian/rules (+2/-0) qml/mcloud/ErrorItem.qml (+48/-0) qml/mcloud/Main.qml (+7/-0) qml/mcloud/OAuth.qml (+283/-0) qml/mcloud/WebView.qml (+94/-0) |
To merge this branch: | bzr merge lp:~gary-wzl77/account-plugins/mcloud-plugin-lp1587282 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alberto Mardegan (community) | Needs Information | ||
Review via email: mp+296088@code.launchpad.net |
This proposal supersedes a proposal from 2016-05-31.
Commit message
Add mcloud plugin.
Description of the change
Add mcloud plugin
Testing instructions:
1) manually install the account-
2) download and install mcloud scope package from
https:/
3) launch mcloud scope and click "Login to MCloud"
Gary.Wang (gary-wzl77) wrote : | # |
Thanks for your hints. mandy
You can find the mcloud OAuth doc here,
http://
sorry it's written in Chinese. I guess google translate can help on this :)
Also I tried to modify the provider file according to your tips
1. web_server mechanism (with DisableStatePar
server popups error page
however If we specify DisableStatePar
log:
qml: Authentication error, code 1
qml: Removing credentials...
2. user_agent mechanism
log:
qml: Authentication error, code 3
qml: Removing credentials...
qml: ====== PLUGIN FINISHED ======
Root cause is the url format that cmcc server give us back is not correct when it navigates to our redirect url with authorized code.
http://
The correct one should be like as following
http://
Error occurs when authentication flow runs here
https:/
That's why I apply workaround1 & 2 in this mechanism to create fake "access token".
Actually, we can check if url contains '?' in this step.
But to be honest, I don't like this "fix" since redirection url format is incompliant with OAuth2.0 specs.
I create a test scope to reproduce above issues, Please take a look.
https:/
Thanks.
Alberto Mardegan (mardy) wrote : | # |
On 01/06/2016 14:48, Gary.Wang wrote:
> Also I tried to modify the provider file according to your tips
> 1. web_server mechanism (with DisableStatePar
> server popups error page
>
> however If we specify DisableStatePar
> log:
> browser-request.cpp 123 ~BrowserRequest
> browser-request.cpp 323 closeView
> qml: Authentication error, code 1
> qml: Removing credentials...
>
> AccountService.
Can you please run the following command
echo "LoggingLevel=2" > ~/.config/
and then try again with the web_server method, and show me the contents
of the syslog? (in a pastebin)
I pushed my changes at lp:~mardy/account-plugins/mcloud-plugin-lp1587282
but I'm unable to test them because I don't know how to login. :-(
I managed to create an account in cmpassport.com, but I don't know what
I should enter in the login screen here. Can you help me?
Gary.Wang (gary-wzl77) wrote : | # |
Sorry, I think I would give your the test account in advance. I sent you via email. Please have a check.
I attach the link for syslog in pastebin
https:/
Here is the log after running online-
https:/
Please let me know if there is anything I can do for you.
Thanks.
Alberto Mardegan (mardy) wrote : | # |
Hi Gary, good news! :-)
Thanks to your help with the account, after some attempts I got the plugin working. My code is in lp:~mardy/account-plugins/mcloud-plugin-lp1587282 (I'll prepare a merge proposal of my branch into yours).
Unfortunately it requires a little change in the signon-plugin-oauth (https:/
I didn't have any problem because of the UserAgent, but I was testing on my desktop, so maybe on the phone it's different.
Gary.Wang (gary-wzl77) wrote : | # |
Hi mandy
That's great. Please have a check if it works on the phone.
Thanks so much for your help on this. :)
Preview Diff
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2016-05-31 09:02:02 +0000 |
3 | +++ .bzrignore 2016-05-31 09:02:02 +0000 |
4 | @@ -28,6 +28,7 @@ |
5 | /debian/account-plugin-google/ |
6 | /debian/account-plugin-icons/ |
7 | /debian/account-plugin-identica/ |
8 | +/debian/account-plugin-mcloud/ |
9 | /debian/account-plugin-owncloud/ |
10 | /debian/account-plugin-sina/ |
11 | /debian/account-plugin-sohu/ |
12 | |
13 | === modified file 'Makefile.am' |
14 | --- Makefile.am 2016-05-31 09:02:02 +0000 |
15 | +++ Makefile.am 2016-05-31 09:02:02 +0000 |
16 | @@ -89,6 +89,7 @@ |
17 | data/providers/identica.provider.in.in \ |
18 | data/providers/linkedin.provider.in.in \ |
19 | data/providers/instagram.provider.in.in \ |
20 | + data/providers/mcloud.provider.in.in \ |
21 | data/providers/owncloud.provider.in.in \ |
22 | data/providers/sina.provider.in.in \ |
23 | data/providers/sohu.provider.in.in \ |
24 | @@ -139,6 +140,7 @@ |
25 | # https://bugs.launchpad.net/bugs/1571587 |
26 | iconsdir = $(datadir)/icons/hicolor/32x32/apps |
27 | dist_icons_DATA = \ |
28 | + data/icons/mcloud.png \ |
29 | data/icons/owncloud.png \ |
30 | data/icons/vk.png |
31 | |
32 | |
33 | === modified file 'configure.ac' |
34 | --- configure.ac 2016-05-31 09:02:02 +0000 |
35 | +++ configure.ac 2016-05-31 09:02:02 +0000 |
36 | @@ -228,6 +228,20 @@ |
37 | AC_SUBST(SOHU_CLIENT_ID, ["$sohu_client_id"]) |
38 | AC_SUBST(SOHU_CLIENT_SECRET, ["$sohu_client_secret"]) |
39 | |
40 | +# Set Mcloud client id/secret |
41 | +AC_ARG_WITH(mcloud-client-id, |
42 | + [AS_HELP_STRING([--with-mcloud-client-id], |
43 | + [Mcloud client id])], |
44 | + [mcloud_client_id=$withval], |
45 | + [mcloud_client_id="APP1ZtqoN3R0002"]) |
46 | +AC_ARG_WITH(mcloud-client-secret, |
47 | + [AS_HELP_STRING([--with-mcloud-client-secret], |
48 | + [Mcloud client secret])], |
49 | + [mcloud_client_secret=$withval], |
50 | + [mcloud_client_secret="A70EFCDC91456349E7FDECF0A33574AC"]) |
51 | +AC_SUBST(MCLOUD_CLIENT_ID, ["$mcloud_client_id"]) |
52 | +AC_SUBST(MCLOUD_CLIENT_SECRET, ["$mcloud_client_secret"]) |
53 | + |
54 | # Set VK client id |
55 | AC_ARG_WITH(vk-client-id, |
56 | [AS_HELP_STRING([--with-vk-client-id], |
57 | @@ -252,6 +266,7 @@ |
58 | data/providers/identica.provider.in |
59 | data/providers/linkedin.provider.in |
60 | data/providers/instagram.provider.in |
61 | + data/providers/mcloud.provider.in |
62 | data/providers/owncloud.provider.in |
63 | data/providers/sina.provider.in |
64 | data/providers/sohu.provider.in |
65 | |
66 | === added file 'data/icons/mcloud.png' |
67 | Binary files data/icons/mcloud.png 1970-01-01 00:00:00 +0000 and data/icons/mcloud.png 2016-05-31 09:02:02 +0000 differ |
68 | === added file 'data/providers/mcloud.provider.in.in' |
69 | --- data/providers/mcloud.provider.in.in 1970-01-01 00:00:00 +0000 |
70 | +++ data/providers/mcloud.provider.in.in 2016-05-31 09:02:02 +0000 |
71 | @@ -0,0 +1,29 @@ |
72 | +<?xml version="1.0" encoding="UTF-8"?> |
73 | +<provider id="mcloud"> |
74 | + <name>MCloud</name> |
75 | + <icon>mcloud</icon> |
76 | + <translations>MCloud</translations> |
77 | + <domains>.*10086\.cn</domains> |
78 | + <plugin>generic-oauth</plugin> |
79 | + <single-account>true</single-account> |
80 | + <template> |
81 | + <group name="auth"> |
82 | + <setting name="method">oauth2</setting> |
83 | + <setting name="mechanism">user_agent</setting> |
84 | + <group name="oauth2"> |
85 | + <group name="user_agent"> |
86 | + <setting name="Host">caiyun.feixin.10086.cn</setting> |
87 | + <setting name="AuthPath">authorize.jsp</setting> |
88 | + <setting name="TokenPath">access_token</setting> |
89 | + <setting name="RedirectUri">http://developer.ubuntu.com/en/</setting> |
90 | + <setting name="ResponseType">code</setting> |
91 | + <setting name="ClientId">@MCLOUD_CLIENT_ID@</setting> |
92 | + <setting type="as" name="Scope">['nd_cloud']</setting> |
93 | + <setting name="ForceClientAuthViaRequestBody" type="b">true</setting> |
94 | + <setting name="DisableStateParameter" type="b">true</setting> |
95 | + <setting type="as" name="AllowedSchemes">['https', 'http']</setting> |
96 | + </group> |
97 | + </group> |
98 | + </group> |
99 | + </template> |
100 | +</provider> |
101 | |
102 | === added file 'debian/account-plugin-mcloud.install' |
103 | --- debian/account-plugin-mcloud.install 1970-01-01 00:00:00 +0000 |
104 | +++ debian/account-plugin-mcloud.install 2016-05-31 09:02:02 +0000 |
105 | @@ -0,0 +1,4 @@ |
106 | +usr/share/accounts/providers/mcloud.provider |
107 | +usr/share/accounts/qml-plugins/mcloud/*.qml |
108 | +usr/share/icons/hicolor/32x32/apps/mcloud.png |
109 | + |
110 | |
111 | === modified file 'debian/control' |
112 | --- debian/control 2016-05-31 09:02:02 +0000 |
113 | +++ debian/control 2016-05-31 09:02:02 +0000 |
114 | @@ -144,6 +144,14 @@ |
115 | Description: GNOME Control Center account plugin for single signon - Instagram |
116 | GNOME Control Center account plugins for single signon |
117 | |
118 | +Package: account-plugin-mcloud |
119 | +Architecture: all |
120 | +Depends: ${misc:Depends}, |
121 | + ubuntu-system-settings-online-accounts, |
122 | +Description: Account plugin for online accounts - mCloud |
123 | + Online Accounts plugin provide the user interface to create accounts for |
124 | + third party services. |
125 | + |
126 | Package: account-plugin-owncloud |
127 | Architecture: all |
128 | Depends: ${misc:Depends}, |
129 | |
130 | === modified file 'debian/rules' |
131 | --- debian/rules 2016-05-31 09:02:02 +0000 |
132 | +++ debian/rules 2016-05-31 09:02:02 +0000 |
133 | @@ -22,6 +22,8 @@ |
134 | --with-linkedin-consumer-secret="BazRki2LE8eZtcqh" \ |
135 | --with-instagram-client-id="01c3df41a2274a14882adea8e8ebbd46" \ |
136 | --with-instagram-client-secret="4751ccdc39c648719ea83cfb1c866c26" \ |
137 | + --with-mcloud-client-id="APP1ZtqoN3R0002" \ |
138 | + --with-mcloud-client-secret="A70EFCDC91456349E7FDECF0A33574AC" \ |
139 | --with-vk-client-id="5402699" |
140 | |
141 | override_dh_install: |
142 | |
143 | === added directory 'qml/mcloud' |
144 | === added file 'qml/mcloud/ErrorItem.qml' |
145 | --- qml/mcloud/ErrorItem.qml 1970-01-01 00:00:00 +0000 |
146 | +++ qml/mcloud/ErrorItem.qml 2016-05-31 09:02:02 +0000 |
147 | @@ -0,0 +1,48 @@ |
148 | +/* |
149 | + * Copyright (C) 2015 Canonical Ltd. |
150 | + * |
151 | + * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> |
152 | + * |
153 | + * This program is free software: you can redistribute it and/or modify it |
154 | + * under the terms of the GNU General Public License version 3, as published |
155 | + * by the Free Software Foundation. |
156 | + * |
157 | + * This program is distributed in the hope that it will be useful, but |
158 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
159 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
160 | + * PURPOSE. See the GNU General Public License for more details. |
161 | + * |
162 | + * You should have received a copy of the GNU General Public License along |
163 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
164 | + */ |
165 | + |
166 | +import QtQuick 2.0 |
167 | +import Ubuntu.Components 0.1 |
168 | +import Ubuntu.Components.ListItems 0.1 as ListItem |
169 | + |
170 | +Item { |
171 | + id: root |
172 | + |
173 | + signal retryRequested() |
174 | + |
175 | + Column { |
176 | + anchors { |
177 | + verticalCenter: parent.verticalCenter |
178 | + left: parent.left; right: parent.right |
179 | + } |
180 | + spacing: units.gu(2) |
181 | + |
182 | + Label { |
183 | + anchors { left: parent.left; right: parent.right } |
184 | + text: i18n.dtr("ubuntu-system-settings-online-accounts", "This service is not available right now. Try again later.") |
185 | + wrapMode: Text.WordWrap |
186 | + horizontalAlignment: Text.AlignHCenter |
187 | + } |
188 | + |
189 | + Button { |
190 | + anchors.horizontalCenter: parent.horizontalCenter |
191 | + text: i18n.dtr("ubuntu-system-settings-online-accounts", "Try Again") |
192 | + onClicked: root.retryRequested() |
193 | + } |
194 | + } |
195 | +} |
196 | |
197 | === added file 'qml/mcloud/Main.qml' |
198 | --- qml/mcloud/Main.qml 1970-01-01 00:00:00 +0000 |
199 | +++ qml/mcloud/Main.qml 2016-05-31 09:02:02 +0000 |
200 | @@ -0,0 +1,7 @@ |
201 | +import Ubuntu.OnlineAccounts.Plugin 1.0 |
202 | +import "." as Local |
203 | + |
204 | +OAuthMain { |
205 | + creationComponent: Local.OAuth { |
206 | + } |
207 | +} |
208 | |
209 | === added file 'qml/mcloud/OAuth.qml' |
210 | --- qml/mcloud/OAuth.qml 1970-01-01 00:00:00 +0000 |
211 | +++ qml/mcloud/OAuth.qml 2016-05-31 09:02:02 +0000 |
212 | @@ -0,0 +1,283 @@ |
213 | +/* |
214 | + * Copyright (C) 2013-2016 Canonical Ltd. |
215 | + * |
216 | + * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> |
217 | + * |
218 | + * This program is free software: you can redistribute it and/or modify it |
219 | + * under the terms of the GNU General Public License version 3, as published |
220 | + * by the Free Software Foundation. |
221 | + * |
222 | + * This program is distributed in the hope that it will be useful, but |
223 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
224 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
225 | + * PURPOSE. See the GNU General Public License for more details. |
226 | + * |
227 | + * You should have received a copy of the GNU General Public License along |
228 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
229 | + */ |
230 | + |
231 | +import QtQuick 2.0 |
232 | +import Ubuntu.Components 1.3 |
233 | +import Ubuntu.Components.ListItems 1.3 as ListItem |
234 | +import Ubuntu.Components.Popups 1.3 |
235 | +import Ubuntu.OnlineAccounts 0.1 |
236 | +import Ubuntu.OnlineAccounts.Plugin 1.0 |
237 | + |
238 | +Item { |
239 | + id: root |
240 | + |
241 | + /* To override the parameters coming from the .provider file: */ |
242 | + property variant authenticationParameters: {} |
243 | + /* To override the default access control list: */ |
244 | + property variant accessControlList: ["unconfined"] |
245 | + |
246 | + property variant authReply |
247 | + property bool isNewAccount: false |
248 | + property variant __account: account |
249 | + property bool __isAuthenticating: false |
250 | + property alias globalAccountService: globalAccountSettings |
251 | + property bool loading: loader.status == Loader.Null || loader.status == Loader.Loading |
252 | + |
253 | + signal authenticated(variant reply) |
254 | + signal authenticationError(variant error) |
255 | + signal finished |
256 | + |
257 | + anchors.fill: parent |
258 | + |
259 | + Component.onCompleted: { |
260 | + isNewAccount = (account.accountId === 0) |
261 | + enableAccount() |
262 | + authenticate() |
263 | + } |
264 | + |
265 | + RequestHandler { |
266 | + id: requestHandler |
267 | + onRequestChanged: { |
268 | + if (request) { |
269 | + console.log("RequestHandler captured request!") |
270 | + loader.setSource("WebView.qml", { |
271 | + "signonRequest": request |
272 | + }) |
273 | + } else { |
274 | + console.log("Request destroyed!") |
275 | + loader.source = "" |
276 | + } |
277 | + } |
278 | + } |
279 | + |
280 | + Credentials { |
281 | + id: creds |
282 | + caption: account.provider.id |
283 | + acl: accessControlList |
284 | + onCredentialsIdChanged: root.credentialsStored() |
285 | + } |
286 | + |
287 | + AccountService { |
288 | + id: globalAccountSettings |
289 | + objectHandle: account.accountServiceHandle |
290 | + credentials: creds |
291 | + autoSync: false |
292 | + |
293 | + onAuthenticated: { |
294 | + __isAuthenticating = false |
295 | + authReply = reply |
296 | + root.authenticated(reply) |
297 | + } |
298 | + onAuthenticationError: { |
299 | + __isAuthenticating = false |
300 | + root.authenticationError(error) |
301 | + } |
302 | + } |
303 | + |
304 | + AccountServiceModel { |
305 | + id: accountServices |
306 | + includeDisabled: true |
307 | + account: __account.objectHandle |
308 | + } |
309 | + |
310 | + ListItem.Base { |
311 | + visible: loading && !errorItem.visible |
312 | + height: units.gu(7) |
313 | + showDivider: false |
314 | + anchors.top: parent.top |
315 | + |
316 | + Item { |
317 | + height: units.gu(5) |
318 | + width: units.gu(30) |
319 | + anchors.horizontalCenter: parent.horizontalCenter |
320 | + anchors.top: parent.top |
321 | + anchors.margins: units.gu(1) |
322 | + |
323 | + ActivityIndicator { |
324 | + id: loadingIndicator |
325 | + anchors.verticalCenter: parent.verticalCenter |
326 | + anchors.left: parent.left |
327 | + anchors.leftMargin: units.gu(5) |
328 | + running: loading |
329 | + z: 1 |
330 | + } |
331 | + Label { |
332 | + text: i18n.dtr("ubuntu-system-settings-online-accounts", "Loading…") |
333 | + anchors.verticalCenter: parent.verticalCenter |
334 | + anchors.left: loadingIndicator.right |
335 | + anchors.leftMargin: units.gu(3) |
336 | + } |
337 | + } |
338 | + } |
339 | + |
340 | + Loader { |
341 | + id: loader |
342 | + anchors { |
343 | + top: parent.top |
344 | + left: parent.left |
345 | + right: parent.right |
346 | + bottom: Qt.inputMethod.visible ? osk.top : cancelButton.top |
347 | + } |
348 | + focus: true |
349 | + visible: !loading |
350 | + } |
351 | + |
352 | + ErrorItem { |
353 | + id: errorItem |
354 | + anchors { fill: parent; margins: units.gu(4) } |
355 | + visible: false |
356 | + onRetryRequested: { |
357 | + root.credentialsStored() |
358 | + visible = false |
359 | + } |
360 | + } |
361 | + |
362 | + KeyboardRectangle { |
363 | + id: osk |
364 | + } |
365 | + |
366 | + ListItem.SingleControl { |
367 | + id: cancelButton |
368 | + anchors.bottom: parent.bottom |
369 | + showDivider: false |
370 | + control: Button { |
371 | + text: i18n.dtr("ubuntu-system-settings-online-accounts", "Cancel") |
372 | + width: parent.width - units.gu(4) |
373 | + onClicked: root.cancel() |
374 | + } |
375 | + } |
376 | + |
377 | + AccountServiceModel { |
378 | + id: possiblyDuplicateAccounts |
379 | + service: "global" |
380 | + provider: __account.provider.id |
381 | + } |
382 | + |
383 | + function authenticate() { |
384 | + console.log("Authenticating...") |
385 | + creds.sync() |
386 | + } |
387 | + |
388 | + function credentialsStored() { |
389 | + console.log("Credentials stored, id: " + creds.credentialsId) |
390 | + if (creds.credentialsId == 0) return |
391 | + var parameters = {} |
392 | + parameters[requestHandler.matchKey] = requestHandler.matchId |
393 | + parameters["providerId"] = account.provider.id |
394 | + for (var p in authenticationParameters) { |
395 | + parameters[p] = authenticationParameters[p] |
396 | + } |
397 | + __isAuthenticating = true |
398 | + globalAccountSettings.authenticate(parameters) |
399 | + } |
400 | + |
401 | + function cancel() { |
402 | + if (__isAuthenticating) { |
403 | + /* This will cause the authentication to fail, and this method will |
404 | + * be invoked again to delete the credentials. */ |
405 | + globalAccountSettings.cancelAuthentication() |
406 | + return |
407 | + } |
408 | + if (isNewAccount && creds.credentialsId != 0) { |
409 | + console.log("Removing credentials...") |
410 | + creds.remove() |
411 | + creds.removed.connect(finished) |
412 | + } else { |
413 | + finished() |
414 | + } |
415 | + } |
416 | + |
417 | + function enableAccount() { |
418 | + globalAccountSettings.updateServiceEnabled(true) |
419 | + } |
420 | + |
421 | + function getUserName(reply, callback) { |
422 | + /* This should work for OAuth 1.0a; for OAuth 2.0 this function needs |
423 | + * to be reimplemented */ |
424 | + if ('ScreenName' in reply) return reply.ScreenName |
425 | + else if ('UserId' in reply) return reply.UserId |
426 | + return '' |
427 | + } |
428 | + |
429 | + function accountIsDuplicate(userName) { |
430 | + var model = possiblyDuplicateAccounts |
431 | + for (var i = 0; i < model.count; i++) { |
432 | + if (model.get(i, "displayName") == userName) |
433 | + return true |
434 | + } |
435 | + return false |
436 | + } |
437 | + |
438 | + function __gotUserName(userName, reply) { |
439 | + console.log("UserName: " + userName) |
440 | + if (userName != '') { |
441 | + if (accountIsDuplicate(userName)) { |
442 | + var dialog = PopupUtils.open(Qt.resolvedUrl("DuplicateAccount.qml")) |
443 | + dialog.closed.connect(cancel) |
444 | + return |
445 | + } |
446 | + account.updateDisplayName(userName) |
447 | + } |
448 | + beforeSaving(reply) |
449 | + } |
450 | + |
451 | + function saveAccount() { |
452 | + account.synced.connect(finished) |
453 | + account.sync() |
454 | + } |
455 | + |
456 | + /* reimplement this function in plugins in order to perform some actions |
457 | + * before quitting the plugin */ |
458 | + function beforeSaving(reply) { |
459 | + saveAccount() |
460 | + } |
461 | + |
462 | + function __getUserNameAndSave(reply) { |
463 | + /* If the completeCreation function is defined, run it */ |
464 | + if (typeof(completeCreation) == "function") { |
465 | + console.warn("The completeCreation method is deprecated; use getUserName() or beforeSaving() instead") |
466 | + completeCreation(reply) |
467 | + return |
468 | + } |
469 | + |
470 | + var userName = getUserName(reply, function(name) { |
471 | + __gotUserName(name, reply) |
472 | + }) |
473 | + if (typeof(userName) == "string") { |
474 | + __gotUserName(userName, reply) |
475 | + } else if (userName === false) { |
476 | + cancel() |
477 | + return |
478 | + } |
479 | + // otherwise (userName === true), wait for the callback to be invoked |
480 | + } |
481 | + |
482 | + onAuthenticated: __getUserNameAndSave(reply) |
483 | + |
484 | + onAuthenticationError: { |
485 | + console.log("Authentication error, code " + error.code) |
486 | + if (error.code == AccountService.NetworkError) { |
487 | + console.log("Network error") |
488 | + errorItem.visible = true |
489 | + return |
490 | + } |
491 | + root.cancel() |
492 | + } |
493 | + |
494 | + onFinished: loading = false |
495 | +} |
496 | |
497 | === added file 'qml/mcloud/WebView.qml' |
498 | --- qml/mcloud/WebView.qml 1970-01-01 00:00:00 +0000 |
499 | +++ qml/mcloud/WebView.qml 2016-05-31 09:02:02 +0000 |
500 | @@ -0,0 +1,94 @@ |
501 | +import QtQuick 2.0 |
502 | +import Ubuntu.Components 1.1 |
503 | +import Ubuntu.Web 0.2 |
504 | + |
505 | +WebView { |
506 | + id: root |
507 | + |
508 | + property QtObject signonRequest |
509 | + readonly property string token_url: "https://ose.caiyun.feixin.10086.cn/oauthApp/OAuth2/getToken" |
510 | + readonly property string redirect_url: "http://developer.ubuntu.com/en/" |
511 | + readonly property string client_id: "APP1ZtqoN3R0002" |
512 | + readonly property string client_pass: "A70EFCDC91456349E7FDECF0A33574AC" |
513 | + |
514 | + Component.onCompleted: { |
515 | + signonRequest.authenticated.connect(onAuthenticated) |
516 | + url = signonRequest.startUrl |
517 | + } |
518 | + |
519 | + //1.WORKAROUND: we need to retrieve refresh token instead of access token. |
520 | + function fetchRefreshToken(code) { |
521 | + var http = new XMLHttpRequest() |
522 | + var body = "grant_type=authorization_code&code="+code+"&redirect_uri="+redirect_url |
523 | + |
524 | + http.open("POST", token_url, true); |
525 | + http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); |
526 | + http.setRequestHeader("Authorization", "Basic " + Qt.btoa(client_id + ":" + client_pass)); |
527 | + http.onreadystatechange = function() { |
528 | + if (http.readyState === 4 && http.status == 200) { |
529 | + var response = JSON.parse(http.responseText) |
530 | + //create a fake access_token with refresh token. |
531 | + var urlStr = redirect_url+"#access_token="+response.refresh_token |
532 | + var authUrl = Qt.resolvedUrl(urlStr); |
533 | + signonRequest.currentUrl = authUrl |
534 | + } else { |
535 | + console.log("error: " + http.status) |
536 | + } |
537 | + }; |
538 | + |
539 | + http.send(body); |
540 | + } |
541 | + |
542 | + onLoadingStateChanged: { |
543 | + if (loading) { |
544 | + signonRequest.onLoadStarted() |
545 | + } else if (lastLoadSucceeded) { |
546 | + signonRequest.onLoadFinished(true) |
547 | + } else { |
548 | + signonRequest.onLoadFinished(false) |
549 | + } |
550 | + } |
551 | + |
552 | + onUrlChanged: { |
553 | + //2.WORKAROUND: retrieve refresh token if code is fetched |
554 | + var code_pattern= new RegExp("\\?code=.*&"); |
555 | + var urlStr = url.toString() |
556 | + if (code_pattern.test(urlStr)){ |
557 | + var code = urlStr.match(/\?code=(.*)&/)[1]; |
558 | + console.log("code::", code) |
559 | + fetchRefreshToken(code) |
560 | + } else { |
561 | + signonRequest.currentUrl = url |
562 | + } |
563 | + } |
564 | + |
565 | + //3.WORKAROUND: Apply desktop useragent to prevent server from detecting android client, |
566 | + //which causes authentication failure. |
567 | + context: WebContext { |
568 | + dataPath: signonRequest ? signonRequest.rootDir : "" |
569 | + userAgent: "Mozilla/5.0 (Linux; Ubuntu 14.04) AppleWebKit/537.36 Chromium/35.0.1870.2 Safari/537.36" |
570 | + } |
571 | + |
572 | + function onAuthenticated() { |
573 | + /* Get the cookies and set them on the request */ |
574 | + console.log("Authenticated; getting cookies") |
575 | + context.cookieManager.getCookiesResponse.connect(onGotCookies) |
576 | + context.cookieManager.getAllCookies() |
577 | + visible = false |
578 | + } |
579 | + |
580 | + function onGotCookies(requestId, cookies) { |
581 | + signonRequest.setCookies(cookies) |
582 | + } |
583 | + |
584 | + /* Taken from webbrowser-app */ |
585 | + ProgressBar { |
586 | + anchors.top: parent.top |
587 | + anchors.left: parent.left |
588 | + anchors.right: parent.right |
589 | + height: units.dp(3) |
590 | + showProgressPercentage: false |
591 | + visible: root.loading |
592 | + value: root.loadProgress / 100 |
593 | + } |
594 | +} |
Hi Gary, thanks for this plugin!
Do you have a link to the OAuth documentation for mccloud? Better if in English :-)
I don't believe that mccould OAuth implementation is special; what you have coded as WORKAROUND 1 & 2 seem to be the normal web flow. I think you can remove those two workarounds, and just change the .provider file by replacing "user_agent" with "web_server", then add your ClientSecret in there too, and it should work.
Once you get it to work, can you also try removing the "DisableStatePa rameter" option, and see if it continues working? It's preferable not to use that option, because it disables a security feature.
As for the user agent, could you please file a bug against https:/ /launchpad. net/ubuntu/ +source/ webbrowser- app and ask for a user-agent override to be added in Ubuntu.WebView?
If we manage to get all the above done, then we won't need any workarounds in the plugin, and we can avoid duplicating the code here. :-)