Merge lp:~gary-wzl77/account-plugins/mcloud-plugin-lp1587282 into lp:account-plugins

Proposed by Gary.Wang
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
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-plugin-mcloud package
2) download and install mcloud scope package from
   https://drive.google.com/open?id=0B2H9ECPSSfqIcGtmUEdZNHpVNVU
3) launch mcloud scope and click "Login to MCloud"

To post a comment you must log in.
Revision history for this message
Alberto Mardegan (mardy) wrote :

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 "DisableStateParameter" 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. :-)

review: Needs Information
Revision history for this message
Gary.Wang (gary-wzl77) wrote :

Thanks for your hints. mandy
 You can find the mcloud OAuth doc here,
 http://caiyun.feixin.10086.cn/Mcloud/dev/
 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 DisableStateParameter removed )
       server popups error page

       however If we specify DisableStateParameter in provider
       log:
       browser-request.cpp 123 ~BrowserRequestPrivate
       browser-request.cpp 323 closeView
       qml: Authentication error, code 1
       qml: Removing credentials...

       AccountService.NoAccountError. That's because session data returned from server doesn't contains user account information.

   2. user_agent mechanism
      log:
       bowser-request.cpp 123 ~BrowserRequestPrivate
       browser-request.cpp 323 closeView
       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://developer.ubuntu.com/en/?code=7598B08A870A5.....
     The correct one should be like as following
     http://developer.ubuntu.com/en/#code=7598B08A870A5.....

     Error occurs when authentication flow runs here
     https://gitlab.com/accounts-sso/signon-plugin-oauth2/blob/master/src/oauth2plugin.cpp#L355

     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://code.launchpad.net/~gary-wzl77/+junk/maccount

   Thanks.

Revision history for this message
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 DisableStateParameter removed )
> server popups error page
>
> however If we specify DisableStateParameter in provider
> log:
> browser-request.cpp 123 ~BrowserRequestPrivate
> browser-request.cpp 323 closeView
> qml: Authentication error, code 1
> qml: Removing credentials...
>
> AccountService.NoAccountError. That's because session data returned from server doesn't contains user account information.

Can you please run the following command

  echo "LoggingLevel=2" > ~/.config/signond.conf

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?

Revision history for this message
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://pastebin.canonical.com/157865/

Here is the log after running online-accounts-service
https://pastebin.canonical.com/157864/

Please let me know if there is anything I can do for you.
Thanks.

Revision history for this message
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://gitlab.com/accounts-sso/signon-plugin-oauth2/commit/e812eb3e76a1221074e3cf27208aacced5091e42) but I'll take care of landing that one.

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.

