diff -Nru signon-plugin-oauth2-0.21+15.04.20150327/common-vars.pri signon-plugin-oauth2-0.22+15.04.20150417/common-vars.pri --- signon-plugin-oauth2-0.21+15.04.20150327/common-vars.pri 2015-03-27 11:12:46.000000000 +0000 +++ signon-plugin-oauth2-0.22+15.04.20150417/common-vars.pri 2015-04-17 14:56:48.000000000 +0000 @@ -13,7 +13,7 @@ # Project version # remember to update debian/* files if you changes this #----------------------------------------------------------------------------- -PROJECT_VERSION = 0.21 +PROJECT_VERSION = 0.22 #----------------------------------------------------------------------------- # Library version diff -Nru signon-plugin-oauth2-0.21+15.04.20150327/debian/changelog signon-plugin-oauth2-0.22+15.04.20150417/debian/changelog --- signon-plugin-oauth2-0.21+15.04.20150327/debian/changelog 2015-04-17 15:05:14.000000000 +0000 +++ signon-plugin-oauth2-0.22+15.04.20150417/debian/changelog 2015-04-17 15:05:14.000000000 +0000 @@ -1,3 +1,16 @@ +signon-plugin-oauth2 (0.22+15.04.20150417-0ubuntu1) vivid; urgency=medium + + [ Alberto Mardegan ] + * New upstream release + - Return the list of granted permissions to the client + - Require Qt5 for building + - Use a "state" parameter to protect against CSRF (LP: #1432857) + + [ CI Train Bot ] + * New rebuild forced. + + -- CI Train Bot Fri, 17 Apr 2015 14:56:51 +0000 + signon-plugin-oauth2 (0.21+15.04.20150327-0ubuntu1) vivid; urgency=medium * New rebuild forced. diff -Nru signon-plugin-oauth2-0.21+15.04.20150327/src/oauth2data.h signon-plugin-oauth2-0.22+15.04.20150417/src/oauth2data.h --- signon-plugin-oauth2-0.21+15.04.20150327/src/oauth2data.h 2015-03-27 11:12:46.000000000 +0000 +++ signon-plugin-oauth2-0.22+15.04.20150417/src/oauth2data.h 2015-04-17 14:56:48.000000000 +0000 @@ -106,6 +106,10 @@ * Access token expiry time */ SIGNON_SESSION_DECLARE_PROPERTY(int, ExpiresIn); + /*! + * Granted permissions + */ + SIGNON_SESSION_DECLARE_PROPERTY(QStringList, Scope); }; } // namespace OAuth2PluginNS diff -Nru signon-plugin-oauth2-0.21+15.04.20150327/src/oauth2plugin.cpp signon-plugin-oauth2-0.22+15.04.20150417/src/oauth2plugin.cpp --- signon-plugin-oauth2-0.21+15.04.20150327/src/oauth2plugin.cpp 2015-03-27 11:12:52.000000000 +0000 +++ signon-plugin-oauth2-0.22+15.04.20150417/src/oauth2plugin.cpp 2015-04-17 14:56:48.000000000 +0000 @@ -25,18 +25,13 @@ #include "oauth2plugin.h" #include "oauth2tokendata.h" +#include #include +#include #include #include #include -#define USE_LIBQJSON (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) - -#if USE_LIBQJSON -#include -#else -#include -#endif using namespace SignOn; using namespace OAuth2PluginNS; @@ -54,6 +49,7 @@ const QString AUTH_CODE = QString("code"); const QString REDIRECT_URI = QString("redirect_uri"); const QString RESPONSE_TYPE = QString("response_type"); +const QString STATE = QString("state"); const QString USERNAME = QString("username"); const QString PASSWORD = QString("password"); const QString ASSERTION_TYPE = QString("assertion_type"); @@ -61,6 +57,7 @@ const QString ACCESS_TOKEN = QString("access_token"); const QString DISPLAY = QString("display"); const QString EXPIRES_IN = QString("expires_in"); +const QString SCOPE = QString("scope"); const QString TIMESTAMP = QString("timestamp"); const QString GRANT_TYPE = QString("grant_type"); const QString AUTHORIZATION_CODE = QString("authorization_code"); @@ -96,6 +93,7 @@ QString m_mechanism; OAuth2PluginData m_oauth2Data; QVariantMap m_tokens; + QString m_state; QString m_key; QString m_username; QString m_password; @@ -133,6 +131,8 @@ QUrl url(QString("https://%1/%2").arg(d->m_oauth2Data.Host()).arg(d->m_oauth2Data.AuthPath())); url.addQueryItem(CLIENT_ID, d->m_oauth2Data.ClientId()); url.addQueryItem(REDIRECT_URI, d->m_oauth2Data.RedirectUri()); + d->m_state = QString::number(qrand()); + url.addQueryItem(STATE, d->m_state); if (!d->m_oauth2Data.ResponseType().isEmpty()) { url.addQueryItem(RESPONSE_TYPE, d->m_oauth2Data.ResponseType().join(" ")); @@ -153,7 +153,7 @@ } // Passing list of scopes - url.addQueryItem(QString("scope"), d->m_oauth2Data.Scope().join(separator)); + url.addQueryItem(SCOPE, d->m_oauth2Data.Scope().join(separator)); } TRACE() << "Url = " << url.toString(); SignOn::UiSessionData uiSession; @@ -360,21 +360,30 @@ if (d->m_mechanism == USER_AGENT) { // Response should contain the access token OAuth2PluginTokenData respData; - QString fragment; if (url.hasFragment()) { - fragment = url.fragment(); - QStringList list = fragment.split(QRegExp("&|="), QString::SkipEmptyParts); - for (int i = 1; i < list.count(); i += 2) { - if (list.at(i - 1) == ACCESS_TOKEN) { - respData.setAccessToken(list.at(i)); - } - else if (list.at(i - 1) == EXPIRES_IN) { - respData.setExpiresIn(QString(list.at(i)).toInt()); - } - else if (list.at(i - 1) == REFRESH_TOKEN) { - respData.setRefreshToken(list.at(i)); + QString state; + respData.setScope(d->m_oauth2Data.Scope()); + QUrlQuery fragment(url.fragment()); + typedef QPair StringPair; + Q_FOREACH(const StringPair &pair, fragment.queryItems()) { + if (pair.first == ACCESS_TOKEN) { + respData.setAccessToken(pair.second); + } else if (pair.first == EXPIRES_IN) { + respData.setExpiresIn(pair.second.toInt()); + } else if (pair.first == REFRESH_TOKEN) { + respData.setRefreshToken(pair.second); + } else if (pair.first == STATE) { + state = pair.second; + } else if (pair.first == SCOPE) { + respData.setScope(pair.second.split(' ', QString::SkipEmptyParts)); } } + if (state != d->m_state) { + Q_EMIT error(Error(Error::NotAuthorized, + QString("'state' parameter mismatch"))); + return; + } + if (respData.AccessToken().isEmpty()) { emit error(Error(Error::NotAuthorized, QString("Access token not present"))); } else { @@ -394,6 +403,11 @@ // 4. Refresh Token (refresh_token) QUrl newUrl; if (url.hasQueryItem(AUTH_CODE)) { + if (d->m_state != url.queryItemValue(STATE)) { + Q_EMIT error(Error(Error::NotAuthorized, + QString("'state' parameter mismatch"))); + return; + } QString code = url.queryItemValue(AUTH_CODE); newUrl.addQueryItem(GRANT_TYPE, AUTHORIZATION_CODE); newUrl.addQueryItem(AUTH_CODE, code); @@ -473,6 +487,8 @@ // Method to handle responses for OAuth 2.0 requests void OAuth2Plugin::serverReply(QNetworkReply *reply) { + Q_D(OAuth2Plugin); + QByteArray replyContent = reply->readAll(); TRACE() << replyContent; @@ -499,6 +515,14 @@ } QByteArray refreshToken = map["refresh_token"].toByteArray(); + QStringList scope; + if (map.contains(SCOPE)) { + QString rawScope = QString::fromUtf8(map[SCOPE].toByteArray()); + scope = rawScope.split(' ', QString::SkipEmptyParts); + } else { + scope = d->m_oauth2Data.Scope(); + } + if (accessToken.isEmpty()) { TRACE()<< "Access token is empty"; Q_EMIT error(Error(Error::NotAuthorized, @@ -508,6 +532,7 @@ response.setAccessToken(accessToken); response.setRefreshToken(refreshToken); response.setExpiresIn(expiresIn); + response.setScope(scope); storeResponse(response); emit result(response); } @@ -676,15 +701,9 @@ QVariantMap OAuth2Plugin::parseJSONReply(const QByteArray &reply) { TRACE(); - bool ok = false; -#if USE_LIBQJSON - QJson::Parser parser; - QVariant tree = parser.parse(reply, &ok); -#else QJsonDocument doc = QJsonDocument::fromJson(reply); - ok = !doc.isEmpty(); + bool ok = !doc.isEmpty(); QVariant tree = doc.toVariant(); -#endif if (ok) { return tree.toMap(); } diff -Nru signon-plugin-oauth2-0.21+15.04.20150327/src/src.pro signon-plugin-oauth2-0.22+15.04.20150417/src/src.pro --- signon-plugin-oauth2-0.21+15.04.20150327/src/src.pro 2015-03-27 11:12:46.000000000 +0000 +++ signon-plugin-oauth2-0.22+15.04.20150417/src/src.pro 2015-04-17 14:56:48.000000000 +0000 @@ -27,17 +27,9 @@ oauth2plugin.cpp \ plugin.cpp PKGCONFIG += \ + libsignon-qt5 \ signon-plugins -lessThan(QT_MAJOR_VERSION, 5) { - PKGCONFIG += \ - QJson \ - libsignon-qt -} else { - PKGCONFIG += \ - libsignon-qt5 -} - headers.files = $$public_headers pkgconfig.files = signon-oauth2plugin.pc include( ../common-installs-config.pri ) diff -Nru signon-plugin-oauth2-0.21+15.04.20150327/tests/oauth2plugintest.cpp signon-plugin-oauth2-0.22+15.04.20150417/tests/oauth2plugintest.cpp --- signon-plugin-oauth2-0.21+15.04.20150327/tests/oauth2plugintest.cpp 2015-03-27 11:12:52.000000000 +0000 +++ signon-plugin-oauth2-0.22+15.04.20150417/tests/oauth2plugintest.cpp 2015-04-17 14:56:48.000000000 +0000 @@ -21,10 +21,13 @@ * 02110-1301 USA */ +#include +#include #include #include #include #include +#include #include #include @@ -38,6 +41,22 @@ using namespace OAuth2PluginNS; using namespace SignOn; +namespace QTest { +template<> +char *toString(const QVariantMap &map) +{ + QJsonDocument doc(QJsonObject::fromVariantMap(map)); + return qstrdup(doc.toJson(QJsonDocument::Compact).data()); +} +} // QTest namespace + +static QString parseState(const QSignalSpy &userActionRequired) +{ + UiSessionData data = userActionRequired.at(0).at(0).value(); + QUrlQuery query(data.OpenUrl()); + return query.queryItemValue("state"); +} + static bool mapIsSubset(const QVariantMap &set, const QVariantMap &test) { QMapIterator it(set); @@ -190,10 +209,6 @@ void OAuth2PluginTest::init() { m_testPlugin = new Plugin(); - m_stored = SignOn::SessionData(); - m_response = SignOn::SessionData(); - m_uiResponse = SignOn::UiSessionData(); - m_error = SignOn::Error(-1); } //finnish each test by deleting plugin @@ -203,43 +218,6 @@ m_testPlugin=NULL; } -//slot for receiving result -void OAuth2PluginTest::result(const SignOn::SessionData& data) -{ - m_response = data; - m_loop.exit(); -} - -//slot for receiving error -void OAuth2PluginTest::pluginError(const SignOn::Error &err) -{ - m_error = err; - m_loop.exit(); -} - -//slot for receiving result -void OAuth2PluginTest::uiRequest(const SignOn::UiSessionData& data) -{ - Q_UNUSED(data); - m_uiResponse.setUrlResponse(QString("UI request received")); - m_loop.exit(); -} - -//slot for store -void OAuth2PluginTest::store(const SignOn::SessionData &data) -{ - m_stored = data; -} - -void OAuth2PluginTest::aborted(QNetworkReply* reply) -{ - qDebug() << "aborted"; - //we should get error code if request was aborted - qDebug() << reply->error(); - QVERIFY(reply->error()); - m_loop.exit(); -} - // TEST CASES void OAuth2PluginTest::testPlugin() { @@ -261,15 +239,11 @@ void OAuth2PluginTest::testPluginCancel() { - QTimer::singleShot(10*1000, &m_loop, SLOT(quit())); - //does nothing as no active connections m_testPlugin->cancel(); //then real cancel - QObject::connect(m_testPlugin, SIGNAL(error(const SignOn::Error &)), - this, SLOT(pluginError(const SignOn::Error &)), - Qt::QueuedConnection); + QSignalSpy pluginError(m_testPlugin, SIGNAL(error(const SignOn::Error &))); OAuth2PluginData userAgentData; userAgentData.setHost("https://localhost"); @@ -280,8 +254,9 @@ m_testPlugin->process(userAgentData, QString("user_agent")); m_testPlugin->cancel(); - m_loop.exec(); - QCOMPARE(m_error.type(), int(Error::SessionCanceled)); + QTRY_COMPARE(pluginError.count(), 1); + Error error = pluginError.at(0).at(0).value(); + QCOMPARE(error.type(), int(Error::SessionCanceled)); } void OAuth2PluginTest::testPluginProcess_data() @@ -289,7 +264,7 @@ QTest::addColumn("mechanism"); QTest::addColumn("sessionData"); QTest::addColumn("errorCode"); - QTest::addColumn("urlResponse"); + QTest::addColumn("uiExpected"); QTest::addColumn("response"); QTest::addColumn("stored"); @@ -304,13 +279,13 @@ "ANONYMOUS" << userAgentData.toMap() << int(Error::MechanismNotAvailable) << - QString() << QVariantMap() << QVariantMap(); + false << QVariantMap() << QVariantMap(); QTest::newRow("without params, user_agent") << "user_agent" << userAgentData.toMap() << int(Error::MissingData) << - QString() << QVariantMap() << QVariantMap(); + false << QVariantMap() << QVariantMap(); OAuth2PluginData webServerData; webServerData.setHost("https://localhost"); @@ -324,21 +299,21 @@ "web_server" << webServerData.toMap() << int(Error::MissingData) << - QString() << QVariantMap() << QVariantMap(); + false << QVariantMap() << QVariantMap(); userAgentData.setAuthPath("authorize"); QTest::newRow("ui-request, user_agent") << "user_agent" << userAgentData.toMap() << -1 << - QString("UI request received") << QVariantMap() << QVariantMap(); + true << QVariantMap() << QVariantMap(); webServerData.setTokenPath("token"); QTest::newRow("ui-request, web_server") << "web_server" << webServerData.toMap() << -1 << - QString("UI request received") << QVariantMap() << QVariantMap(); + true << QVariantMap() << QVariantMap(); QVariantMap tokens; QVariantMap token; @@ -353,7 +328,7 @@ "web_server" << webServerData.toMap() << -1 << - QString("UI request received") << QVariantMap() << QVariantMap(); + true << QVariantMap() << QVariantMap(); tokens.insert(webServerData.ClientId(), QVariant::fromValue(token)); webServerData.m_data.insert(QLatin1String("Tokens"), tokens); @@ -362,7 +337,7 @@ "web_server" << webServerData.toMap() << -1 << - QString("UI request received") << QVariantMap() << QVariantMap(); + true << QVariantMap() << QVariantMap(); token.insert("Scopes", QStringList("scope2")); tokens.insert(webServerData.ClientId(), QVariant::fromValue(token)); @@ -372,7 +347,7 @@ "web_server" << webServerData.toMap() << -1 << - QString("UI request received") << QVariantMap() << QVariantMap(); + true << QVariantMap() << QVariantMap(); token.insert("Scopes", QStringList() << "scope1" << "scope3" << "scope2"); @@ -386,14 +361,14 @@ "web_server" << webServerData.toMap() << -1 << - QString() << response << QVariantMap(); + false << response << QVariantMap(); webServerData.setForceTokenRefresh(true); QTest::newRow("force token refresh, without refresh token") << "web_server" << webServerData.toMap() << -1 << - QString("UI request received") << QVariantMap() << QVariantMap(); + true << QVariantMap() << QVariantMap(); /* test the ProvidedTokens semantics */ OAuth2PluginData providedTokensWebServerData; @@ -422,7 +397,7 @@ "web_server" << providedTokensWebServerData.toMap() << -1 << - QString() << providedTokens << stored; + false << providedTokens << stored; } void OAuth2PluginTest::testPluginProcess() @@ -430,27 +405,35 @@ QFETCH(QString, mechanism); QFETCH(QVariantMap, sessionData); QFETCH(int, errorCode); - QFETCH(QString, urlResponse); + QFETCH(bool, uiExpected); QFETCH(QVariantMap, response); QFETCH(QVariantMap, stored); - QObject::connect(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)), - this, SLOT(result(const SignOn::SessionData&)),Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(error(const SignOn::Error & )), - this, SLOT(pluginError(const SignOn::Error &)),Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(userActionRequired(const SignOn::UiSessionData&)), - this, SLOT(uiRequest(const SignOn::UiSessionData&)),Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(store(const SignOn::SessionData&)), - this, SLOT(store(const SignOn::SessionData&)),Qt::QueuedConnection); - QTimer::singleShot(10*1000, &m_loop, SLOT(quit())); + QSignalSpy result(m_testPlugin, SIGNAL(result(const SignOn::SessionData&))); + QSignalSpy error(m_testPlugin, SIGNAL(error(const SignOn::Error &))); + QSignalSpy userActionRequired(m_testPlugin, + SIGNAL(userActionRequired(const SignOn::UiSessionData&))); + QSignalSpy store(m_testPlugin, SIGNAL(store(const SignOn::SessionData&))); m_testPlugin->process(sessionData, mechanism); - m_loop.exec(); - QCOMPARE(m_error.type(), errorCode); if (errorCode < 0) { - QCOMPARE(m_uiResponse.UrlResponse(), urlResponse); - QCOMPARE(m_response.toMap(), response); - QVERIFY(mapIsSubset(stored, m_stored.toMap())); + QCOMPARE(error.count(), 0); + QTRY_COMPARE(userActionRequired.count(), uiExpected ? 1 : 0); + if (!response.isEmpty()) { + QCOMPARE(result.count(), 1); + QVariantMap resp = result.at(0).at(0).value().toMap(); + QCOMPARE(resp, response); + } + if (!stored.isEmpty()) { + QCOMPARE(store.count(), 1); + QVariantMap storedData = + store.at(0).at(0).value().toMap(); + QVERIFY(mapIsSubset(stored, storedData)); + } + } else { + QTRY_COMPARE(error.count(), 1); + Error err = error.at(0).at(0).value(); + QCOMPARE(err.type(), errorCode); } } @@ -462,7 +445,7 @@ QTest::addColumn("replyContentType"); QTest::addColumn("replyContents"); QTest::addColumn("errorCode"); - QTest::addColumn("urlResponse"); + QTest::addColumn("uiExpected"); QTest::addColumn("response"); QTest::addColumn("stored"); @@ -480,7 +463,7 @@ hmacSha1Data.toMap() << int(200) << "" << "" << int(Error::MechanismNotAvailable) << - QString() << QVariantMap() << QVariantMap(); + false << QVariantMap() << QVariantMap(); // Try without params hmacSha1Data.setAuthorizationEndpoint(QString()); @@ -489,7 +472,7 @@ hmacSha1Data.toMap() << int(200) << "" << "" << int(Error::MissingData) << - QString() << QVariantMap() << QVariantMap(); + false << QVariantMap() << QVariantMap(); // Check for signon UI request for HMAC-SHA1 hmacSha1Data.setAuthorizationEndpoint("https://localhost/oauth/authorize"); @@ -499,7 +482,7 @@ int(200) << "text/plain" << "oauth_token=HiThere&oauth_token_secret=BigSecret" << -1 << - QString("UI request received") << QVariantMap() << QVariantMap(); + true << QVariantMap() << QVariantMap(); QTest::newRow("ui-request, PLAINTEXT") << "PLAINTEXT" << @@ -507,7 +490,7 @@ int(200) << "text/plain" << "oauth_token=HiThere&oauth_token_secret=BigSecret" << -1 << - QString("UI request received") << QVariantMap() << QVariantMap(); + true << QVariantMap() << QVariantMap(); /* Now store some tokens and test the responses */ hmacSha1Data.m_data.insert("UiPolicy", NoUserInteractionPolicy); @@ -527,7 +510,7 @@ int(200) << "text/plain" << "oauth_token=HiThere&oauth_token_secret=BigSecret" << -1 << - QString("UI request received") << QVariantMap() << QVariantMap(); + true << QVariantMap() << QVariantMap(); // Ensure that the cached token is returned as required tokens.insert(hmacSha1Data.ConsumerKey(), QVariant::fromValue(token)); @@ -539,7 +522,7 @@ hmacSha1Data.toMap() << int(200) << "" << "" << -1 << - QString() << response << QVariantMap(); + false << response << QVariantMap(); hmacSha1Data.m_data.insert("UiPolicy", RequestPasswordPolicy); QTest::newRow("cached tokens, request password policy") << @@ -548,7 +531,7 @@ int(200) << "text/plain" << "oauth_token=HiThere&oauth_token_secret=BigSecret" << -1 << - QString("UI request received") << QVariantMap() << QVariantMap(); + true << QVariantMap() << QVariantMap(); hmacSha1Data.m_data.remove("UiPolicy"); hmacSha1Data.setForceTokenRefresh(true); @@ -558,7 +541,7 @@ int(200) << "text/plain" << "oauth_token=HiThere&oauth_token_secret=BigSecret" << -1 << - QString("UI request received") << QVariantMap() << QVariantMap(); + true << QVariantMap() << QVariantMap(); hmacSha1Data.setForceTokenRefresh(false); token.insert("timestamp", QDateTime::currentDateTime().toTime_t() - 50000); @@ -571,7 +554,7 @@ int(200) << "text/plain" << "oauth_token=HiThere&oauth_token_secret=BigSecret" << -1 << - QString("UI request received") << QVariantMap() << QVariantMap(); + true << QVariantMap() << QVariantMap(); /* test the ProvidedTokens semantics */ OAuth1PluginData providedTokensHmacSha1Data; @@ -601,7 +584,7 @@ providedTokensHmacSha1Data.toMap() << int(200) << "" << "" << -1 << - QString() << providedTokens << stored; + false << providedTokens << stored; QTest::newRow("http error 401") << "HMAC-SHA1" << @@ -609,14 +592,14 @@ int(401) << "text/plain" << "oauth_token=HiThere&oauth_token_secret=BigSecret" << int(Error::OperationFailed) << - QString() << QVariantMap() << QVariantMap(); + false << QVariantMap() << QVariantMap(); QTest::newRow("no content returned") << "HMAC-SHA1" << hmacSha1Data.toMap() << int(200) << "" << "" << int(Error::OperationFailed) << - QString() << QVariantMap() << QVariantMap(); + false << QVariantMap() << QVariantMap(); QTest::newRow("no token returned") << "HMAC-SHA1" << @@ -624,7 +607,7 @@ int(200) << "text/plain" << "oauth_token=HiThere" << int(Error::OperationFailed) << - QString() << QVariantMap() << QVariantMap(); + false << QVariantMap() << QVariantMap(); /* Test handling of oauth_problem; this is a non standard extension: * http://wiki.oauth.net/w/page/12238543/ProblemReporting @@ -636,21 +619,21 @@ int(400) << "text/plain" << "oauth_problem=user_refused" << int(Error::PermissionDenied) << - QString() << QVariantMap() << QVariantMap(); + false << QVariantMap() << QVariantMap(); QTest::newRow("problem permission_denied") << "HMAC-SHA1" << hmacSha1Data.toMap() << int(400) << "text/plain" << "oauth_problem=permission_denied" << int(Error::PermissionDenied) << - QString() << QVariantMap() << QVariantMap(); + false << QVariantMap() << QVariantMap(); QTest::newRow("problem signature_invalid") << "HMAC-SHA1" << hmacSha1Data.toMap() << int(400) << "text/plain" << "oauth_problem=signature_invalid" << int(Error::OperationFailed) << - QString() << QVariantMap() << QVariantMap(); + false << QVariantMap() << QVariantMap(); } void OAuth2PluginTest::testPluginHmacSha1Process() @@ -661,19 +644,15 @@ QFETCH(QString, replyContentType); QFETCH(QString, replyContents); QFETCH(int, errorCode); - QFETCH(QString, urlResponse); + QFETCH(bool, uiExpected); QFETCH(QVariantMap, response); QFETCH(QVariantMap, stored); - QObject::connect(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)), - this, SLOT(result(const SignOn::SessionData&)),Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(error(const SignOn::Error & )), - this, SLOT(pluginError(const SignOn::Error &)),Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(userActionRequired(const SignOn::UiSessionData&)), - this, SLOT(uiRequest(const SignOn::UiSessionData&)),Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(store(const SignOn::SessionData&)), - this, SLOT(store(const SignOn::SessionData&)),Qt::QueuedConnection); - QTimer::singleShot(10*1000, &m_loop, SLOT(quit())); + QSignalSpy result(m_testPlugin, SIGNAL(result(const SignOn::SessionData&))); + QSignalSpy error(m_testPlugin, SIGNAL(error(const SignOn::Error &))); + QSignalSpy userActionRequired(m_testPlugin, + SIGNAL(userActionRequired(const SignOn::UiSessionData&))); + QSignalSpy store(m_testPlugin, SIGNAL(store(const SignOn::SessionData&))); TestNetworkAccessManager *nam = new TestNetworkAccessManager; m_testPlugin->m_networkAccessManager = nam; @@ -686,13 +665,25 @@ nam->setNextReply(reply); m_testPlugin->process(sessionData, mechanism); - m_loop.exec(); - QCOMPARE(m_error.type(), errorCode); + + QTRY_COMPARE(result.count(), response.isEmpty() ? 0 : 1); + /* In the test data sometimes we don't specify the expected stored data, + * but this doesn't mean that store() shouldn't be emitted. */ + if (!stored.isEmpty()) { QTRY_COMPARE(store.count(), 1); } + QTRY_COMPARE(userActionRequired.count(), uiExpected ? 1 : 0); + QTRY_COMPARE(error.count(), errorCode < 0 ? 0 : 1); + if (errorCode < 0) { + QCOMPARE(error.count(), 0); + + QVariantMap resp = result.count() > 0 ? + result.at(0).at(0).value().toMap() : QVariantMap(); + QVariantMap storedData = store.count() > 0 ? + store.at(0).at(0).value().toMap() : QVariantMap(); /* We don't check the network request if a response was received, * because a response can only be received if a cached token was * found -- and that doesn't cause any network request to be made. */ - if (m_response.toMap().isEmpty()) { + if (resp.isEmpty()) { QCOMPARE(nam->m_lastRequest.url(), sessionData.value("RequestEndpoint").toUrl()); QVERIFY(nam->m_lastRequestData.isEmpty()); @@ -712,9 +703,11 @@ QCOMPARE(authMap.value("oauth_signature_method").toString(), mechanism); } - QCOMPARE(m_uiResponse.UrlResponse(), urlResponse); - QVERIFY(mapIsSubset(response, m_response.toMap())); - QVERIFY(mapIsSubset(stored, m_stored.toMap())); + QVERIFY(mapIsSubset(response, resp)); + QVERIFY(mapIsSubset(stored, storedData)); + } else { + Error err = error.at(0).at(0).value(); + QCOMPARE(err.type(), errorCode); } } @@ -731,72 +724,108 @@ QStringList scopes = QStringList() << "scope1" << "scope2"; data.setScope(scopes); - QObject::connect(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)), - this, SLOT(result(const SignOn::SessionData&)),Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(error(const SignOn::Error & )), - this, SLOT(pluginError(const SignOn::Error &)),Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(userActionRequired(const SignOn::UiSessionData&)), - this, SLOT(uiRequest(const SignOn::UiSessionData&)),Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(store(const SignOn::SessionData&)), - this, SLOT(store(const SignOn::SessionData&)), - Qt::QueuedConnection); - QTimer::singleShot(10*1000, &m_loop, SLOT(quit())); + QSignalSpy resultSpy(m_testPlugin, SIGNAL(result(const SignOn::SessionData&))); + QSignalSpy error(m_testPlugin, SIGNAL(error(const SignOn::Error &))); + QSignalSpy userActionRequired(m_testPlugin, + SIGNAL(userActionRequired(const SignOn::UiSessionData&))); + QSignalSpy store(m_testPlugin, SIGNAL(store(const SignOn::SessionData&))); m_testPlugin->process(data, QString("user_agent")); - m_loop.exec(); - QCOMPARE(m_uiResponse.UrlResponse(), QString("UI request received")); + + QTRY_COMPARE(userActionRequired.count(), 1); + QString state = parseState(userActionRequired); //empty data m_testPlugin->userActionFinished(info); - m_loop.exec(); - QCOMPARE(m_error.type(), int(Error::NotAuthorized)); + QTRY_COMPARE(error.count(), 1); + QCOMPARE(error.at(0).at(0).value().type(), int(Error::NotAuthorized)); + error.clear(); //invalid data info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html#access_token=&expires_in=4776")); m_testPlugin->userActionFinished(info); - m_loop.exec(); - QCOMPARE(m_error.type(), int(Error::NotAuthorized)); + QTRY_COMPARE(error.count(), 1); + QCOMPARE(error.at(0).at(0).value().type(), int(Error::NotAuthorized)); + error.clear(); //Invalid data info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html")); m_testPlugin->userActionFinished(info); - m_loop.exec(); - QCOMPARE(m_error.type(), int(Error::NotAuthorized)); + QTRY_COMPARE(error.count(), 1); + QCOMPARE(error.at(0).at(0).value().type(), int(Error::NotAuthorized)); + error.clear(); + + // Wrong state + info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html" + "#access_token=123&expires_in=456&state=%1"). + arg(state + "Boo")); + m_testPlugin->userActionFinished(info); + QTRY_COMPARE(error.count(), 1); + QCOMPARE(error.at(0).at(0).value().type(), int(Error::NotAuthorized)); + error.clear(); //valid data - info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html#access_token=testtoken.&expires_in=4776")); + info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html#access_token=testtoken.&expires_in=4776&state=%1"). + arg(state)); m_testPlugin->userActionFinished(info); - m_loop.exec(); - OAuth2PluginTokenData *result = (OAuth2PluginTokenData*)&m_response; - QCOMPARE(result->AccessToken(), QString("testtoken.")); - QCOMPARE(result->ExpiresIn(), 4776); - QVariantMap storedTokenData = m_stored.data().Tokens(); + QTRY_COMPARE(resultSpy.count(), 1); + SessionData response = resultSpy.at(0).at(0).value(); + OAuth2PluginTokenData result = response.data(); + QCOMPARE(result.AccessToken(), QString("testtoken.")); + QCOMPARE(result.ExpiresIn(), 4776); + QCOMPARE(result.Scope(), QStringList() << "scope1" << "scope2"); + resultSpy.clear(); + QTRY_COMPARE(store.count(), 1); + SessionData storedData = store.at(0).at(0).value(); + QVariantMap storedTokenData = storedData.data().Tokens(); QVariantMap storedClientData = storedTokenData.value(data.ClientId()).toMap(); QVERIFY(!storedClientData.isEmpty()); QCOMPARE(storedClientData["Scopes"].toStringList(), scopes); + store.clear(); + + //valid data, got scopes + info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html#access_token=testtoken.&expires_in=4776&state=%1&scope=scope2"). + arg(state)); + m_testPlugin->userActionFinished(info); + QTRY_COMPARE(resultSpy.count(), 1); + response = resultSpy.at(0).at(0).value(); + result = response.data(); + QCOMPARE(result.AccessToken(), QString("testtoken.")); + QCOMPARE(result.ExpiresIn(), 4776); + QCOMPARE(result.Scope(), QStringList() << "scope2"); + resultSpy.clear(); + store.clear(); //valid data - info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html#access_token=testtoken.")); + info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html" + "#state=%1&access_token=testtoken."). + arg(state)); m_testPlugin->userActionFinished(info); - m_loop.exec(); - result = (OAuth2PluginTokenData*)&m_response; - QCOMPARE(result->AccessToken(), QString("testtoken.")); - QCOMPARE(result->ExpiresIn(), 0); + QTRY_COMPARE(resultSpy.count(), 1); + response = resultSpy.at(0).at(0).value(); + result = response.data(); + QCOMPARE(result.AccessToken(), QString("testtoken.")); + QCOMPARE(result.ExpiresIn(), 0); + resultSpy.clear(); /* Check that the expiration time has not been stored, since the expiration * time was not given (https://bugs.launchpad.net/bugs/1316021) */ - storedTokenData = m_stored.data().Tokens(); + QTRY_COMPARE(store.count(), 1); + storedData = store.at(0).at(0).value(); + storedTokenData = storedData.data().Tokens(); storedClientData = storedTokenData.value(data.ClientId()).toMap(); QVERIFY(!storedClientData.isEmpty()); QCOMPARE(storedClientData["Token"].toString(), QString("testtoken.")); QVERIFY(!storedClientData.contains("Expiry")); + store.clear(); //Permission denied info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html?error=user_denied")); m_testPlugin->userActionFinished(info); - m_loop.exec(); - QCOMPARE(m_error.type(), int(Error::NotAuthorized)); + QTRY_COMPARE(error.count(), 1); + QCOMPARE(error.at(0).at(0).value().type(), int(Error::NotAuthorized)); + error.clear(); } void OAuth2PluginTest::testPluginWebserverUserActionFinished_data() @@ -823,7 +852,7 @@ "" << "" << 0 << "" << "" << QVariantMap(); QTest::newRow("permission denied") << - "http://localhost/resp.html?error=user_denied" << + "http://localhost/resp.html?error=user_denied&$state" << int(Error::NotAuthorized) << "" << "" << 0 << "" << "" << QVariantMap(); @@ -833,7 +862,7 @@ "" << "" << 0 << "" << "" << QVariantMap(); QTest::newRow("reply code, http error 401") << - "http://localhost/resp.html?code=c0d3" << + "http://localhost/resp.html?code=c0d3&$state" << int(Error::OperationFailed) << "https://localhost/access_token" << "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" << @@ -843,7 +872,7 @@ QVariantMap(); QTest::newRow("reply code, empty reply") << - "http://localhost/resp.html?code=c0d3" << + "http://localhost/resp.html?code=c0d3&$state" << int(Error::NotAuthorized) << "https://localhost/access_token" << "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" << @@ -853,7 +882,7 @@ QVariantMap(); QTest::newRow("reply code, no access token") << - "http://localhost/resp.html?code=c0d3" << + "http://localhost/resp.html?code=c0d3&$state" << int(Error::NotAuthorized) << "https://localhost/access_token" << "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" << @@ -863,7 +892,7 @@ QVariantMap(); QTest::newRow("reply code, no content type") << - "http://localhost/resp.html?code=c0d3" << + "http://localhost/resp.html?code=c0d3&$state" << int(Error::OperationFailed) << "https://localhost/access_token" << "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" << @@ -873,7 +902,7 @@ QVariantMap(); QTest::newRow("reply code, unsupported content type") << - "http://localhost/resp.html?code=c0d3" << + "http://localhost/resp.html?code=c0d3&$state" << int(Error::OperationFailed) << "https://localhost/access_token" << "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" << @@ -886,8 +915,23 @@ response.insert("AccessToken", "t0k3n"); response.insert("ExpiresIn", int(3600)); response.insert("RefreshToken", QString()); - QTest::newRow("reply code, valid token") << - "http://localhost/resp.html?code=c0d3" << + QTest::newRow("reply code, valid token, wrong state") << + "http://localhost/resp.html?code=c0d3&$wrongstate" << + int(Error::NotAuthorized) << + "" << + "" << + int(200) << + "application/json" << + "{ \"access_token\":\"t0k3n\", \"expires_in\": 3600 }" << + response; + + response.clear(); + response.insert("AccessToken", "t0k3n"); + response.insert("ExpiresIn", int(3600)); + response.insert("RefreshToken", QString()); + response.insert("Scope", QStringList() << "one" << "two" << "three"); + QTest::newRow("reply code, valid token, no scope") << + "http://localhost/resp.html?code=c0d3&$state" << int(-1) << "https://localhost/access_token" << "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" << @@ -897,8 +941,39 @@ response; response.clear(); + response.insert("AccessToken", "t0k3n"); + response.insert("ExpiresIn", int(3600)); + response.insert("RefreshToken", QString()); + response.insert("Scope", QStringList()); + QTest::newRow("reply code, valid token, empty scope") << + "http://localhost/resp.html?code=c0d3&$state" << + int(-1) << + "https://localhost/access_token" << + "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" << + int(200) << + "application/json" << + "{ \"access_token\":\"t0k3n\", \"expires_in\": 3600, \"scope\": \"\" }" << + response; + + response.clear(); + response.insert("AccessToken", "t0k3n"); + response.insert("ExpiresIn", int(3600)); + response.insert("RefreshToken", QString()); + response.insert("Scope", QStringList() << "one" << "two"); + QTest::newRow("reply code, valid token, other scope") << + "http://localhost/resp.html?code=c0d3&$state" << + int(-1) << + "https://localhost/access_token" << + "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" << + int(200) << + "application/json" << + "{ \"access_token\":\"t0k3n\", \"expires_in\": 3600, " + "\"scope\": \"one two\" }" << + response; + + response.clear(); QTest::newRow("reply code, facebook, no token") << - "http://localhost/resp.html?code=c0d3" << + "http://localhost/resp.html?code=c0d3&$state" << int(Error::NotAuthorized) << "https://localhost/access_token" << "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" << @@ -911,8 +986,9 @@ response.insert("AccessToken", "t0k3n"); response.insert("ExpiresIn", int(3600)); response.insert("RefreshToken", QString()); + response.insert("Scope", QStringList() << "one" << "two" << "three"); QTest::newRow("reply code, facebook, valid token") << - "http://localhost/resp.html?code=c0d3" << + "http://localhost/resp.html?code=c0d3&$state" << int(-1) << "https://localhost/access_token" << "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" << @@ -925,6 +1001,7 @@ response.insert("AccessToken", "t0k3n"); response.insert("ExpiresIn", int(3600)); response.insert("RefreshToken", QString()); + response.insert("Scope", QStringList() << "one" << "two" << "three"); QTest::newRow("username-password, valid token") << "http://localhost/resp.html?username=us3r&password=s3cr3t" << int(-1) << @@ -939,6 +1016,7 @@ response.insert("AccessToken", "t0k3n"); response.insert("ExpiresIn", int(3600)); response.insert("RefreshToken", QString()); + response.insert("Scope", QStringList() << "one" << "two" << "three"); QTest::newRow("assertion, valid token") << "http://localhost/resp.html?assertion_type=http://oauth.net/token/1.0" "&assertion=oauth1t0k3n" << @@ -954,6 +1032,7 @@ response.insert("AccessToken", "t0k3n"); response.insert("ExpiresIn", int(3600)); response.insert("RefreshToken", QString()); + response.insert("Scope", QStringList() << "one" << "two" << "three"); QTest::newRow("username-password, valid token, wrong content type") << "http://localhost/resp.html?username=us3r&password=s3cr3t" << int(-1) << @@ -984,14 +1063,12 @@ data.setClientId("104660106251471"); data.setClientSecret("fa28f40b5a1f8c1d5628963d880636fbkjkjkj"); data.setRedirectUri("http://localhost/resp.html"); + data.setScope(QStringList() << "one" << "two" << "three"); - QObject::connect(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)), - this, SLOT(result(const SignOn::SessionData&)),Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(error(const SignOn::Error & )), - this, SLOT(pluginError(const SignOn::Error &)),Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(userActionRequired(const SignOn::UiSessionData&)), - this, SLOT(uiRequest(const SignOn::UiSessionData&)),Qt::QueuedConnection); - QTimer::singleShot(10*1000, &m_loop, SLOT(quit())); + QSignalSpy result(m_testPlugin, SIGNAL(result(const SignOn::SessionData&))); + QSignalSpy error(m_testPlugin, SIGNAL(error(const SignOn::Error &))); + QSignalSpy userActionRequired(m_testPlugin, + SIGNAL(userActionRequired(const SignOn::UiSessionData&))); TestNetworkAccessManager *nam = new TestNetworkAccessManager; m_testPlugin->m_networkAccessManager = nam; @@ -1004,20 +1081,26 @@ nam->setNextReply(reply); m_testPlugin->process(data, QString("web_server")); - m_loop.exec(); - QCOMPARE(m_uiResponse.UrlResponse(), QString("UI request received")); + QTRY_COMPARE(userActionRequired.count(), 1); + QString state = parseState(userActionRequired); if (!urlResponse.isEmpty()) { + urlResponse.replace("$state", QString("state=") + state); + urlResponse.replace("$wrongstate", QString("state=12") + state); info.setUrlResponse(urlResponse); } m_testPlugin->userActionFinished(info); - m_loop.exec(); - QCOMPARE(m_error.type(), errorCode); + QTRY_COMPARE(error.count(), errorCode < 0 ? 0 : 1); + QTRY_COMPARE(result.count(), errorCode < 0 ? 1 : 0); + if (errorCode >= 0) { + QCOMPARE(error.at(0).at(0).value().type(), errorCode); + } else { + QCOMPARE(result.at(0).at(0).value().toMap(), response); + } QCOMPARE(nam->m_lastRequest.url(), QUrl(postUrl)); QCOMPARE(QString::fromUtf8(nam->m_lastRequestData), postContents); - QCOMPARE(m_response.toMap(), response); delete nam; } @@ -1132,13 +1215,10 @@ data.setConsumerSecret("fa28f40b5a1f8c1d5628963d880636fbkjkjkj"); data.setRealm("MyHost"); - QObject::connect(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)), - this, SLOT(result(const SignOn::SessionData&)),Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(error(const SignOn::Error & )), - this, SLOT(pluginError(const SignOn::Error &)),Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(userActionRequired(const SignOn::UiSessionData&)), - this, SLOT(uiRequest(const SignOn::UiSessionData&)),Qt::QueuedConnection); - QTimer::singleShot(10*1000, &m_loop, SLOT(quit())); + QSignalSpy result(m_testPlugin, SIGNAL(result(const SignOn::SessionData&))); + QSignalSpy error(m_testPlugin, SIGNAL(error(const SignOn::Error &))); + QSignalSpy userActionRequired(m_testPlugin, + SIGNAL(userActionRequired(const SignOn::UiSessionData&))); TestNetworkAccessManager *nam = new TestNetworkAccessManager; m_testPlugin->m_networkAccessManager = nam; @@ -1149,8 +1229,7 @@ nam->setNextReply(reply); m_testPlugin->process(data, mechanism); - m_loop.exec(); - QCOMPARE(m_uiResponse.UrlResponse(), QString("UI request received")); + QTRY_COMPARE(userActionRequired.count(), 1); nam->m_lastRequest = QNetworkRequest(); nam->m_lastRequestData = QByteArray(); @@ -1168,9 +1247,16 @@ } m_testPlugin->userActionFinished(info); - m_loop.exec(); + QTRY_COMPARE(error.count(), errorCode < 0 ? 0 : 1); + QTRY_COMPARE(result.count(), errorCode < 0 ? 1 : 0); + QVariantMap resp; + if (errorCode >= 0) { + QCOMPARE(error.at(0).at(0).value().type(), errorCode); + } else { + resp = result.at(0).at(0).value().toMap(); + QVERIFY(mapIsSubset(response, resp)); + } - QCOMPARE(m_error.type(), errorCode); if (!expectedAuthMap.isEmpty()) { QCOMPARE(nam->m_lastRequest.url().toString(), data.TokenEndpoint()); QVERIFY(nam->m_lastRequestData.isEmpty()); @@ -1189,9 +1275,6 @@ QCOMPARE(authMap.value("oauth_signature_method").toString(), mechanism); QVERIFY(mapIsSubset(expectedAuthMap, authMap)); } - if (errorCode < 0) { - QVERIFY(mapIsSubset(response, m_response.toMap())); - } delete nam; } @@ -1256,16 +1339,9 @@ data.setClientSecret("fa28f40b5a1f8c1d5628963d880636fbkjkjkj"); data.setRedirectUri("http://localhost/resp.html"); - QObject::connect(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)), - this, SLOT(result(const SignOn::SessionData&)), - Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(error(const SignOn::Error & )), - this, SLOT(pluginError(const SignOn::Error &)), - Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(userActionRequired(const SignOn::UiSessionData&)), - this, SLOT(uiRequest(const SignOn::UiSessionData&)), - Qt::QueuedConnection); - QTimer::singleShot(10*1000, &m_loop, SLOT(quit())); + QSignalSpy error(m_testPlugin, SIGNAL(error(const SignOn::Error &))); + QSignalSpy userActionRequired(m_testPlugin, + SIGNAL(userActionRequired(const SignOn::UiSessionData&))); TestNetworkAccessManager *nam = new TestNetworkAccessManager; m_testPlugin->m_networkAccessManager = nam; @@ -1276,13 +1352,14 @@ nam->setNextReply(reply); m_testPlugin->process(data, QString("web_server")); - m_loop.exec(); + QTRY_COMPARE(userActionRequired.count(), 1); + QString state = parseState(userActionRequired); - info.setUrlResponse("http://localhost/resp.html?code=c0d3"); + info.setUrlResponse("http://localhost/resp.html?code=c0d3&state=" + state); m_testPlugin->userActionFinished(info); - m_loop.exec(); - QCOMPARE(m_error.type(), expectedErrorCode); + QTRY_COMPARE(error.count(), 1); + QCOMPARE(error.at(0).at(0).value().type(), expectedErrorCode); delete nam; } @@ -1313,6 +1390,7 @@ response.insert("AccessToken", "n3w-t0k3n"); response.insert("ExpiresIn", 3600); response.insert("RefreshToken", QString()); + response.insert("Scope", QStringList()); QTest::newRow("expired access token") << data.toMap() << response; @@ -1331,16 +1409,8 @@ SignOn::UiSessionData info; - QObject::connect(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)), - this, SLOT(result(const SignOn::SessionData&)), - Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(error(const SignOn::Error & )), - this, SLOT(pluginError(const SignOn::Error &)), - Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(userActionRequired(const SignOn::UiSessionData&)), - this, SLOT(uiRequest(const SignOn::UiSessionData&)), - Qt::QueuedConnection); - QTimer::singleShot(10*1000, &m_loop, SLOT(quit())); + QSignalSpy result(m_testPlugin, SIGNAL(result(const SignOn::SessionData&))); + QSignalSpy error(m_testPlugin, SIGNAL(error(const SignOn::Error &))); TestNetworkAccessManager *nam = new TestNetworkAccessManager; m_testPlugin->m_networkAccessManager = nam; @@ -1351,14 +1421,14 @@ nam->setNextReply(reply); m_testPlugin->process(sessionData, QString("web_server")); - m_loop.exec(); + QTRY_COMPARE(result.count(), 1); + QCOMPARE(error.count(), 0); - QCOMPARE(m_error.type(), -1); QCOMPARE(nam->m_lastRequest.url(), QUrl("https://localhost/access_token")); QCOMPARE(QString::fromUtf8(nam->m_lastRequestData), QString("grant_type=refresh_token&refresh_token=r3fr3sh")); - QCOMPARE(m_response.toMap(), expectedResponse); + QCOMPARE(result.at(0).at(0).value().toMap(), expectedResponse); delete nam; } @@ -1421,16 +1491,9 @@ SignOn::UiSessionData info; - QObject::connect(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)), - this, SLOT(result(const SignOn::SessionData&)), - Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(error(const SignOn::Error & )), - this, SLOT(pluginError(const SignOn::Error &)), - Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(userActionRequired(const SignOn::UiSessionData&)), - this, SLOT(uiRequest(const SignOn::UiSessionData&)), - Qt::QueuedConnection); - QTimer::singleShot(10*1000, &m_loop, SLOT(quit())); + QSignalSpy error(m_testPlugin, SIGNAL(error(const SignOn::Error &))); + QSignalSpy userActionRequired(m_testPlugin, + SIGNAL(userActionRequired(const SignOn::UiSessionData&))); TestNetworkAccessManager *nam = new TestNetworkAccessManager; m_testPlugin->m_networkAccessManager = nam; @@ -1445,11 +1508,13 @@ nam->setNextReply(reply); m_testPlugin->process(data, QString("web_server")); - m_loop.exec(); - QCOMPARE(m_error.type(), expectedError); if (expectedError < 0) { - QCOMPARE(m_uiResponse.UrlResponse(), QString("UI request received")); + QTRY_COMPARE(userActionRequired.count(), 1); + QCOMPARE(error.count(), 0); + } else { + QTRY_COMPARE(error.count(), 1); + QCOMPARE(error.at(0).at(0).value().type(), expectedError); } delete nam; @@ -1502,16 +1567,10 @@ data.setRedirectUri("http://localhost/resp.html"); data.setForceClientAuthViaRequestBody(forceAuthViaRequestBody); - QObject::connect(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)), - this, SLOT(result(const SignOn::SessionData&)), - Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(error(const SignOn::Error & )), - this, SLOT(pluginError(const SignOn::Error &)), - Qt::QueuedConnection); - QObject::connect(m_testPlugin, SIGNAL(userActionRequired(const SignOn::UiSessionData&)), - this, SLOT(uiRequest(const SignOn::UiSessionData&)), - Qt::QueuedConnection); - QTimer::singleShot(10*1000, &m_loop, SLOT(quit())); + QSignalSpy result(m_testPlugin, SIGNAL(result(const SignOn::SessionData&))); + QSignalSpy error(m_testPlugin, SIGNAL(error(const SignOn::Error &))); + QSignalSpy userActionRequired(m_testPlugin, + SIGNAL(userActionRequired(const SignOn::UiSessionData&))); TestNetworkAccessManager *nam = new TestNetworkAccessManager; m_testPlugin->m_networkAccessManager = nam; @@ -1522,13 +1581,14 @@ nam->setNextReply(reply); m_testPlugin->process(data, QString("web_server")); - m_loop.exec(); + QTRY_COMPARE(userActionRequired.count(), 1); + QString state = parseState(userActionRequired); - info.setUrlResponse("http://localhost/resp.html?code=c0d3"); + info.setUrlResponse("http://localhost/resp.html?code=c0d3&state=" + state); m_testPlugin->userActionFinished(info); - m_loop.exec(); - QCOMPARE(m_error.type(), -1); + QTRY_COMPARE(result.count(), 1); + QCOMPARE(error.count(), 0); QCOMPARE(nam->m_lastRequest.url(), QUrl("https://localhost/access_token")); QCOMPARE(QString::fromUtf8(nam->m_lastRequestData), postContents); QCOMPARE(QString::fromUtf8(nam->m_lastRequest.rawHeader("Authorization")), diff -Nru signon-plugin-oauth2-0.21+15.04.20150327/tests/oauth2plugintest.h signon-plugin-oauth2-0.22+15.04.20150417/tests/oauth2plugintest.h --- signon-plugin-oauth2-0.21+15.04.20150327/tests/oauth2plugintest.h 2015-03-27 11:12:52.000000000 +0000 +++ signon-plugin-oauth2-0.22+15.04.20150417/tests/oauth2plugintest.h 2015-04-17 14:56:48.000000000 +0000 @@ -35,13 +35,6 @@ { Q_OBJECT -public slots: - void result(const SignOn::SessionData &data); - void pluginError(const SignOn::Error &err); - void uiRequest(const SignOn::UiSessionData &data); - void store(const SignOn::SessionData &data); - void aborted(QNetworkReply *reply); - private slots: void initTestCase(); void cleanupTestCase(); @@ -73,11 +66,6 @@ private: Plugin *m_testPlugin; - SignOn::Error m_error; - SignOn::SessionData m_response; - SignOn::UiSessionData m_uiResponse; - SignOn::SessionData m_stored; - QEventLoop m_loop; }; #endif // OAUTH2PLUGINTEST_H diff -Nru signon-plugin-oauth2-0.21+15.04.20150327/tests/tests.pro signon-plugin-oauth2-0.22+15.04.20150417/tests/tests.pro --- signon-plugin-oauth2-0.21+15.04.20150327/tests/tests.pro 2015-03-27 11:12:46.000000000 +0000 +++ signon-plugin-oauth2-0.22+15.04.20150417/tests/tests.pro 2015-04-17 14:56:48.000000000 +0000 @@ -25,16 +25,9 @@ $${TOP_SRC_DIR}/src \ /usr/include/signon-qt PKGCONFIG += \ + libsignon-qt5 \ signon-plugins -lessThan(QT_MAJOR_VERSION, 5) { - PKGCONFIG += \ - QJson \ - libsignon-qt -} else { - PKGCONFIG += \ - libsignon-qt5 -} target.path = $${INSTALL_PREFIX}/bin testsuite.path = $${INSTALL_PREFIX}/share/$$TARGET