Merge lp:~dobey/ubuntuone-credentials/signon-plugin-part2 into lp:ubuntuone-credentials

Proposed by dobey
Status: Superseded
Proposed branch: lp:~dobey/ubuntuone-credentials/signon-plugin-part2
Merge into: lp:ubuntuone-credentials
Diff against target: 1349 lines (+441/-507)
14 files modified
data/ubuntuone.provider (+2/-2)
debian/control (+1/-1)
libubuntuoneauth/CMakeLists.txt (+4/-0)
libubuntuoneauth/authenticator.cpp (+174/-0)
libubuntuoneauth/authenticator.h (+71/-0)
libubuntuoneauth/keyring.cpp (+22/-158)
libubuntuoneauth/keyring.h (+10/-10)
libubuntuoneauth/libubuntuoneauth.symbols (+2/-1)
libubuntuoneauth/ssoservice.cpp (+51/-33)
libubuntuoneauth/ssoservice.h (+3/-3)
signon-plugin/tests/test_plugin.cpp (+59/-110)
signon-plugin/ubuntuone-plugin.cpp (+36/-184)
signon-plugin/ubuntuone-plugin.h (+1/-5)
signon-plugin/ubuntuonedata.h (+5/-0)
To merge this branch: bzr merge lp:~dobey/ubuntuone-credentials/signon-plugin-part2
Reviewer Review Type Date Requested Status
Unity API Team Pending
Review via email: mp+296713@code.launchpad.net

Commit message

Final pieces for switching to the new signon plug-in.

To post a comment you must log in.
260. By dobey

Restore ABI compat.

261. By dobey

Restore some of the removed code to reduce diff size and use storeToken hack.

262. By dobey

Try to store the credentials a different way.

263. By dobey

Hopefully store the token correctly now too.

264. By dobey

Must use 'unsigned int' in symbols file for quint32.

265. By dobey

The login() call should never emit credentialsNotFound.
Don't emit an error in existingCredentialsId if there is no account.

266. By dobey

Refactor so createSession/process are called after identity is stored.
Fix invalidateCredentials to actually invalidate the credentials.

267. By dobey

Emit tokenNotFound immediately if no account is found.

268. By dobey

Need to depend on signond, since apparently nothing else does.

269. By dobey

Try to handle process() calls better.
Fix a few small typos.

270. By dobey

Set the m_invalidate flag properly.

271. By dobey

Refactor token clearing to separate method.
Handle existing secret separately from invalidation request.

Unmerged revisions

271. By dobey

Refactor token clearing to separate method.
Handle existing secret separately from invalidation request.

270. By dobey

Set the m_invalidate flag properly.

269. By dobey

Try to handle process() calls better.
Fix a few small typos.

268. By dobey

Need to depend on signond, since apparently nothing else does.

267. By dobey

Emit tokenNotFound immediately if no account is found.

266. By dobey

Refactor so createSession/process are called after identity is stored.
Fix invalidateCredentials to actually invalidate the credentials.

265. By dobey

The login() call should never emit credentialsNotFound.
Don't emit an error in existingCredentialsId if there is no account.

264. By dobey

Must use 'unsigned int' in symbols file for quint32.

263. By dobey

Hopefully store the token correctly now too.

262. By dobey