Revision history for this message
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.bzrignore'
--- .bzrignore 2016-05-31 09:02:02 +0000
+++ .bzrignore 2016-05-31 09:02:02 +0000
@@ -28,6 +28,7 @@
28/debian/account-plugin-google/28/debian/account-plugin-google/
29/debian/account-plugin-icons/29/debian/account-plugin-icons/
30/debian/account-plugin-identica/30/debian/account-plugin-identica/
31/debian/account-plugin-mcloud/
31/debian/account-plugin-owncloud/32/debian/account-plugin-owncloud/
32/debian/account-plugin-sina/33/debian/account-plugin-sina/
33/debian/account-plugin-sohu/34/debian/account-plugin-sohu/
3435
=== modified file 'Makefile.am'
--- Makefile.am 2016-05-31 09:02:02 +0000
+++ Makefile.am 2016-05-31 09:02:02 +0000
@@ -89,6 +89,7 @@
89 data/providers/identica.provider.in.in \89 data/providers/identica.provider.in.in \
90 data/providers/linkedin.provider.in.in \90 data/providers/linkedin.provider.in.in \
91 data/providers/instagram.provider.in.in \91 data/providers/instagram.provider.in.in \
92 data/providers/mcloud.provider.in.in \
92 data/providers/owncloud.provider.in.in \93 data/providers/owncloud.provider.in.in \
93 data/providers/sina.provider.in.in \94 data/providers/sina.provider.in.in \
94 data/providers/sohu.provider.in.in \95 data/providers/sohu.provider.in.in \
@@ -139,6 +140,7 @@
139# https://bugs.launchpad.net/bugs/1571587140# https://bugs.launchpad.net/bugs/1571587
140iconsdir = $(datadir)/icons/hicolor/32x32/apps141iconsdir = $(datadir)/icons/hicolor/32x32/apps
141dist_icons_DATA = \142dist_icons_DATA = \
143 data/icons/mcloud.png \
142 data/icons/owncloud.png \144 data/icons/owncloud.png \
143 data/icons/vk.png145 data/icons/vk.png
144146
145147
=== modified file 'configure.ac'
--- configure.ac 2016-05-31 09:02:02 +0000
+++ configure.ac 2016-05-31 09:02:02 +0000
@@ -228,6 +228,20 @@
228AC_SUBST(SOHU_CLIENT_ID, ["$sohu_client_id"])228AC_SUBST(SOHU_CLIENT_ID, ["$sohu_client_id"])
229AC_SUBST(SOHU_CLIENT_SECRET, ["$sohu_client_secret"])229AC_SUBST(SOHU_CLIENT_SECRET, ["$sohu_client_secret"])
230230
231# Set Mcloud client id/secret
232AC_ARG_WITH(mcloud-client-id,
233 [AS_HELP_STRING([--with-mcloud-client-id],
234 [Mcloud client id])],
235 [mcloud_client_id=$withval],
236 [mcloud_client_id="APP1ZtqoN3R0002"])
237AC_ARG_WITH(mcloud-client-secret,
238 [AS_HELP_STRING([--with-mcloud-client-secret],
239 [Mcloud client secret])],
240 [mcloud_client_secret=$withval],
241 [mcloud_client_secret="A70EFCDC91456349E7FDECF0A33574AC"])
242AC_SUBST(MCLOUD_CLIENT_ID, ["$mcloud_client_id"])
243AC_SUBST(MCLOUD_CLIENT_SECRET, ["$mcloud_client_secret"])
244
231# Set VK client id245# Set VK client id
232AC_ARG_WITH(vk-client-id,246AC_ARG_WITH(vk-client-id,
233 [AS_HELP_STRING([--with-vk-client-id],247 [AS_HELP_STRING([--with-vk-client-id],
@@ -252,6 +266,7 @@
252 data/providers/identica.provider.in266 data/providers/identica.provider.in
253 data/providers/linkedin.provider.in267 data/providers/linkedin.provider.in
254 data/providers/instagram.provider.in268 data/providers/instagram.provider.in
269 data/providers/mcloud.provider.in
255 data/providers/owncloud.provider.in270 data/providers/owncloud.provider.in
256 data/providers/sina.provider.in271 data/providers/sina.provider.in
257 data/providers/sohu.provider.in272 data/providers/sohu.provider.in
258273
=== added file 'data/icons/mcloud.png'
259Binary files data/icons/mcloud.png 1970-01-01 00:00:00 +0000 and data/icons/mcloud.png 2016-05-31 09:02:02 +0000 differ274Binary 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
=== added file 'data/providers/mcloud.provider.in.in'
--- data/providers/mcloud.provider.in.in 1970-01-01 00:00:00 +0000
+++ data/providers/mcloud.provider.in.in 2016-05-31 09:02:02 +0000
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<provider id="mcloud">
3 <name>MCloud</name>
4 <icon>mcloud</icon>
5 <translations>MCloud</translations>
6 <domains>.*10086\.cn</domains>
7 <plugin>generic-oauth</plugin>
8 <single-account>true</single-account>
9 <template>
10 <group name="auth">
11 <setting name="method">oauth2</setting>
12 <setting name="mechanism">user_agent</setting>
13 <group name="oauth2">
14 <group name="user_agent">
15 <setting name="Host">caiyun.feixin.10086.cn</setting>
16 <setting name="AuthPath">authorize.jsp</setting>
17 <setting name="TokenPath">access_token</setting>
18 <setting name="RedirectUri">http://developer.ubuntu.com/en/</setting>
19 <setting name="ResponseType">code</setting>
20 <setting name="ClientId">@MCLOUD_CLIENT_ID@</setting>
21 <setting type="as" name="Scope">['nd_cloud']</setting>
22 <setting name="ForceClientAuthViaRequestBody" type="b">true</setting>
23 <setting name="DisableStateParameter" type="b">true</setting>
24 <setting type="as" name="AllowedSchemes">['https', 'http']</setting>
25 </group>
26 </group>
27 </group>
28 </template>
29</provider>
030
=== added file 'debian/account-plugin-mcloud.install'
--- debian/account-plugin-mcloud.install 1970-01-01 00:00:00 +0000
+++ debian/account-plugin-mcloud.install 2016-05-31 09:02:02 +0000
@@ -0,0 +1,4 @@
1usr/share/accounts/providers/mcloud.provider
2usr/share/accounts/qml-plugins/mcloud/*.qml
3usr/share/icons/hicolor/32x32/apps/mcloud.png
4
05
=== modified file 'debian/control'
--- debian/control 2016-05-31 09:02:02 +0000
+++ debian/control 2016-05-31 09:02:02 +0000
@@ -144,6 +144,14 @@
144Description: GNOME Control Center account plugin for single signon - Instagram144Description: GNOME Control Center account plugin for single signon - Instagram
145 GNOME Control Center account plugins for single signon145 GNOME Control Center account plugins for single signon
146146
147Package: account-plugin-mcloud
148Architecture: all
149Depends: ${misc:Depends},
150 ubuntu-system-settings-online-accounts,
151Description: Account plugin for online accounts - mCloud
152 Online Accounts plugin provide the user interface to create accounts for
153 third party services.
154
147Package: account-plugin-owncloud155Package: account-plugin-owncloud
148Architecture: all156Architecture: all
149Depends: ${misc:Depends},157Depends: ${misc:Depends},
150158
=== modified file 'debian/rules'
--- debian/rules 2016-05-31 09:02:02 +0000
+++ debian/rules 2016-05-31 09:02:02 +0000
@@ -22,6 +22,8 @@
22 --with-linkedin-consumer-secret="BazRki2LE8eZtcqh" \22 --with-linkedin-consumer-secret="BazRki2LE8eZtcqh" \
23 --with-instagram-client-id="01c3df41a2274a14882adea8e8ebbd46" \23 --with-instagram-client-id="01c3df41a2274a14882adea8e8ebbd46" \
24 --with-instagram-client-secret="4751ccdc39c648719ea83cfb1c866c26" \24 --with-instagram-client-secret="4751ccdc39c648719ea83cfb1c866c26" \
25 --with-mcloud-client-id="APP1ZtqoN3R0002" \
26 --with-mcloud-client-secret="A70EFCDC91456349E7FDECF0A33574AC" \
25 --with-vk-client-id="5402699"27 --with-vk-client-id="5402699"
2628
27override_dh_install:29override_dh_install:
2830
=== added directory 'qml/mcloud'
=== added file 'qml/mcloud/ErrorItem.qml'
--- qml/mcloud/ErrorItem.qml 1970-01-01 00:00:00 +0000
+++ qml/mcloud/ErrorItem.qml 2016-05-31 09:02:02 +0000
@@ -0,0 +1,48 @@
1/*
2 * Copyright (C) 2015 Canonical Ltd.
3 *
4 * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.0
20import Ubuntu.Components 0.1
21import Ubuntu.Components.ListItems 0.1 as ListItem
22
23Item {
24 id: root
25
26 signal retryRequested()
27
28 Column {
29 anchors {
30 verticalCenter: parent.verticalCenter
31 left: parent.left; right: parent.right
32 }
33 spacing: units.gu(2)
34
35 Label {
36 anchors { left: parent.left; right: parent.right }
37 text: i18n.dtr("ubuntu-system-settings-online-accounts", "This service is not available right now. Try again later.")
38 wrapMode: Text.WordWrap
39 horizontalAlignment: Text.AlignHCenter
40 }
41
42 Button {
43 anchors.horizontalCenter: parent.horizontalCenter
44 text: i18n.dtr("ubuntu-system-settings-online-accounts", "Try Again")
45 onClicked: root.retryRequested()
46 }
47 }
48}
049
=== added file 'qml/mcloud/Main.qml'
--- qml/mcloud/Main.qml 1970-01-01 00:00:00 +0000
+++ qml/mcloud/Main.qml 2016-05-31 09:02:02 +0000
@@ -0,0 +1,7 @@
1import Ubuntu.OnlineAccounts.Plugin 1.0
2import "." as Local
3
4OAuthMain {
5 creationComponent: Local.OAuth {
6 }
7}
08
=== added file 'qml/mcloud/OAuth.qml'
--- qml/mcloud/OAuth.qml 1970-01-01 00:00:00 +0000
+++ qml/mcloud/OAuth.qml 2016-05-31 09:02:02 +0000
@@ -0,0 +1,283 @@
1/*
2 * Copyright (C) 2013-2016 Canonical Ltd.
3 *
4 * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.0
20import Ubuntu.Components 1.3
21import Ubuntu.Components.ListItems 1.3 as ListItem
22import Ubuntu.Components.Popups 1.3
23import Ubuntu.OnlineAccounts 0.1
24import Ubuntu.OnlineAccounts.Plugin 1.0
25
26Item {
27 id: root
28
29 /* To override the parameters coming from the .provider file: */
30 property variant authenticationParameters: {}
31 /* To override the default access control list: */
32 property variant accessControlList: ["unconfined"]
33
34 property variant authReply
35 property bool isNewAccount: false
36 property variant __account: account
37 property bool __isAuthenticating: false
38 property alias globalAccountService: globalAccountSettings
39 property bool loading: loader.status == Loader.Null || loader.status == Loader.Loading
40
41 signal authenticated(variant reply)
42 signal authenticationError(variant error)
43 signal finished
44
45 anchors.fill: parent
46
47 Component.onCompleted: {
48 isNewAccount = (account.accountId === 0)
49 enableAccount()
50 authenticate()
51 }
52
53 RequestHandler {
54 id: requestHandler
55 onRequestChanged: {
56 if (request) {
57 console.log("RequestHandler captured request!")
58 loader.setSource("WebView.qml", {
59 "signonRequest": request
60 })
61 } else {
62 console.log("Request destroyed!")
63 loader.source = ""
64 }
65 }
66 }
67
68 Credentials {
69 id: creds
70 caption: account.provider.id
71 acl: accessControlList
72 onCredentialsIdChanged: root.credentialsStored()
73 }
74
75 AccountService {
76 id: globalAccountSettings
77 objectHandle: account.accountServiceHandle
78 credentials: creds
79 autoSync: false
80
81 onAuthenticated: {
82 __isAuthenticating = false
83 authReply = reply
84 root.authenticated(reply)
85 }
86 onAuthenticationError: {
87 __isAuthenticating = false
88 root.authenticationError(error)
89 }
90 }
91
92 AccountServiceModel {
93 id: accountServices
94 includeDisabled: true
95 account: __account.objectHandle
96 }
97
98 ListItem.Base {
99 visible: loading && !errorItem.visible
100 height: units.gu(7)
101 showDivider: false
102 anchors.top: parent.top
103
104 Item {
105 height: units.gu(5)
106 width: units.gu(30)
107 anchors.horizontalCenter: parent.horizontalCenter
108 anchors.top: parent.top
109 anchors.margins: units.gu(1)
110
111 ActivityIndicator {
112 id: loadingIndicator
113 anchors.verticalCenter: parent.verticalCenter
114 anchors.left: parent.left
115 anchors.leftMargin: units.gu(5)
116 running: loading
117 z: 1
118 }
119 Label {
120 text: i18n.dtr("ubuntu-system-settings-online-accounts", "Loading…")
121 anchors.verticalCenter: parent.verticalCenter
122 anchors.left: loadingIndicator.right
123 anchors.leftMargin: units.gu(3)
124 }
125 }
126 }
127
128 Loader {
129 id: loader
130 anchors {
131 top: parent.top
132 left: parent.left
133 right: parent.right
134 bottom: Qt.inputMethod.visible ? osk.top : cancelButton.top
135 }
136 focus: true
137 visible: !loading
138 }
139
140 ErrorItem {
141 id: errorItem
142 anchors { fill: parent; margins: units.gu(4) }
143 visible: false
144 onRetryRequested: {
145 root.credentialsStored()
146 visible = false
147 }
148 }
149
150 KeyboardRectangle {
151 id: osk
152 }
153
154 ListItem.SingleControl {
155 id: cancelButton
156 anchors.bottom: parent.bottom
157 showDivider: false
158 control: Button {
159 text: i18n.dtr("ubuntu-system-settings-online-accounts", "Cancel")
160 width: parent.width - units.gu(4)
161 onClicked: root.cancel()
162 }
163 }
164
165 AccountServiceModel {
166 id: possiblyDuplicateAccounts
167 service: "global"
168 provider: __account.provider.id
169 }
170
171 function authenticate() {
172 console.log("Authenticating...")
173 creds.sync()
174 }
175
176 function credentialsStored() {
177 console.log("Credentials stored, id: " + creds.credentialsId)
178 if (creds.credentialsId == 0) return
179 var parameters = {}
180 parameters[requestHandler.matchKey] = requestHandler.matchId
181 parameters["providerId"] = account.provider.id
182 for (var p in authenticationParameters) {
183 parameters[p] = authenticationParameters[p]
184 }
185 __isAuthenticating = true
186 globalAccountSettings.authenticate(parameters)
187 }
188
189 function cancel() {
190 if (__isAuthenticating) {
191 /* This will cause the authentication to fail, and this method will
192 * be invoked again to delete the credentials. */
193 globalAccountSettings.cancelAuthentication()
194 return
195 }
196 if (isNewAccount && creds.credentialsId != 0) {
197 console.log("Removing credentials...")
198 creds.remove()
199 creds.removed.connect(finished)
200 } else {
201 finished()
202 }
203 }
204
205 function enableAccount() {
206 globalAccountSettings.updateServiceEnabled(true)
207 }
208
209 function getUserName(reply, callback) {
210 /* This should work for OAuth 1.0a; for OAuth 2.0 this function needs
211 * to be reimplemented */
212 if ('ScreenName' in reply) return reply.ScreenName
213 else if ('UserId' in reply) return reply.UserId
214 return ''
215 }
216
217 function accountIsDuplicate(userName) {
218 var model = possiblyDuplicateAccounts
219 for (var i = 0; i < model.count; i++) {
220 if (model.get(i, "displayName") == userName)
221 return true
222 }
223 return false
224 }
225
226 function __gotUserName(userName, reply) {
227 console.log("UserName: " + userName)
228 if (userName != '') {
229 if (accountIsDuplicate(userName)) {
230 var dialog = PopupUtils.open(Qt.resolvedUrl("DuplicateAccount.qml"))
231 dialog.closed.connect(cancel)
232 return
233 }
234 account.updateDisplayName(userName)
235 }
236 beforeSaving(reply)
237 }
238
239 function saveAccount() {
240 account.synced.connect(finished)
241 account.sync()
242 }
243
244 /* reimplement this function in plugins in order to perform some actions
245 * before quitting the plugin */
246 function beforeSaving(reply) {
247 saveAccount()
248 }
249
250 function __getUserNameAndSave(reply) {
251 /* If the completeCreation function is defined, run it */
252 if (typeof(completeCreation) == "function") {
253 console.warn("The completeCreation method is deprecated; use getUserName() or beforeSaving() instead")
254 completeCreation(reply)
255 return
256 }
257
258 var userName = getUserName(reply, function(name) {
259 __gotUserName(name, reply)
260 })
261 if (typeof(userName) == "string") {
262 __gotUserName(userName, reply)
263 } else if (userName === false) {
264 cancel()
265 return
266 }
267 // otherwise (userName === true), wait for the callback to be invoked
268 }
269
270 onAuthenticated: __getUserNameAndSave(reply)
271
272 onAuthenticationError: {
273 console.log("Authentication error, code " + error.code)
274 if (error.code == AccountService.NetworkError) {
275 console.log("Network error")
276 errorItem.visible = true
277 return
278 }
279 root.cancel()
280 }
281
282 onFinished: loading = false
283}
0284
=== added file 'qml/mcloud/WebView.qml'
--- qml/mcloud/WebView.qml 1970-01-01 00:00:00 +0000
+++ qml/mcloud/WebView.qml 2016-05-31 09:02:02 +0000
@@ -0,0 +1,94 @@
1import QtQuick 2.0
2import Ubuntu.Components 1.1
3import Ubuntu.Web 0.2
4
5WebView {
6 id: root
7
8 property QtObject signonRequest
9 readonly property string token_url: "https://ose.caiyun.feixin.10086.cn/oauthApp/OAuth2/getToken"
10 readonly property string redirect_url: "http://developer.ubuntu.com/en/"
11 readonly property string client_id: "APP1ZtqoN3R0002"
12 readonly property string client_pass: "A70EFCDC91456349E7FDECF0A33574AC"
13
14 Component.onCompleted: {
15 signonRequest.authenticated.connect(onAuthenticated)
16 url = signonRequest.startUrl
17 }
18
19 //1.WORKAROUND: we need to retrieve refresh token instead of access token.
20 function fetchRefreshToken(code) {
21 var http = new XMLHttpRequest()
22 var body = "grant_type=authorization_code&code="+code+"&redirect_uri="+redirect_url
23
24 http.open("POST", token_url, true);
25 http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
26 http.setRequestHeader("Authorization", "Basic " + Qt.btoa(client_id + ":" + client_pass));
27 http.onreadystatechange = function() {
28 if (http.readyState === 4 && http.status == 200) {
29 var response = JSON.parse(http.responseText)
30 //create a fake access_token with refresh token.
31 var urlStr = redirect_url+"#access_token="+response.refresh_token
32 var authUrl = Qt.resolvedUrl(urlStr);
33 signonRequest.currentUrl = authUrl
34 } else {
35 console.log("error: " + http.status)
36 }
37 };
38
39 http.send(body);
40 }
41
42 onLoadingStateChanged: {
43 if (loading) {
44 signonRequest.onLoadStarted()
45 } else if (lastLoadSucceeded) {
46 signonRequest.onLoadFinished(true)
47 } else {
48 signonRequest.onLoadFinished(false)
49 }
50 }
51
52 onUrlChanged: {
53 //2.WORKAROUND: retrieve refresh token if code is fetched
54 var code_pattern= new RegExp("\\?code=.*&");
55 var urlStr = url.toString()
56 if (code_pattern.test(urlStr)){
57 var code = urlStr.match(/\?code=(.*)&/)[1];
58 console.log("code::", code)
59 fetchRefreshToken(code)
60 } else {
61 signonRequest.currentUrl = url
62 }
63 }
64
65 //3.WORKAROUND: Apply desktop useragent to prevent server from detecting android client,
66 //which causes authentication failure.
67 context: WebContext {
68 dataPath: signonRequest ? signonRequest.rootDir : ""
69 userAgent: "Mozilla/5.0 (Linux; Ubuntu 14.04) AppleWebKit/537.36 Chromium/35.0.1870.2 Safari/537.36"
70 }
71
72 function onAuthenticated() {
73 /* Get the cookies and set them on the request */
74 console.log("Authenticated; getting cookies")
75 context.cookieManager.getCookiesResponse.connect(onGotCookies)
76 context.cookieManager.getAllCookies()
77 visible = false
78 }
79
80 function onGotCookies(requestId, cookies) {
81 signonRequest.setCookies(cookies)
82 }
83
84 /* Taken from webbrowser-app */
85 ProgressBar {
86 anchors.top: parent.top
87 anchors.left: parent.left
88 anchors.right: parent.right
89 height: units.dp(3)
90 showProgressPercentage: false
91 visible: root.loading
92 value: root.loadProgress / 100
93 }
94}

Subscribers

People subscribed via source and target branches