Try to store the credentials a different way.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/ubuntuone.provider'
2--- data/ubuntuone.provider 2016-04-19 15:04:15 +0000
3+++ data/ubuntuone.provider 2016-06-07 18:42:38 +0000
4@@ -8,8 +8,8 @@
5
6 <template>
7 <group name="auth">
8- <setting name="method">password</setting>
9- <setting name="mechanism">password</setting>
10+ <setting name="method">ubuntuone</setting>
11+ <setting name="mechanism">ubuntuone</setting>
12 </group>
13 </template>
14 </provider>
15
16=== modified file 'debian/control'
17--- debian/control 2016-04-27 14:07:35 +0000
18+++ debian/control 2016-06-07 18:42:38 +0000
19@@ -76,7 +76,7 @@
20 ${misc:Pre-Depends},
21 Depends:
22 account-plugin-tools,
23- signon-plugin-password,
24+ signon-plugin-ubuntuone (= ${source:Version}),
25 sqlite3,
26 ubuntuone-credentials-common (= ${source:Version}),
27 ${misc:Depends},
28
29=== modified file 'libubuntuoneauth/CMakeLists.txt'
30--- libubuntuoneauth/CMakeLists.txt 2016-04-21 09:25:58 +0000
31+++ libubuntuoneauth/CMakeLists.txt 2016-06-07 18:42:38 +0000
32@@ -13,6 +13,10 @@
33 SET (LIB_TYPE STATIC)
34 ENDIF (BUILD_STATIC_LIBS)
35
36+# Some slots are deprecated; disable warnings on deprecations, because
37+# moc-generated files are using these methods
38+SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
39+
40 # The sources for building the library
41 FILE (GLOB SOURCES *.cpp)
42 # HEADERS only includes the public headers for installation.
43
44=== added file 'libubuntuoneauth/authenticator.cpp'
45--- libubuntuoneauth/authenticator.cpp 1970-01-01 00:00:00 +0000
46+++ libubuntuoneauth/authenticator.cpp 2016-06-07 18:42:38 +0000
47@@ -0,0 +1,174 @@
48+/*
49+ * Copyright 2016 Canonical Ltd.
50+ *
51+ * This library is free software; you can redistribute it and/or
52+ * modify it under the terms of version 3 of the GNU Lesser General Public
53+ * License as published by the Free Software Foundation.
54+ *
55+ * This program is distributed in the hope that it will be useful,
56+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
57+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
58+ * General Public License for more details.
59+ *
60+ * You should have received a copy of the GNU Lesser General Public
61+ * License along with this library; if not, write to the
62+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
63+ * Boston, MA 02110-1301, USA.
64+ */
65+
66+#include "authenticator.h"
67+#include "../signon-plugin/ubuntuonedata.h"
68+
69+#include <Accounts/Account>
70+#include <Accounts/Service>
71+#include <SignOn/AuthSession>
72+#include <SignOn/Identity>
73+#include <SignOn/IdentityInfo>
74+
75+#include <QDebug>
76+
77+using namespace Internal;
78+using namespace UbuntuOne;
79+
80+Authenticator::Authenticator(Accounts::Manager *manager, QObject *parent):
81+ QObject(parent),
82+ m_manager(manager),
83+ m_invalidate(false),
84+ m_uiAllowed(true)
85+{
86+ if (!m_manager) {
87+ m_manager = new Accounts::Manager(this);
88+ }
89+}
90+
91+void Authenticator::handleError(const SignOn::Error &e)
92+{
93+ qCritical() << "Authentication error:" << e.message();
94+ Q_EMIT error(AuthenticationError, e.message());
95+}
96+
97+void Authenticator::handleSessionData(const SignOn::SessionData &data)
98+{
99+ PluginData reply = data.data<PluginData>();
100+
101+ auto errorCode = PluginData::ErrorCode(reply.U1ErrorCode());
102+ auto message = reply.U1ErrorMessage();
103+ if (errorCode != PluginData::NoError) {
104+ switch (errorCode) {
105+ case PluginData::OneTimePasswordRequired:
106+ qDebug() << "Error: OTP required";
107+ Q_EMIT error(OneTimePasswordRequired, message);
108+ break;
109+ case PluginData::InvalidPassword:
110+ qDebug() << "Error: invalid password";
111+ Q_EMIT error(InvalidPassword, message);
112+ break;
113+ default:
114+ qWarning() << "Unknown error:" << message;
115+ Q_EMIT error(AuthenticationError, message);
116+ }
117+ return;
118+ }
119+
120+ Token token(reply.TokenKey(), reply.TokenSecret(),
121+ reply.ConsumerKey(), reply.ConsumerSecret(),
122+ reply.DateCreated(), reply.DateUpdated());
123+ Q_EMIT authenticated(token);
124+}
125+
126+quint32 Authenticator::credentialsId()
127+{
128+ QString providerId("ubuntuone");
129+ Accounts::AccountIdList accountIds = m_manager->accountList(providerId);
130+
131+ if (accountIds.isEmpty()) {
132+ qDebug() << "authenticate(): No UbuntuOne accounts found";
133+ Q_EMIT error(AccountNotFound, "");
134+ return 0;
135+ }
136+
137+ if (Q_UNLIKELY(accountIds.count() > 1)) {
138+ qWarning() << "authenticate(): Found '" << accountIds.count() <<
139+ "' accounts. Using first.";
140+ }
141+
142+ qDebug() << "authenticate(): Using account '" << accountIds[0] << "'.";
143+
144+ auto account = m_manager->account(accountIds[0]);
145+ if (Q_UNLIKELY(!account)) {
146+ qDebug() << "Couldn't load account";
147+ /* This could either happen because the account was deleted right while
148+ * we were loading it, or because the accounts DB was locked by another
149+ * app. Let's just return an authentication error here, so the client
150+ * can retry.
151+ */
152+ Q_EMIT error(AuthenticationError, "");
153+ return 0;
154+ }
155+
156+ /* Here we should check that the account service is enabled; but since the
157+ * old code was not doing this check, and that from the API there is no way
158+ * of knowing which service we are interested in, let's leave it as a TODO.
159+ */
160+
161+ return account->credentialsId();
162+}
163+
164+void Authenticator::authenticate(const QString &tokenName,
165+ const QString &userName,
166+ const QString &password,
167+ const QString &otp)
168+{
169+ SignOn::Identity *identity;
170+ if (userName.isEmpty()) {
171+ // Use existing account
172+ quint32 id = credentialsId();
173+ if (Q_UNLIKELY(!id)) return;
174+
175+ identity = SignOn::Identity::existingIdentity(id, this);
176+ if (Q_UNLIKELY(!identity)) {
177+ qCritical() << "authenticate(): unable to load credentials" << id;
178+ Q_EMIT error(AccountNotFound, "");
179+ return;
180+ }
181+ } else {
182+ identity = SignOn::Identity::newIdentity(SignOn::IdentityInfo(), this);
183+ }
184+
185+ auto session = identity->createSession(QStringLiteral("ubuntuone"));
186+ if (Q_UNLIKELY(!session)) {
187+ qCritical() << "Unable to create AuthSession.";
188+ Q_EMIT error(AuthenticationError, "");
189+ return;
190+ }
191+
192+ connect(session, SIGNAL(response(const SignOn::SessionData&)),
193+ this, SLOT(handleSessionData(const SignOn::SessionData&)));
194+ connect(session, SIGNAL(error(const SignOn::Error&)),
195+ this, SLOT(handleError(const SignOn::Error&)));
196+
197+ PluginData data;
198+ data.setTokenName(tokenName);
199+ data.setUserName(userName);
200+ data.setSecret(password);
201+ data.setOneTimePassword(otp);
202+ int uiPolicy = m_uiAllowed ?
203+ SignOn::DefaultPolicy : SignOn::NoUserInteractionPolicy;
204+ data.setUiPolicy(uiPolicy);
205+ if (m_invalidate) {
206+ data.setInvalidateToken(true);
207+ m_invalidate = false;
208+ }
209+
210+ session->process(data, QStringLiteral("ubuntuone"));
211+}
212+
213+void Authenticator::invalidateCredentials()
214+{
215+ m_invalidate = true;
216+}
217+
218+void Authenticator::setUiAllowed(bool allowed)
219+{
220+ m_uiAllowed = allowed;
221+}
222
223=== added file 'libubuntuoneauth/authenticator.h'
224--- libubuntuoneauth/authenticator.h 1970-01-01 00:00:00 +0000
225+++ libubuntuoneauth/authenticator.h 2016-06-07 18:42:38 +0000
226@@ -0,0 +1,71 @@
227+/*
228+ * Copyright 2016 Canonical Ltd.
229+ *
230+ * This library is free software; you can redistribute it and/or
231+ * modify it under the terms of version 3 of the GNU Lesser General Public
232+ * License as published by the Free Software Foundation.
233+ *
234+ * This program is distributed in the hope that it will be useful,
235+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
236+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
237+ * General Public License for more details.
238+ *
239+ * You should have received a copy of the GNU Lesser General Public
240+ * License along with this library; if not, write to the
241+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
242+ * Boston, MA 02110-1301, USA.
243+ */
244+#ifndef _U1_AUTHENTICATOR_H_
245+#define _U1_AUTHENTICATOR_H_
246+
247+#include <Accounts/Manager>
248+#include <SignOn/Identity>
249+
250+#include <QObject>
251+
252+#include "token.h"
253+
254+namespace Internal {
255+
256+class Authenticator : public QObject
257+{
258+ Q_OBJECT
259+
260+public:
261+ enum ErrorCode {
262+ NoError = 0,
263+ AccountNotFound,
264+ OneTimePasswordRequired,
265+ InvalidPassword,
266+ AuthenticationError, // will create more specific codes if needed
267+ };
268+
269+ explicit Authenticator(Accounts::Manager *manager = 0, QObject *parent = 0);
270+
271+ void authenticate(const QString &tokenName,
272+ const QString &userName = QString(),
273+ const QString &password = QString(),
274+ const QString &otp = QString());
275+ void invalidateCredentials();
276+ void setUiAllowed(bool allowed);
277+
278+Q_SIGNALS:
279+ void authenticated(const UbuntuOne::Token& token);
280+ void error(Internal::Authenticator::ErrorCode code, const QString& message);
281+
282+private:
283+ quint32 credentialsId();
284+
285+private Q_SLOTS:
286+ void handleError(const SignOn::Error &error);
287+ void handleSessionData(const SignOn::SessionData &data);
288+
289+private:
290+ Accounts::Manager *m_manager;
291+ bool m_invalidate;
292+ bool m_uiAllowed;
293+};
294+
295+} /* namespace */
296+
297+#endif /* _U1_AUTHENTICATOR_H_ */
298
299=== modified file 'libubuntuoneauth/keyring.cpp'
300--- libubuntuoneauth/keyring.cpp 2016-04-19 15:04:15 +0000
301+++ libubuntuoneauth/keyring.cpp 2016-06-07 18:42:38 +0000
302@@ -23,7 +23,9 @@
303
304 #include <QDebug>
305
306+#include "authenticator.h"
307 #include "keyring.h"
308+#include "../signon-plugin/ubuntuonedata.h"
309
310 using namespace Accounts;
311 using namespace SignOn;
312@@ -38,166 +40,28 @@
313 _account = nullptr;
314 }
315
316- void Keyring::handleError(const SignOn::Error &error)
317- {
318- qCritical() << "Error:" << error.message();
319- emit keyringError(error.message());
320- }
321-
322- void Keyring::handleSessionData(const SignOn::SessionData &data)
323- {
324- QString secret = data.Secret();
325-
326- if (secret.length() == 0) {
327- QString msg("Could not read credentials secret value.");
328- qCritical() << msg;
329- emit keyringError(msg);
330- return;
331- }
332-
333- Token *token = Token::fromQuery(secret);
334- if (token->isValid()) {
335- emit tokenFound(*token);
336- } else {
337- QString message("Failed to convert result to Token object.");
338- qCritical() << message;
339- emit keyringError(message);
340- }
341- delete token;
342- }
343-
344 void Keyring::findToken()
345 {
346- QString _acctName("ubuntuone");
347- AccountIdList _ids = _manager.accountList(_acctName);
348- Identity *identity;
349- Account *account;
350-
351- if (_ids.length() > 0) {
352- if (_ids.length() > 1) {
353- qDebug() << "findToken(): Found '" << _ids.length() << "' accounts. Using first.";
354- }
355- account = _manager.account(_ids[0]);
356- qDebug() << "findToken(): Using Ubuntu One account '" << _ids[0] << "'.";
357- identity = Identity::existingIdentity(account->credentialsId());
358- if (identity == NULL) {
359- qCritical() << "findToken(): disabled account " << _acctName << _ids[0];
360- emit tokenNotFound();
361- return;
362- }
363- AuthSession *session = identity->createSession(QStringLiteral("password"));
364- if (session != NULL) {
365- connect(session, SIGNAL(response(const SignOn::SessionData&)),
366- this, SLOT(handleSessionData(const SignOn::SessionData&)));
367- connect(session, SIGNAL(error(const SignOn::Error&)),
368- this, SLOT(handleError(const SignOn::Error&)));
369- session->process(SessionData(), QStringLiteral("password"));
370- return;
371- }
372- qCritical() << "Unable to create AuthSession.";
373- }
374- qDebug() << "findToken(): No accounts found matching " << _acctName;
375- emit tokenNotFound();
376- }
377-
378- void Keyring::handleCredentialsStored(const quint32 id)
379- {
380- QString _acctName("ubuntuone");
381- AccountIdList _ids = _manager.accountList(_acctName);
382-
383- _account->selectService();
384- _account->setCredentialsId(id);
385-
386- for (auto service: _account->services()) {
387- _account->selectService(service);
388- _account->setEnabled(true);
389- }
390- _account->sync();
391- emit tokenStored();
392- }
393-
394- void Keyring::storeToken(Token token)
395- {
396- storeToken(token, "");
397- }
398-
399- void Keyring::storeToken(Token token, const QString& displayName)
400- {
401- QString _acctName("ubuntuone");
402- AccountIdList _ids = _manager.accountList(_acctName);
403- Identity *identity = NULL;
404-
405- if (_ids.length() > 0) {
406- if (_ids.length() > 1) {
407- qDebug() << "storeToken(): Found '" << _ids.length() << "' accounts. Using first.";
408- }
409- _account = _manager.account(_ids[0]);
410- qDebug() << "storeToken(): Using Ubuntu One account '" << _ids[0] << "'.";
411- } else {
412- qDebug() << "in storeToken(): no accounts found in accountList, creating new";
413- _account = _manager.createAccount(_acctName);
414- }
415- _account->setEnabled(true);
416-
417- if (!displayName.isEmpty()) {
418- _account->setDisplayName(displayName);
419- }
420-
421- if(_account->credentialsId() == 0) {
422- qDebug() << "storeToken() : creating new Identity for account " << _account->id() ;
423- identity = Identity::newIdentity();
424- } else {
425- qDebug() << "storeToken(): identity found.";
426- identity = Identity::existingIdentity(_account->credentialsId());
427- }
428-
429- Q_ASSERT(identity != NULL);
430-
431- connect(identity, SIGNAL(error(const SignOn::Error&)),
432- this, SLOT(handleError(const SignOn::Error&)));
433- connect(identity, SIGNAL(credentialsStored(const quint32)),
434- this, SLOT(handleCredentialsStored(const quint32)));
435-
436- IdentityInfo info = IdentityInfo();
437-
438- info.setSecret(token.toQuery(), true);
439- info.setAccessControlList(QStringList() << "unconfined");
440- identity->storeCredentials(info);
441- }
442-
443- void Keyring::handleAccountRemoved()
444- {
445- emit tokenDeleted();
446- }
447-
448- void Keyring::handleDeleteError(const SignOn::Error &error)
449- {
450- // Just log the error here, as we don't want to infinite loop.
451- qWarning() << "Error deleting token:" << error.message();
452- }
453-
454- void Keyring::deleteToken()
455- {
456- QString _acctName("ubuntuone");
457- AccountIdList _ids = _manager.accountList(_acctName);
458- if (_ids.length() > 0) {
459- if (_ids.length() > 1) {
460- qDebug() << "deleteToken(): Found '" << _ids.length() << "' accounts. Using first.";
461- }
462- Account *account = _manager.account(_ids[0]);
463- qDebug() << "deleteToken(): Using Ubuntu One account '" << _ids[0] << "'.";
464- Identity *identity = Identity::existingIdentity(account->credentialsId());
465- connect(account, SIGNAL(removed()),
466- this, SLOT(handleAccountRemoved()));
467- connect(identity, SIGNAL(error(const SignOn::Error&)),
468- this, SLOT(handleDeleteError(const SignOn::Error&)));
469-
470- identity->remove();
471- account->remove();
472- account->sync();
473- return;
474- }
475- emit tokenNotFound();
476+ using namespace Internal;
477+
478+ auto authenticator = new Authenticator(&_manager);
479+ authenticator->setUiAllowed(false);
480+
481+ connect(authenticator, &Authenticator::authenticated,
482+ [=](const Token &token) {
483+ Q_EMIT tokenFound(token);
484+ authenticator->deleteLater();
485+ });
486+ connect(authenticator, &Authenticator::error,
487+ [=](Authenticator::ErrorCode code) {
488+ if (code == Authenticator::AccountNotFound) {
489+ Q_EMIT tokenNotFound();
490+ } else {
491+ Q_EMIT keyringError("Authentication failed");
492+ }
493+ authenticator->deleteLater();
494+ });
495+ authenticator->authenticate(Token::buildTokenName());
496 }
497
498 } // namespace UbuntuOne
499
500=== modified file 'libubuntuoneauth/keyring.h'
501--- libubuntuoneauth/keyring.h 2016-04-21 09:25:58 +0000
502+++ libubuntuoneauth/keyring.h 2016-06-07 18:42:38 +0000
503@@ -36,24 +36,24 @@
504 explicit Keyring(QObject *parent=NULL);
505
506 void findToken();
507- void storeToken(Token token);
508- void storeToken(Token token, const QString& displayName);
509- void deleteToken();
510+ Q_DECL_DEPRECATED void storeToken(Token token);
511+ Q_DECL_DEPRECATED void storeToken(Token token, const QString& displayName);
512+ Q_DECL_DEPRECATED void deleteToken() {};
513
514 Q_SIGNALS:
515 void tokenFound(const Token& token);
516 void tokenNotFound();
517- void tokenStored();
518- void tokenDeleted();
519+ Q_DECL_DEPRECATED void tokenStored();
520+ Q_DECL_DEPRECATED void tokenDeleted();
521
522 void keyringError(QString message);
523
524 private Q_SLOTS:
525- void handleError(const SignOn::Error &error);
526- void handleSessionData(const SignOn::SessionData &data);
527- void handleCredentialsStored(const quint32 id);
528- void handleAccountRemoved();
529- void handleDeleteError(const SignOn::Error &error);
530+ Q_DECL_DEPRECATED void handleError(const SignOn::Error &error) {};
531+ Q_DECL_DEPRECATED void handleSessionData(const SignOn::SessionData &data) {};
532+ Q_DECL_DEPRECATED void handleCredentialsStored(const quint32 id) {};
533+ Q_DECL_DEPRECATED void handleAccountRemoved() {};
534+ Q_DECL_DEPRECATED void handleDeleteError(const SignOn::Error &error) {};
535
536 private:
537 Accounts::Manager _manager;
538
539=== modified file 'libubuntuoneauth/libubuntuoneauth.symbols'
540--- libubuntuoneauth/libubuntuoneauth.symbols 2013-07-22 15:54:02 +0000
541+++ libubuntuoneauth/libubuntuoneauth.symbols 2016-06-07 18:42:38 +0000
542@@ -1,7 +1,8 @@
543 {
544 global:
545 extern "C++" {
546- *UbuntuOne::*;
547+ UbuntuOne::*;
548+ *for?UbuntuOne::*;
549 };
550 qt_*;
551 local:
552
553=== modified file 'libubuntuoneauth/ssoservice.cpp'
554--- libubuntuoneauth/ssoservice.cpp 2016-04-19 15:04:15 +0000
555+++ libubuntuoneauth/ssoservice.cpp 2016-06-07 18:42:38 +0000
556@@ -22,6 +22,7 @@
557 #include <QNetworkRequest>
558 #include <QUrlQuery>
559
560+#include "authenticator.h"
561 #include "logging.h"
562 #include "ssoservice.h"
563 #include "requests.h"
564@@ -45,27 +46,14 @@
565
566 // create the keyring that will be used to store and retrieve the different tokens
567 _keyring = new Keyring(this);
568- _nam = new QNetworkAccessManager(this);
569-
570 connect(_keyring, SIGNAL(tokenFound(const Token&)),
571 this, SLOT(handleCredentialsFound(const Token&)));
572 connect(_keyring, SIGNAL(tokenNotFound()),
573 this, SLOT(handleCredentialsNotFound()));
574
575- connect(_keyring, SIGNAL(tokenStored()),
576- this, SLOT(handleTokenStored()));
577- connect(_keyring, SIGNAL(tokenDeleted()),
578- this, SLOT(handleTokenDeleted()));
579-
580 connect(_keyring, SIGNAL(keyringError(QString)),
581 this, SLOT(handleKeyringError(QString)));
582
583- connect(_nam, SIGNAL(finished(QNetworkReply*)),
584- this, SLOT(accountPinged(QNetworkReply*)));
585-
586- connect(&(_provider),
587- SIGNAL(OAuthTokenGranted(const OAuthTokenResponse&)),
588- this, SLOT(tokenReceived(const OAuthTokenResponse&)));
589 connect(&(_provider),
590 SIGNAL(AccountGranted(const AccountResponse&)),
591 this, SLOT(accountRegistered(const AccountResponse&)));
592@@ -92,11 +80,6 @@
593 emit credentialsFound(token);
594 }
595
596- void SSOService::handleTokenStored()
597- {
598- emit credentialsStored();
599- }
600-
601 void SSOService::registerUser(QString email, QString password,
602 QString display_name)
603 {
604@@ -116,12 +99,33 @@
605
606 void SSOService::login(QString email, QString password, QString twoFactorCode)
607 {
608- OAuthTokenRequest request(getAuthBaseUrl(),
609- email, password,
610- Token::buildTokenName(), twoFactorCode);
611- _tempEmail = email;
612-
613- _provider.GetOAuthToken(request);
614+ using namespace Internal;
615+
616+ auto authenticator = new Authenticator;
617+ /* The caller of this API is assumed to have his own UI, so no support
618+ * from SignOn UI is needed or even desired. */
619+ authenticator->setUiAllowed(false);
620+
621+ connect(authenticator, &Authenticator::authenticated,
622+ [=](const Token &token) {
623+ Q_EMIT credentialsStored();
624+ Q_EMIT credentialsFound(token);
625+ authenticator->deleteLater();
626+ });
627+ connect(authenticator, &Authenticator::error,
628+ [=](Authenticator::ErrorCode code, const QString& message) {
629+ if (code == Authenticator::AccountNotFound) {
630+ Q_EMIT credentialsNotFound();
631+ } else if (code == Authenticator::OneTimePasswordRequired) {
632+ Q_EMIT twoFactorAuthRequired();
633+ } else {
634+ /* TODO: deliver a proper error response. */
635+ Q_EMIT requestFailed(ErrorResponse(400, "", "LOGIN_FAILED", message));
636+ }
637+ authenticator->deleteLater();
638+ });
639+ authenticator->authenticate(Token::buildTokenName(),
640+ email, password, twoFactorCode);
641 }
642
643 void SSOService::handleTwoFactorAuthRequired()
644@@ -145,14 +149,6 @@
645 return baseUrl;
646 }
647
648- void SSOService::tokenReceived(const OAuthTokenResponse& token)
649- {
650- Token realToken = Token(token.token_key(), token.token_secret(),
651- token.consumer_key(), token.consumer_secret(),
652- token.date_created(), token.date_updated());
653- _keyring->storeToken(realToken, _tempEmail);
654- }
655-
656 void SSOService::accountPinged(QNetworkReply*)
657 {
658 /* DEPRECATED */
659@@ -160,7 +156,29 @@
660
661 void SSOService::invalidateCredentials()
662 {
663- _keyring->deleteToken();
664+ using namespace Internal;
665+
666+ auto authenticator = new Authenticator;
667+ /* The caller of this API is assumed to have his own UI, so no support
668+ * from SignOn UI is needed or even desired. */
669+ authenticator->setUiAllowed(false);
670+
671+ connect(authenticator, &Authenticator::authenticated,
672+ [=](const Token &token) {
673+ Q_EMIT credentialsFound(token);
674+ authenticator->deleteLater();
675+ });
676+ connect(authenticator, &Authenticator::error,
677+ [=](Authenticator::ErrorCode code, const QString& message) {
678+ if (code == Authenticator::AccountNotFound) {
679+ Q_EMIT credentialsNotFound();
680+ } else {
681+ /* TODO: deliver a proper error response. */
682+ Q_EMIT requestFailed(ErrorResponse(400, "", "LOGIN_FAILED", message));
683+ }
684+ authenticator->deleteLater();
685+ });
686+ authenticator->invalidateCredentials();
687 }
688
689 void SSOService::errorOccurred(const ErrorResponse& error)
690
691=== modified file 'libubuntuoneauth/ssoservice.h'
692--- libubuntuoneauth/ssoservice.h 2016-04-21 09:25:58 +0000
693+++ libubuntuoneauth/ssoservice.h 2016-06-07 18:42:38 +0000
694@@ -57,11 +57,11 @@
695
696 private slots:
697 void accountPinged(QNetworkReply*);
698- void handleTokenStored();
699- void handleTokenDeleted() { emit credentialsDeleted(); };
700+ Q_DECL_DEPRECATED void handleTokenStored() {};
701+ Q_DECL_DEPRECATED void handleTokenDeleted() {};
702 void handleCredentialsFound(const Token& token);
703 void handleCredentialsNotFound();
704- void tokenReceived(const OAuthTokenResponse& token);
705+ Q_DECL_DEPRECATED void tokenReceived(const OAuthTokenResponse& token) {};
706 void accountRegistered(const AccountResponse& account);
707 void errorOccurred(const ErrorResponse&);
708 void handleTwoFactorAuthRequired();
709
710=== modified file 'signon-plugin/tests/test_plugin.cpp'
711--- signon-plugin/tests/test_plugin.cpp 2016-04-27 08:41:03 +0000
712+++ signon-plugin/tests/test_plugin.cpp 2016-06-07 18:42:38 +0000
713@@ -28,6 +28,7 @@
714
715 #include <SignOn/uisessiondata_priv.h>
716
717+#include "token.h"
718 #include "ubuntuone-plugin.h"
719
720 using namespace SignOn;
721@@ -149,7 +150,6 @@
722 void testPluginMechanisms();
723 void testStoredToken_data();
724 void testStoredToken();
725- void testUserInteraction();
726 void testTokenCreation_data();
727 void testTokenCreation();
728
729@@ -222,7 +222,6 @@
730 {
731 QTest::addColumn<QVariantMap>("sessionData");
732 QTest::addColumn<int>("expectedErrorCode");
733- QTest::addColumn<bool>("uiExpected");
734 QTest::addColumn<QVariantMap>("expectedResponse");
735 QTest::addColumn<QVariantMap>("expectedStore");
736
737@@ -232,34 +231,65 @@
738
739 QTest::newRow("empty") <<
740 sessionData.toMap() <<
741- int(Error::MissingData) <<
742- false << QVariantMap() << QVariantMap();
743-
744- sessionData.setTokenName("helloworld");
745+ -1 <<
746+ QVariantMap() << QVariantMap();
747+
748+ sessionData = UbuntuOne::PluginData();
749+ QString tokenName = UbuntuOne::Token::buildTokenName();
750+ sessionData.setStoredData(QVariantMap {
751+ { tokenName, QVariantMap {
752+ { "ConsumerKey", "ck" },
753+ { "ConsumerSecret", "cs" },
754+ { "TokenKey", "tk" },
755+ { "TokenSecret", "ts" },
756+ }},
757+ });
758+ response = UbuntuOne::PluginData();
759+ response.setConsumerKey("ck");
760+ response.setConsumerSecret("cs");
761+ response.setTokenKey("tk");
762+ response.setTokenSecret("ts");
763+ response.setTokenName(tokenName);
764+ stored = UbuntuOne::PluginData();
765+ QTest::newRow("stored, valid") <<
766+ sessionData.toMap() <<
767+ -1 <<
768+ response.toMap() << stored.toMap();
769+
770+ sessionData = UbuntuOne::PluginData();
771+ sessionData.setStoredData(QVariantMap {
772+ { tokenName, QVariantMap {
773+ { "ConsumerKey", "ck" },
774+ { "ConsumerSecret", "cs" },
775+ { "TokenKey", "tk" },
776+ { "TokenSecret", "ts" },
777+ }},
778+ });
779+ sessionData.setInvalidateToken(true);
780+ response = UbuntuOne::PluginData();
781+ response.setTokenName(tokenName);
782+ stored = UbuntuOne::PluginData();
783+ QVariantMap storedData;
784+ stored.setStoredData(storedData);
785+ QTest::newRow("clearing token") <<
786+ sessionData.toMap() <<
787+ -1 <<
788+ response.toMap() << stored.toMap();
789+
790+ sessionData = UbuntuOne::PluginData();
791 sessionData.setSecret("consumer_key=aAa&consumer_secret=bBb&name=helloworld&token=cCc&token_secret=dDd");
792- response.setConsumerKey("aAa");
793- response.setConsumerSecret("bBb");
794- response.setTokenKey("cCc");
795- response.setTokenSecret("dDd");
796- QVariantMap storedData;
797- storedData[sessionData.TokenName()] = response.toMap();
798- stored.setStoredData(storedData);
799- response.setTokenName(sessionData.TokenName());
800- QTest::newRow("in secret, valid") <<
801+ response = UbuntuOne::PluginData();
802+ stored = UbuntuOne::PluginData();
803+ QTest::newRow("in secret, clearing") <<
804 sessionData.toMap() <<
805 -1 <<
806- false << response.toMap() << stored.toMap();
807- sessionData = UbuntuOne::PluginData();
808- response = UbuntuOne::PluginData();
809- stored = UbuntuOne::PluginData();
810- storedData.clear();
811+ response.toMap() << stored.toMap();
812 }
813
814 void PluginTest::testStoredToken()
815 {
816 QFETCH(QVariantMap, sessionData);
817 QFETCH(int, expectedErrorCode);
818- QFETCH(bool, uiExpected);
819 QFETCH(QVariantMap, expectedResponse);
820 QFETCH(QVariantMap, expectedStore);
821
822@@ -272,7 +302,7 @@
823 m_testPlugin->process(sessionData, "ubuntuone");
824 if (expectedErrorCode < 0) {
825 QCOMPARE(error.count(), 0);
826- QTRY_COMPARE(userActionRequired.count(), uiExpected ? 1 : 0);
827+ QTRY_COMPARE(userActionRequired.count(), 0);
828 if (!expectedResponse.isEmpty()) {
829 QTRY_COMPARE(result.count(), 1);
830 QVariantMap resp = result.at(0).at(0).value<SessionData>().toMap();
831@@ -296,66 +326,6 @@
832 }
833 }
834
835-void PluginTest::testUserInteraction()
836-{
837- QSignalSpy result(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)));
838- QSignalSpy error(m_testPlugin, SIGNAL(error(const SignOn::Error &)));
839- QSignalSpy userActionRequired(m_testPlugin,
840- SIGNAL(userActionRequired(const SignOn::UiSessionData&)));
841- QSignalSpy store(m_testPlugin, SIGNAL(store(const SignOn::SessionData&)));
842-
843- TestNetworkAccessManager *nam = new TestNetworkAccessManager;
844- m_testPlugin->m_networkAccessManager = nam;
845-
846- UbuntuOne::PluginData sessionData;
847- sessionData.setTokenName("helloworld");
848- sessionData.setUserName("tom@example.com");
849- m_testPlugin->process(sessionData, "ubuntuone");
850-
851- QTRY_COMPARE(userActionRequired.count(), 1);
852- QVariantMap data =
853- userActionRequired.at(0).at(0).value<UiSessionData>().toMap();
854- /* We want the title to be there, but we don't care about its value here */
855- QVERIFY(data.contains(SSOUI_KEY_TITLE));
856- data.remove(SSOUI_KEY_TITLE);
857- QVariantMap expectedUserInteraction;
858- expectedUserInteraction[SSOUI_KEY_USERNAME] = "tom@example.com";
859- expectedUserInteraction[SSOUI_KEY_QUERYPASSWORD] = true;
860- QCOMPARE(data, expectedUserInteraction);
861- userActionRequired.clear();
862-
863- /* Prepare network reply */
864- TestNetworkReply *reply = new TestNetworkReply(this);
865- reply->setStatusCode(401);
866- reply->setContent("{\n"
867- " \"code\": \"TWOFACTOR_REQUIRED\",\n"
868- " \"message\": \"This account requires 2-factor authentication.\",\n"
869- " \"extra\": {}\n"
870- "}");
871- nam->setNextReply(reply);
872-
873- QVariantMap userReply;
874- userReply[SSOUI_KEY_USERNAME] = "tom@example.com";
875- userReply[SSOUI_KEY_PASSWORD] = "s3cr3t";
876- m_testPlugin->userActionFinished(userReply);
877-
878- /* Again the plugin should request user interaction, as OTP is required */
879- QTRY_COMPARE(userActionRequired.count(), 1);
880- data = userActionRequired.at(0).at(0).value<UiSessionData>().toMap();
881- expectedUserInteraction.clear();
882- expectedUserInteraction[SSOUI_KEY_USERNAME] = "tom@example.com";
883- expectedUserInteraction[SSOUI_KEY_PASSWORD] = "s3cr3t";
884- expectedUserInteraction[SSOUI_KEY_QUERY2FA] = true;
885- /* We want the map to contain the SSOUI_KEY_2FA_TEXT, but we don't care
886- * about the value */
887- QVERIFY(data.contains(SSOUI_KEY_2FA_TEXT));
888- data.remove(SSOUI_KEY_2FA_TEXT);
889- /* Same goes for the title */
890- QVERIFY(data.contains(SSOUI_KEY_TITLE));
891- data.remove(SSOUI_KEY_TITLE);
892- QCOMPARE(data, expectedUserInteraction);
893-}
894-
895 void PluginTest::testTokenCreation_data()
896 {
897 QTest::addColumn<QVariantMap>("sessionData");
898@@ -365,12 +335,10 @@
899 QTest::addColumn<int>("expectedErrorCode");
900 QTest::addColumn<QVariantMap>("expectedResponse");
901 QTest::addColumn<QVariantMap>("expectedStore");
902- QTest::addColumn<QVariantMap>("expectedUserInteraction");
903
904 UbuntuOne::PluginData sessionData;
905 UbuntuOne::PluginData response;
906 UbuntuOne::PluginData stored;
907- QVariantMap userInteraction;
908
909 // Successful creation, with password only
910 sessionData.setTokenName("helloworld");
911@@ -382,10 +350,10 @@
912 response.setTokenSecret("dDd");
913 response.setDateUpdated("2013-01-11 12:43:23");
914 response.setDateCreated("2013-01-11 12:43:23");
915+ response.setTokenName(sessionData.TokenName());
916 QVariantMap storedData;
917 storedData[sessionData.TokenName()] = response.toMap();
918 stored.setStoredData(storedData);
919- response.setTokenName(sessionData.TokenName());
920 QTest::newRow("no OTP needed, 201") <<
921 sessionData.toMap() <<
922 -1 <<
923@@ -400,7 +368,7 @@
924 " \"date_updated\": \"2013-01-11 12:43:23\"\n"
925 "}") <<
926 -1 <<
927- response.toMap() << stored.toMap() << userInteraction;
928+ response.toMap() << stored.toMap();
929 sessionData = UbuntuOne::PluginData();
930 response = UbuntuOne::PluginData();
931 stored = UbuntuOne::PluginData();
932@@ -410,8 +378,6 @@
933 sessionData.setTokenName("helloworld");
934 sessionData.setUserName("jim@example.com");
935 sessionData.setSecret("s3cr3t");
936- userInteraction[SSOUI_KEY_USERNAME] = "jim@example.com";
937- userInteraction[SSOUI_KEY_QUERYPASSWORD] = true;
938 QTest::newRow("wrong password") <<
939 sessionData.toMap() <<
940 -1 <<
941@@ -421,16 +387,12 @@
942 " \"extra\": {}\n"
943 "}") <<
944 -1 <<
945- response.toMap() << stored.toMap() << userInteraction;
946+ response.toMap() << stored.toMap();
947 sessionData = UbuntuOne::PluginData();
948- userInteraction.clear();
949
950 // Empty username
951 sessionData.setTokenName("helloworld");
952 sessionData.setSecret("s3cr3t");
953- userInteraction[SSOUI_KEY_QUERYUSERNAME] = true;
954- userInteraction[SSOUI_KEY_USERNAME] = "";
955- userInteraction[SSOUI_KEY_QUERYPASSWORD] = true;
956 QTest::newRow("empty username") <<
957 sessionData.toMap() <<
958 -1 <<
959@@ -440,9 +402,8 @@
960 " \"extra\": {}\n"
961 "}") <<
962 -1 <<
963- response.toMap() << stored.toMap() << userInteraction;
964+ response.toMap() << stored.toMap();
965 sessionData = UbuntuOne::PluginData();
966- userInteraction.clear();
967
968 // Network error while creating token
969 sessionData.setTokenName("helloworld");
970@@ -453,14 +414,13 @@
971 int(QNetworkReply::SslHandshakeFailedError) <<
972 -1 << QString() <<
973 int(SignOn::Error::Ssl) <<
974- response.toMap() << stored.toMap() << userInteraction;
975+ response.toMap() << stored.toMap();
976 sessionData = UbuntuOne::PluginData();
977
978 // Account needs reset
979 sessionData.setTokenName("helloworld");
980 sessionData.setUserName("jim@example.com");
981 sessionData.setSecret("s3cr3t");
982- userInteraction[SSOUI_KEY_OPENURL] = "http://www.example.com/reset";
983 QTest::newRow("reset needed") <<
984 sessionData.toMap() <<
985 -1 <<
986@@ -472,9 +432,8 @@
987 " }\n"
988 "}") <<
989 -1 <<
990- response.toMap() << stored.toMap() << userInteraction;
991+ response.toMap() << stored.toMap();
992 sessionData = UbuntuOne::PluginData();
993- userInteraction.clear();
994 }
995
996 void PluginTest::testTokenCreation()
997@@ -486,7 +445,6 @@
998 QFETCH(int, expectedErrorCode);
999 QFETCH(QVariantMap, expectedResponse);
1000 QFETCH(QVariantMap, expectedStore);
1001- QFETCH(QVariantMap, expectedUserInteraction);
1002
1003 QSignalSpy result(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)));
1004 QSignalSpy error(m_testPlugin, SIGNAL(error(const SignOn::Error &)));
1005@@ -510,16 +468,7 @@
1006
1007 m_testPlugin->process(sessionData, "ubuntuone");
1008 if (expectedErrorCode < 0) {
1009- if (!expectedUserInteraction.isEmpty()) {
1010- QTRY_COMPARE(userActionRequired.count(), 1);
1011- QVariantMap data =
1012- userActionRequired.at(0).at(0).value<UiSessionData>().toMap();
1013- /* We don't care about the title here */
1014- data.remove(SSOUI_KEY_TITLE);
1015- QCOMPARE(data, expectedUserInteraction);
1016- } else {
1017- QCOMPARE(userActionRequired.count(), 0);
1018- }
1019+ QCOMPARE(userActionRequired.count(), 0);
1020
1021 if (!expectedResponse.isEmpty()) {
1022 QTRY_COMPARE(result.count(), 1);
1023
1024=== modified file 'signon-plugin/ubuntuone-plugin.cpp'
1025--- signon-plugin/ubuntuone-plugin.cpp 2016-04-27 14:07:35 +0000
1026+++ signon-plugin/ubuntuone-plugin.cpp 2016-06-07 18:42:38 +0000
1027@@ -69,71 +69,22 @@
1028 {
1029 }
1030
1031- bool SignOnPlugin::validateInput(const PluginData &data,
1032- const QString &mechanism)
1033- {
1034- Q_UNUSED(mechanism);
1035-
1036- if (data.TokenName().isEmpty()) {
1037- return false;
1038- }
1039-
1040- return true;
1041- }
1042-
1043- bool SignOnPlugin::respondWithStoredData()
1044+ void SignOnPlugin::respondWithStoredData()
1045 {
1046 QVariantMap storedData = m_data.StoredData();
1047
1048- /* When U1 was using the password plugin, it was storing the token data
1049- * in the password field. So, if we don't have any data stored in the
1050- * plugin's data, try to get a token from the password field.
1051- */
1052+ /* If there's a secret stored in password field, clear it. */
1053 if (storedData.isEmpty() && !m_data.Secret().isEmpty()) {
1054- Token *token = Token::fromQuery(m_data.Secret());
1055- if (token->isValid()) {
1056- PluginData tokenData;
1057- tokenData.setConsumerKey(token->consumerKey());
1058- tokenData.setConsumerSecret(token->consumerSecret());
1059- tokenData.setTokenKey(token->tokenKey());
1060- tokenData.setTokenSecret(token->tokenSecret());
1061- QDateTime time = token->updated();
1062- if (time.isValid()) {
1063- tokenData.setDateUpdated(time.toString(Qt::ISODate));
1064- }
1065- time = token->created();
1066- if (time.isValid()) {
1067- tokenData.setDateCreated(time.toString(Qt::ISODate));
1068- }
1069- storedData[token->name()] = tokenData.toMap();
1070- PluginData pluginData;
1071- pluginData.setStoredData(storedData);
1072- Q_EMIT store(pluginData);
1073-
1074- /* We know that the given secret is a valid token, so it cannot
1075- * be a valid password as well: let's clear it out now, so that
1076- * if it turns out that the token is no longer valid and that
1077- * we need to create a new one, we won't make a useless attempt
1078- * to create one with a wrong password.
1079- */
1080- m_data.setSecret(QString());
1081- }
1082- delete token;
1083+ m_data.setSecret(QString());
1084 }
1085
1086+ /* Always use the same token name for now */
1087+ m_data.setTokenName(Token::buildTokenName());
1088+
1089 /* Check if we have stored data for this token name */
1090 PluginData tokenData(storedData[m_data.TokenName()].toMap());
1091- Token token(tokenData.TokenKey(), tokenData.TokenSecret(),
1092- tokenData.ConsumerKey(), tokenData.ConsumerSecret(),
1093- tokenData.DateCreated(), tokenData.DateUpdated());
1094- if (!token.isValid()) {
1095- return false;
1096- }
1097- qDebug() << "Token is valid!" << tokenData.TokenKey();
1098-
1099 tokenData.setTokenName(m_data.TokenName());
1100 Q_EMIT result(tokenData);
1101- return true;
1102 }
1103
1104 void SignOnPlugin::emitErrorFromReply(QNetworkReply *reply)
1105@@ -167,21 +118,18 @@
1106 PluginData response;
1107 m_data = inData.data<PluginData>();
1108
1109- if (!validateInput(m_data, mechanism)) {
1110- qWarning() << "Invalid parameters passed";
1111- Q_EMIT error(SignOn::Error(SignOn::Error::MissingData));
1112- return;
1113- }
1114-
1115- /* It may be that the stored token is valid; however, do the check only
1116- * if no OTP was provided (since the presence of an OTP is a clear
1117- * signal that the caller wants to get a new token). */
1118- if (m_data.OneTimePassword().isEmpty() &&
1119- respondWithStoredData()) {
1120- return;
1121- }
1122-
1123- getCredentialsAndCreateNewToken();
1124+ if (m_data.InvalidateToken()) {
1125+ qDebug() << "Clearing stored token";
1126+ PluginData pluginData;
1127+ pluginData.setStoredData(QVariantMap());
1128+ Q_EMIT store(pluginData);
1129+ m_data.setStoredData(QVariantMap());
1130+ respondWithStoredData();
1131+ } else if (!m_data.StoredData().isEmpty() && m_data.Secret().isEmpty()) {
1132+ respondWithStoredData();
1133+ } else {
1134+ createNewToken();
1135+ }
1136 }
1137
1138 void SignOnPlugin::onCreationFinished()
1139@@ -195,8 +143,6 @@
1140 QJsonDocument json = QJsonDocument::fromJson(data);
1141 QJsonObject object = json.object();
1142
1143- QString error = object.value("code").toString();
1144-
1145 int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
1146 qDebug() << "Status code:" << statusCode;
1147 if (statusCode == 200 || statusCode == 201) {
1148@@ -208,6 +154,7 @@
1149 token.setTokenSecret(object.value("token_secret").toString());
1150 token.setDateCreated(Token::dateStringToISO(object.value("date_created").toString()));
1151 token.setDateUpdated(Token::dateStringToISO(object.value("date_updated").toString()));
1152+ token.setTokenName(tokenName);
1153
1154 /* Store the token */
1155 QVariantMap storedData;
1156@@ -216,29 +163,23 @@
1157 pluginData.setStoredData(storedData);
1158 Q_EMIT store(pluginData);
1159
1160- token.setTokenName(tokenName);
1161 Q_EMIT result(token);
1162- } else if (statusCode == 401 && error == ERR_INVALID_CREDENTIALS) {
1163- m_data.setSecret(QString());
1164- m_data.setOneTimePassword(QString());
1165- getCredentialsAndCreateNewToken();
1166- } else if (statusCode == 401 && error == ERR_TWOFACTOR_REQUIRED) {
1167- m_needsOtp = true;
1168- getCredentialsAndCreateNewToken();
1169- } else if (statusCode == 403 && error == ERR_TWOFACTOR_FAILURE) {
1170- m_data.setOneTimePassword(QString());
1171- getCredentialsAndCreateNewToken();
1172- } else if (statusCode == 403 && error == ERR_PASSWORD_POLICY_ERROR) {
1173- QVariantMap data;
1174- QJsonObject extra = object.value("extra").toObject();
1175- data[SSOUI_KEY_OPENURL] = extra.value("location").toString();
1176- Q_EMIT userActionRequired(data);
1177- } else if (error == ERR_INVALID_DATA) {
1178- // This error is received when the email address is invalid
1179- m_data.setUserName(QString());
1180- m_data.setSecret(QString());
1181- m_data.setOneTimePassword(QString());
1182- getCredentialsAndCreateNewToken();
1183+ } else if (statusCode == 401 || statusCode == 403) {
1184+ QString error = object.value("code").toString();
1185+ QString message = object.value("message").toString();
1186+
1187+ PluginData errorData;
1188+ if (error == ERR_TWOFACTOR_REQUIRED) {
1189+ errorData.setU1ErrorCode(PluginData::OneTimePasswordRequired);
1190+ } else {
1191+ errorData.setU1ErrorCode(PluginData::InvalidPassword);
1192+ }
1193+ errorData.setU1ErrorMessage(message);
1194+
1195+ // Emit a result with error data since this seems to be the
1196+ // only feasible way to get error messages from server back up
1197+ // to the UI.
1198+ Q_EMIT result(errorData);
1199 } else {
1200 emitErrorFromReply(reply);
1201 }
1202@@ -253,7 +194,7 @@
1203 QJsonObject formData;
1204 formData.insert("email", m_data.UserName());
1205 formData.insert("password", m_data.Secret());
1206- formData.insert("token_name", m_data.TokenName());
1207+ formData.insert("token_name", Token::buildTokenName());
1208 if (!m_data.OneTimePassword().isEmpty()) {
1209 formData.insert("otp", m_data.OneTimePassword());
1210 }
1211@@ -265,94 +206,5 @@
1212 this, SLOT(onCreationFinished()));
1213 }
1214
1215- void SignOnPlugin::getCredentialsAndCreateNewToken()
1216- {
1217- if (!m_data.Secret().isEmpty() &&
1218- (!m_needsOtp || !m_data.OneTimePassword().isEmpty())) {
1219- createNewToken();
1220- } else if (m_data.Secret().isEmpty()) {
1221- QVariantMap data;
1222- data[SSOUI_KEY_TITLE] =
1223- QString::fromUtf8(_("Sign in to your Ubuntu One account"));
1224- if (m_data.UserName().isEmpty()) {
1225- data[SSOUI_KEY_QUERYUSERNAME] = true;
1226- }
1227- data[SSOUI_KEY_USERNAME] = m_data.UserName();
1228- data[SSOUI_KEY_QUERYPASSWORD] = true;
1229- m_didAskForPassword = true;
1230- Q_EMIT userActionRequired(data);
1231- } else {
1232- QVariantMap data;
1233- data[SSOUI_KEY_TITLE] =
1234- QString::fromUtf8(_("Sign in to your Ubuntu One account"));
1235- data[SSOUI_KEY_USERNAME] = m_data.UserName();
1236- data[SSOUI_KEY_PASSWORD] = m_data.Secret();
1237- data[SSOUI_KEY_QUERY2FA] = true;
1238- data[SSOUI_KEY_2FA_TEXT] =
1239- QString::fromUtf8(_("2-factor device code"));
1240- Q_EMIT userActionRequired(data);
1241- }
1242- }
1243-
1244- bool SignOnPlugin::handleUiError(const SignOn::UiSessionData &data)
1245- {
1246- using namespace SignOn;
1247-
1248- int code = data.QueryErrorCode();
1249- if (code == QUERY_ERROR_NONE) {
1250- return false;
1251- }
1252-
1253- qDebug() << "userActionFinished with error: " << code;
1254- if (code == QUERY_ERROR_CANCELED) {
1255- Q_EMIT error(Error(Error::SessionCanceled,
1256- QLatin1String("Cancelled by user")));
1257- } else if (code == QUERY_ERROR_NETWORK) {
1258- Q_EMIT error(Error(Error::Network, QLatin1String("Network error")));
1259- } else if (code == QUERY_ERROR_SSL) {
1260- Q_EMIT error(Error(Error::Ssl, QLatin1String("SSL error")));
1261- } else {
1262- QVariantMap map = data.toMap();
1263- if (map.contains(SSOUI_KEY_QUERY2FA)) {
1264- PluginData reply;
1265- reply.setU1ErrorCode(PluginData::OneTimePasswordRequired);
1266- Q_EMIT result(reply);
1267- } else if (map.contains(SSOUI_KEY_QUERYPASSWORD)) {
1268- PluginData reply;
1269- reply.setU1ErrorCode(PluginData::InvalidPassword);
1270- Q_EMIT result(reply);
1271- } else {
1272- Q_EMIT error(Error(Error::UserInteraction,
1273- QString("userActionFinished error: ")
1274- + QString::number(data.QueryErrorCode())));
1275- }
1276- }
1277- return true;
1278- }
1279-
1280- void SignOnPlugin::userActionFinished(const SignOn::UiSessionData &data)
1281- {
1282- if (handleUiError(data)) {
1283- return;
1284- }
1285-
1286- PluginData uiData = data.data<PluginData>();
1287- if (!uiData.UserName().isEmpty()) {
1288- m_data.setUserName(uiData.UserName());
1289- }
1290-
1291- if (!uiData.Secret().isEmpty()) {
1292- m_data.setSecret(uiData.Secret());
1293- }
1294-
1295- QVariantMap map = data.toMap();
1296- QString oneTimePassword = map.value(SSOUI_KEY_2FA).toString();
1297- if (!oneTimePassword.isEmpty()) {
1298- m_data.setOneTimePassword(oneTimePassword);
1299- }
1300-
1301- getCredentialsAndCreateNewToken();
1302- }
1303-
1304 SIGNON_DECL_AUTH_PLUGIN(SignOnPlugin)
1305 } // namespace UbuntuOne
1306
1307=== modified file 'signon-plugin/ubuntuone-plugin.h'
1308--- signon-plugin/ubuntuone-plugin.h 2016-04-26 08:45:29 +0000
1309+++ signon-plugin/ubuntuone-plugin.h 2016-06-07 18:42:38 +0000
1310@@ -51,15 +51,11 @@
1311 void cancel() Q_DECL_OVERRIDE;
1312 void process(const SignOn::SessionData &inData,
1313 const QString &mechanism = 0) Q_DECL_OVERRIDE;
1314- void userActionFinished(const SignOn::UiSessionData &data) Q_DECL_OVERRIDE;
1315
1316 private:
1317- bool validateInput(const PluginData &data, const QString &mechanism);
1318- bool respondWithStoredData();
1319+ void respondWithStoredData();
1320 void emitErrorFromReply(QNetworkReply *reply);
1321 void createNewToken();
1322- void getCredentialsAndCreateNewToken();
1323- bool handleUiError(const SignOn::UiSessionData &data);
1324
1325 private Q_SLOTS:
1326 void onCreationFinished();
1327
1328=== modified file 'signon-plugin/ubuntuonedata.h'
1329--- signon-plugin/ubuntuonedata.h 2016-04-27 08:36:19 +0000
1330+++ signon-plugin/ubuntuonedata.h 2016-06-07 18:42:38 +0000
1331@@ -46,6 +46,10 @@
1332 SIGNON_SESSION_DECLARE_PROPERTY(QString, DateCreated);
1333 SIGNON_SESSION_DECLARE_PROPERTY(QString, DateUpdated);
1334
1335+ // Set this to true if the token returned by the previous
1336+ // authentication is invalid.
1337+ SIGNON_SESSION_DECLARE_PROPERTY(bool, InvalidateToken);
1338+
1339 // Error code
1340 enum ErrorCode {
1341 NoError = 0,
1342@@ -53,6 +57,7 @@
1343 InvalidPassword,
1344 };
1345 SIGNON_SESSION_DECLARE_PROPERTY(int, U1ErrorCode);
1346+ SIGNON_SESSION_DECLARE_PROPERTY(QString, U1ErrorMessage);
1347
1348 // Data which the plugin has stored into signond
1349 SIGNON_SESSION_DECLARE_PROPERTY(QVariantMap, StoredData);

Subscribers

People subscribed via source and target branches

to all changes: