Merge lp:~mardy/signon-plugin-oauth2/packaging into lp:signon-plugin-oauth2

Proposed by Alberto Mardegan
Status: Merged
Approved by: David Barth
Approved revision: 66
Merged at revision: 64
Proposed branch: lp:~mardy/signon-plugin-oauth2/packaging
Merge into: lp:signon-plugin-oauth2
Diff against target: 783 lines (+562/-44)
8 files modified
common-vars.pri (+1/-1)
debian/changelog (+8/-0)
debian/control (+2/-1)
src/oauth2data.h (+7/-0)
src/oauth2plugin.cpp (+22/-16)
src/oauth2plugin.h (+1/-1)
tests/oauth2plugintest.cpp (+515/-25)
tests/oauth2plugintest.h (+6/-0)
To merge this branch: bzr merge lp:~mardy/signon-plugin-oauth2/packaging
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
David Barth (community) Approve
Review via email: mp+234282@code.launchpad.net

Commit message

New upstream release

- OAuth 2.0: follow the spec more closely, add Vimeo support
- Tests: increase test coverage

Description of the change

New upstream release

- OAuth 2.0: follow the spec more closely, add Vimeo support
- Tests: increase test coverage

To post a comment you must log in.
Revision history for this message
David Barth (dbarth) :
review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
66. By Alberto Mardegan

Require the very latest signond

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'common-vars.pri'
2--- common-vars.pri 2013-11-13 09:47:25 +0000
3+++ common-vars.pri 2014-09-12 09:09:50 +0000
4@@ -13,7 +13,7 @@
5 # Project version
6 # remember to update debian/* files if you changes this
7 #-----------------------------------------------------------------------------
8-PROJECT_VERSION = 0.19
9+PROJECT_VERSION = 0.20
10
11 #-----------------------------------------------------------------------------
12 # Library version
13
14=== modified file 'debian/changelog'
15--- debian/changelog 2014-05-13 07:07:20 +0000
16+++ debian/changelog 2014-09-12 09:09:50 +0000
17@@ -1,3 +1,11 @@
18+signon-plugin-oauth2 (0.20-0ubuntu1) UNRELEASED; urgency=medium
19+
20+ * New upstream release
21+ - OAuth 2.0: follow the spec more closely, add Vimeo support
22+ - Tests: increase test coverage
23+
24+ -- Alberto Mardegan <alberto.mardegan@canonical.com> Thu, 11 Sep 2014 12:55:35 +0300
25+
26 signon-plugin-oauth2 (0.19+14.10.20140513-0ubuntu1) utopic; urgency=low
27
28 [ Ubuntu daily release ]
29
30=== modified file 'debian/control'
31--- debian/control 2014-05-09 19:27:46 +0000
32+++ debian/control 2014-09-12 09:09:50 +0000
33@@ -9,7 +9,7 @@
34 libsignon-qt5-dev,
35 pkg-config,
36 qt5-default,
37- signon-plugins-dev (>= 8.50-0ubuntu1),
38+ signon-plugins-dev (>> 8.57+14.10.20140827-0ubuntu1),
39 xvfb,
40 Standards-Version: 3.9.4
41 Homepage: http://code.google.com/p/accounts-sso/
42@@ -23,6 +23,7 @@
43 Depends: ${shlibs:Depends},
44 ${misc:Depends},
45 signon-ui,
46+Breaks: account-plugin-google (<< 0.12)
47 Description: Single Signon oauth2 plugin
48 Oauth2 plugin for the Single Signon framework
49
50
51=== modified file 'src/oauth2data.h'
52--- src/oauth2data.h 2012-07-17 13:09:22 +0000
53+++ src/oauth2data.h 2014-09-12 09:09:50 +0000
54@@ -57,6 +57,13 @@
55 SIGNON_SESSION_DECLARE_PROPERTY(QString, ClientSecret);
56
57 /*!
58+ * Set this to true if the server does not conform to the OAuth 2.0
59+ * specification in that it does not support supplying client ID and
60+ * secret via basic HTTP authorization.
61+ */
62+ SIGNON_SESSION_DECLARE_PROPERTY(bool, ForceClientAuthViaRequestBody);
63+
64+ /*!
65 * redirection URI
66 */
67 SIGNON_SESSION_DECLARE_PROPERTY(QString, RedirectUri);
68
69=== modified file 'src/oauth2plugin.cpp'
70--- src/oauth2plugin.cpp 2014-05-05 09:42:08 +0000
71+++ src/oauth2plugin.cpp 2014-09-12 09:09:50 +0000
72@@ -388,33 +388,27 @@
73 if (url.hasQueryItem(AUTH_CODE)) {
74 QString code = url.queryItemValue(AUTH_CODE);
75 newUrl.addQueryItem(GRANT_TYPE, AUTHORIZATION_CODE);
76- newUrl.addQueryItem(CLIENT_ID, d->m_oauth2Data.ClientId());
77- newUrl.addQueryItem(CLIENT_SECRET, d->m_oauth2Data.ClientSecret());
78 newUrl.addQueryItem(AUTH_CODE, code);
79 newUrl.addQueryItem(REDIRECT_URI, d->m_oauth2Data.RedirectUri());
80- sendOAuth2PostRequest(newUrl.encodedQuery(),
81+ sendOAuth2PostRequest(newUrl,
82 GrantType::AuthorizationCode);
83 }
84 else if (url.hasQueryItem(USERNAME) && url.hasQueryItem(PASSWORD)) {
85 QString username = url.queryItemValue(USERNAME);
86 QString password = url.queryItemValue(PASSWORD);
87 newUrl.addQueryItem(GRANT_TYPE, USER_BASIC);
88- newUrl.addQueryItem(CLIENT_ID, d->m_oauth2Data.ClientId());
89- newUrl.addQueryItem(CLIENT_SECRET, d->m_oauth2Data.ClientSecret());
90 newUrl.addQueryItem(USERNAME, username);
91 newUrl.addQueryItem(PASSWORD, password);
92- sendOAuth2PostRequest(newUrl.encodedQuery(),
93+ sendOAuth2PostRequest(newUrl,
94 GrantType::UserBasic);
95 }
96 else if (url.hasQueryItem(ASSERTION_TYPE) && url.hasQueryItem(ASSERTION)) {
97 QString assertion_type = url.queryItemValue(ASSERTION_TYPE);
98 QString assertion = url.queryItemValue(ASSERTION);
99 newUrl.addQueryItem(GRANT_TYPE, ASSERTION);
100- newUrl.addQueryItem(CLIENT_ID, d->m_oauth2Data.ClientId());
101- newUrl.addQueryItem(CLIENT_SECRET, d->m_oauth2Data.ClientSecret());
102 newUrl.addQueryItem(ASSERTION_TYPE, assertion_type);
103 newUrl.addQueryItem(ASSERTION, assertion);
104- sendOAuth2PostRequest(newUrl.encodedQuery(),
105+ sendOAuth2PostRequest(newUrl,
106 GrantType::Assertion);
107 }
108 else if (url.hasQueryItem(REFRESH_TOKEN)) {
109@@ -569,15 +563,11 @@
110 TRACE() << refreshToken;
111 QUrl url;
112 url.addQueryItem(GRANT_TYPE, REFRESH_TOKEN);
113- url.addQueryItem(CLIENT_ID, d->m_oauth2Data.ClientId());
114- if (!d->m_oauth2Data.ClientSecret().isEmpty()) {
115- url.addQueryItem(CLIENT_SECRET, d->m_oauth2Data.ClientSecret());
116- }
117 url.addQueryItem(REFRESH_TOKEN, refreshToken);
118- sendOAuth2PostRequest(url.encodedQuery(), GrantType::RefreshToken);
119+ sendOAuth2PostRequest(url, GrantType::RefreshToken);
120 }
121
122-void OAuth2Plugin::sendOAuth2PostRequest(const QByteArray &postData,
123+void OAuth2Plugin::sendOAuth2PostRequest(QUrl &postData,
124 GrantType::e grantType)
125 {
126 Q_D(OAuth2Plugin);
127@@ -589,10 +579,26 @@
128 QNetworkRequest request(url);
129 request.setRawHeader(CONTENT_TYPE, CONTENT_APP_URLENCODED);
130
131+ if (!d->m_oauth2Data.ClientSecret().isEmpty()) {
132+ if (d->m_oauth2Data.ForceClientAuthViaRequestBody()) {
133+ postData.addQueryItem(CLIENT_ID, d->m_oauth2Data.ClientId());
134+ postData.addQueryItem(CLIENT_SECRET, d->m_oauth2Data.ClientSecret());
135+ } else {
136+ QByteArray authorization =
137+ QUrl::toPercentEncoding(d->m_oauth2Data.ClientId()) + ":" +
138+ QUrl::toPercentEncoding(d->m_oauth2Data.ClientSecret());
139+ QByteArray basicAuthorization =
140+ QByteArray("Basic ") + authorization.toBase64();
141+ request.setRawHeader("Authorization", basicAuthorization);
142+ }
143+ } else {
144+ postData.addQueryItem(CLIENT_ID, d->m_oauth2Data.ClientId());
145+ }
146+
147 d->m_grantType = grantType;
148
149 TRACE() << "Query string = " << postData;
150- postRequest(request, postData);
151+ postRequest(request, postData.encodedQuery());
152 }
153
154 void OAuth2Plugin::storeResponse(const OAuth2PluginTokenData &response)
155
156=== modified file 'src/oauth2plugin.h'
157--- src/oauth2plugin.h 2013-01-22 14:30:08 +0000
158+++ src/oauth2plugin.h 2014-09-12 09:09:50 +0000
159@@ -72,7 +72,7 @@
160 bool respondWithStoredToken(const QVariantMap &token,
161 const QStringList &scopes);
162 void refreshOAuth2Token(const QString &refreshToken);
163- void sendOAuth2PostRequest(const QByteArray &postData,
164+ void sendOAuth2PostRequest(QUrl &postData,
165 GrantType::e grantType);
166 void storeResponse(const OAuth2PluginTokenData &response);
167 const QVariantMap parseJSONReply(const QByteArray &reply);
168
169=== modified file 'tests/oauth2plugintest.cpp'
170--- tests/oauth2plugintest.cpp 2014-05-05 09:42:08 +0000
171+++ tests/oauth2plugintest.cpp 2014-09-12 09:09:50 +0000
172@@ -21,6 +21,10 @@
173 * 02110-1301 USA
174 */
175
176+#include <QNetworkAccessManager>
177+#include <QNetworkReply>
178+#include <QPointer>
179+#include <QTimer>
180 #include <QtTest/QtTest>
181
182 #include "plugin.h"
183@@ -36,6 +40,91 @@
184 #define TEST_START qDebug("\n\n\n\n ----------------- %s ----------------\n\n", __func__);
185 #define TEST_DONE qDebug("\n\n ----------------- %s DONE ----------------\n\n", __func__);
186
187+class TestNetworkReply: public QNetworkReply
188+{
189+ Q_OBJECT
190+
191+public:
192+ TestNetworkReply(QObject *parent = 0):
193+ QNetworkReply(parent),
194+ m_offset(0)
195+ {}
196+
197+ void setError(NetworkError errorCode, const QString &errorString) {
198+ QNetworkReply::setError(errorCode, errorString);
199+ }
200+
201+ void setRawHeader(const QByteArray &headerName, const QByteArray &value) {
202+ QNetworkReply::setRawHeader(headerName, value);
203+ }
204+
205+ void setContentType(const QString &contentType) {
206+ setRawHeader("Content-Type", contentType.toUtf8());
207+ }
208+
209+ void setStatusCode(int statusCode) {
210+ setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode);
211+ }
212+
213+ void setContent(const QByteArray &content) {
214+ m_content = content;
215+ m_offset = 0;
216+
217+ open(ReadOnly | Unbuffered);
218+ setHeader(QNetworkRequest::ContentLengthHeader, QVariant(content.size()));
219+
220+ QTimer::singleShot(0, this, SIGNAL(readyRead()));
221+ QTimer::singleShot(10, this, SLOT(finish()));
222+ }
223+
224+public Q_SLOTS:
225+ void finish() { setFinished(true); Q_EMIT finished(); }
226+
227+protected:
228+ void abort() Q_DECL_OVERRIDE {}
229+ qint64 bytesAvailable() const Q_DECL_OVERRIDE {
230+ return m_content.size() - m_offset + QIODevice::bytesAvailable();
231+ }
232+
233+ bool isSequential() const Q_DECL_OVERRIDE { return true; }
234+ qint64 readData(char *data, qint64 maxSize) Q_DECL_OVERRIDE {
235+ if (m_offset >= m_content.size())
236+ return -1;
237+ qint64 number = qMin(maxSize, m_content.size() - m_offset);
238+ memcpy(data, m_content.constData() + m_offset, number);
239+ m_offset += number;
240+ return number;
241+ }
242+
243+private:
244+ QByteArray m_content;
245+ qint64 m_offset;
246+};
247+
248+class TestNetworkAccessManager: public QNetworkAccessManager
249+{
250+ Q_OBJECT
251+
252+public:
253+ TestNetworkAccessManager(): QNetworkAccessManager() {}
254+
255+ void setNextReply(TestNetworkReply *reply) { m_nextReply = reply; }
256+
257+protected:
258+ QNetworkReply *createRequest(Operation op, const QNetworkRequest &request,
259+ QIODevice *outgoingData = 0) Q_DECL_OVERRIDE {
260+ Q_UNUSED(op);
261+ m_lastRequest = request;
262+ m_lastRequestData = outgoingData->readAll();
263+ return m_nextReply;
264+ }
265+
266+public:
267+ QPointer<TestNetworkReply> m_nextReply;
268+ QNetworkRequest m_lastRequest;
269+ QByteArray m_lastRequestData;
270+};
271+
272 void OAuth2PluginTest::initTestCase()
273 {
274 TEST_START
275@@ -56,6 +145,8 @@
276 void OAuth2PluginTest::init()
277 {
278 m_testPlugin = new Plugin();
279+ m_response = SignOn::SessionData();
280+ m_error = SignOn::Error(-1);
281 }
282
283 //finnish each test by deleting plugin
284@@ -506,18 +597,169 @@
285 TEST_DONE
286 }
287
288+void OAuth2PluginTest::testPluginWebserverUserActionFinished_data()
289+{
290+ QTest::addColumn<QString>("urlResponse");
291+ QTest::addColumn<int>("errorCode");
292+ QTest::addColumn<QString>("postUrl");
293+ QTest::addColumn<QString>("postContents");
294+ QTest::addColumn<int>("replyStatusCode");
295+ QTest::addColumn<QString>("replyContentType");
296+ QTest::addColumn<QString>("replyContents");
297+ QTest::addColumn<QVariantMap>("response");
298+
299+ QVariantMap response;
300+
301+ QTest::newRow("empty data") <<
302+ "" <<
303+ int(Error::NotAuthorized) <<
304+ "" << "" << 0 << "" << "" << QVariantMap();
305+
306+ QTest::newRow("no query data") <<
307+ "http://localhost/resp.html" <<
308+ int(Error::NotAuthorized) <<
309+ "" << "" << 0 << "" << "" << QVariantMap();
310+
311+ QTest::newRow("permission denied") <<
312+ "http://localhost/resp.html?error=user_denied" <<
313+ int(Error::NotAuthorized) <<
314+ "" << "" << 0 << "" << "" << QVariantMap();
315+
316+ QTest::newRow("invalid data") <<
317+ "http://localhost/resp.html?sdsdsds=access.grant." <<
318+ int(Error::NotAuthorized) <<
319+ "" << "" << 0 << "" << "" << QVariantMap();
320+
321+ QTest::newRow("reply code, http error 401") <<
322+ "http://localhost/resp.html?code=c0d3" <<
323+ int(Error::OperationFailed) <<
324+ "https://localhost/access_token" <<
325+ "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" <<
326+ int(401) <<
327+ "application/json" <<
328+ "something else" <<
329+ QVariantMap();
330+
331+ QTest::newRow("reply code, empty reply") <<
332+ "http://localhost/resp.html?code=c0d3" <<
333+ int(Error::NotAuthorized) <<
334+ "https://localhost/access_token" <<
335+ "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" <<
336+ int(200) <<
337+ "application/json" <<
338+ "something else" <<
339+ QVariantMap();
340+
341+ QTest::newRow("reply code, no content type") <<
342+ "http://localhost/resp.html?code=c0d3" <<
343+ int(Error::OperationFailed) <<
344+ "https://localhost/access_token" <<
345+ "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" <<
346+ int(200) <<
347+ "" <<
348+ "something else" <<
349+ QVariantMap();
350+
351+ QTest::newRow("reply code, unsupported content type") <<
352+ "http://localhost/resp.html?code=c0d3" <<
353+ int(Error::OperationFailed) <<
354+ "https://localhost/access_token" <<
355+ "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" <<
356+ int(200) <<
357+ "image/jpeg" <<
358+ "something else" <<
359+ QVariantMap();
360+
361+ response.clear();
362+ response.insert("AccessToken", "t0k3n");
363+ response.insert("ExpiresIn", int(3600));
364+ response.insert("RefreshToken", QString());
365+ QTest::newRow("reply code, valid token") <<
366+ "http://localhost/resp.html?code=c0d3" <<
367+ int(-1) <<
368+ "https://localhost/access_token" <<
369+ "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" <<
370+ int(200) <<
371+ "application/json" <<
372+ "{ \"access_token\":\"t0k3n\", \"expires_in\": 3600 }" <<
373+ response;
374+
375+ response.clear();
376+ QTest::newRow("reply code, facebook, no token") <<
377+ "http://localhost/resp.html?code=c0d3" <<
378+ int(Error::NotAuthorized) <<
379+ "https://localhost/access_token" <<
380+ "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" <<
381+ int(200) <<
382+ "text/plain" <<
383+ "expires=3600" <<
384+ response;
385+
386+ response.clear();
387+ response.insert("AccessToken", "t0k3n");
388+ response.insert("ExpiresIn", int(3600));
389+ response.insert("RefreshToken", QString());
390+ QTest::newRow("reply code, facebook, valid token") <<
391+ "http://localhost/resp.html?code=c0d3" <<
392+ int(-1) <<
393+ "https://localhost/access_token" <<
394+ "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" <<
395+ int(200) <<
396+ "text/plain" <<
397+ "access_token=t0k3n&expires=3600" <<
398+ response;
399+
400+ response.clear();
401+ response.insert("AccessToken", "t0k3n");
402+ response.insert("ExpiresIn", int(3600));
403+ response.insert("RefreshToken", QString());
404+ QTest::newRow("username-password, valid token") <<
405+ "http://localhost/resp.html?username=us3r&password=s3cr3t" <<
406+ int(-1) <<
407+ "https://localhost/access_token" <<
408+ "grant_type=user_basic&username=us3r&password=s3cr3t" <<
409+ int(200) <<
410+ "application/json" <<
411+ "{ \"access_token\":\"t0k3n\", \"expires_in\": 3600 }" <<
412+ response;
413+
414+ response.clear();
415+ response.insert("AccessToken", "t0k3n");
416+ response.insert("ExpiresIn", int(3600));
417+ response.insert("RefreshToken", QString());
418+ QTest::newRow("assertion, valid token") <<
419+ "http://localhost/resp.html?assertion_type=http://oauth.net/token/1.0"
420+ "&assertion=oauth1t0k3n" <<
421+ int(-1) <<
422+ "https://localhost/access_token" <<
423+ "grant_type=assertion&assertion_type=http://oauth.net/token/1.0&assertion=oauth1t0k3n" <<
424+ int(200) <<
425+ "application/json" <<
426+ "{ \"access_token\":\"t0k3n\", \"expires_in\": 3600 }" <<
427+ response;
428+}
429+
430 void OAuth2PluginTest::testPluginWebserverUserActionFinished()
431 {
432 TEST_START
433
434+ QFETCH(QString, urlResponse);
435+ QFETCH(int, errorCode);
436+ QFETCH(QString, postUrl);
437+ QFETCH(QString, postContents);
438+ QFETCH(int, replyStatusCode);
439+ QFETCH(QString, replyContentType);
440+ QFETCH(QString, replyContents);
441+ QFETCH(QVariantMap, response);
442+
443 SignOn::UiSessionData info;
444 OAuth2PluginData data;
445- data.setHost("https://localhost");
446+ data.setHost("localhost");
447 data.setAuthPath("authorize");
448 data.setTokenPath("access_token");
449 data.setClientId("104660106251471");
450 data.setClientSecret("fa28f40b5a1f8c1d5628963d880636fbkjkjkj");
451- data.setRedirectUri("http://localhost/connect/login_success.html");
452+ data.setRedirectUri("http://localhost/resp.html");
453
454 QObject::connect(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)),
455 this, SLOT(result(const SignOn::SessionData&)),Qt::QueuedConnection);
456@@ -527,33 +769,281 @@
457 this, SLOT(uiRequest(const SignOn::UiSessionData&)),Qt::QueuedConnection);
458 QTimer::singleShot(10*1000, &m_loop, SLOT(quit()));
459
460+ TestNetworkAccessManager *nam = new TestNetworkAccessManager;
461+ m_testPlugin->m_networkAccessManager = nam;
462+ TestNetworkReply *reply = new TestNetworkReply(this);
463+ reply->setStatusCode(replyStatusCode);
464+ if (!replyContentType.isEmpty()) {
465+ reply->setContentType(replyContentType);
466+ }
467+ reply->setContent(replyContents.toUtf8());
468+ nam->setNextReply(reply);
469+
470 m_testPlugin->process(data, QString("web_server"));
471 m_loop.exec();
472 qDebug() << "Data = " << m_uiResponse.UrlResponse();
473 QCOMPARE(m_uiResponse.UrlResponse(), QString("UI request received"));
474
475- //empty data
476- m_testPlugin->userActionFinished(info);
477- m_loop.exec();
478- QCOMPARE(m_error.type(), int(Error::NotAuthorized));
479-
480- //invalid data
481- info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html"));
482- m_testPlugin->userActionFinished(info);
483- m_loop.exec();
484- QCOMPARE(m_error.type(), int(Error::NotAuthorized));
485-
486- //Permission denied
487- info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html?error=user_denied"));
488- m_testPlugin->userActionFinished(info);
489- m_loop.exec();
490- QCOMPARE(m_error.type(), int(Error::NotAuthorized));
491-
492- //invalid data
493- info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html?sdsdsds=access.grant."));
494- m_testPlugin->userActionFinished(info);
495- m_loop.exec();
496- QCOMPARE(m_error.type(), int(Error::NotAuthorized));
497+ if (!urlResponse.isEmpty()) {
498+ info.setUrlResponse(urlResponse);
499+ }
500+
501+ m_testPlugin->userActionFinished(info);
502+ m_loop.exec();
503+
504+ QCOMPARE(m_error.type(), errorCode);
505+ QCOMPARE(nam->m_lastRequest.url(), QUrl(postUrl));
506+ QCOMPARE(QString::fromUtf8(nam->m_lastRequestData), postContents);
507+ qDebug() << "got response" << m_response.toMap();
508+ qDebug() << "expected" << response;
509+ QCOMPARE(m_response.toMap(), response);
510+
511+ delete nam;
512+
513+ TEST_DONE
514+}
515+
516+void OAuth2PluginTest::testOAuth2Errors_data()
517+{
518+ QTest::addColumn<QString>("replyContents");
519+ QTest::addColumn<int>("expectedErrorCode");
520+
521+ QTest::newRow("incorrect_client_credentials") <<
522+ "{ \"error\": \"incorrect_client_credentials\" }" <<
523+ int(Error::InvalidCredentials);
524+
525+ QTest::newRow("redirect_uri_mismatch") <<
526+ "{ \"error\": \"redirect_uri_mismatch\" }" <<
527+ int(Error::InvalidCredentials);
528+
529+ QTest::newRow("bad_authorization_code") <<
530+ "{ \"error\": \"bad_authorization_code\" }" <<
531+ int(Error::InvalidCredentials);
532+
533+ QTest::newRow("invalid_client_credentials") <<
534+ "{ \"error\": \"invalid_client_credentials\" }" <<
535+ int(Error::InvalidCredentials);
536+
537+ QTest::newRow("unauthorized_client") <<
538+ "{ \"error\": \"unauthorized_client\" }" <<
539+ int(Error::NotAuthorized);
540+
541+ QTest::newRow("invalid_assertion") <<
542+ "{ \"error\": \"invalid_assertion\" }" <<
543+ int(Error::InvalidCredentials);
544+
545+ QTest::newRow("unknown_format") <<
546+ "{ \"error\": \"unknown_format\" }" <<
547+ int(Error::InvalidQuery);
548+
549+ QTest::newRow("authorization_expired") <<
550+ "{ \"error\": \"authorization_expired\" }" <<
551+ int(Error::InvalidCredentials);
552+
553+ QTest::newRow("multiple_credentials") <<
554+ "{ \"error\": \"multiple_credentials\" }" <<
555+ int(Error::InvalidQuery);
556+
557+ QTest::newRow("invalid_user_credentials") <<
558+ "{ \"error\": \"invalid_user_credentials\" }" <<
559+ int(Error::InvalidCredentials);
560+}
561+
562+void OAuth2PluginTest::testOAuth2Errors()
563+{
564+ TEST_START
565+
566+ QFETCH(QString, replyContents);
567+ QFETCH(int, expectedErrorCode);
568+
569+ SignOn::UiSessionData info;
570+ OAuth2PluginData data;
571+ data.setHost("localhost");
572+ data.setAuthPath("authorize");
573+ data.setTokenPath("access_token");
574+ data.setClientId("104660106251471");
575+ data.setClientSecret("fa28f40b5a1f8c1d5628963d880636fbkjkjkj");
576+ data.setRedirectUri("http://localhost/resp.html");
577+
578+ QObject::connect(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)),
579+ this, SLOT(result(const SignOn::SessionData&)),
580+ Qt::QueuedConnection);
581+ QObject::connect(m_testPlugin, SIGNAL(error(const SignOn::Error & )),
582+ this, SLOT(pluginError(const SignOn::Error &)),
583+ Qt::QueuedConnection);
584+ QObject::connect(m_testPlugin, SIGNAL(userActionRequired(const SignOn::UiSessionData&)),
585+ this, SLOT(uiRequest(const SignOn::UiSessionData&)),
586+ Qt::QueuedConnection);
587+ QTimer::singleShot(10*1000, &m_loop, SLOT(quit()));
588+
589+ TestNetworkAccessManager *nam = new TestNetworkAccessManager;
590+ m_testPlugin->m_networkAccessManager = nam;
591+ TestNetworkReply *reply = new TestNetworkReply(this);
592+ reply->setStatusCode(401);
593+ reply->setContentType("application/json");
594+ reply->setContent(replyContents.toUtf8());
595+ nam->setNextReply(reply);
596+
597+ m_testPlugin->process(data, QString("web_server"));
598+ m_loop.exec();
599+
600+ info.setUrlResponse("http://localhost/resp.html?code=c0d3");
601+ m_testPlugin->userActionFinished(info);
602+ m_loop.exec();
603+
604+ QCOMPARE(m_error.type(), expectedErrorCode);
605+
606+ delete nam;
607+
608+ TEST_DONE
609+}
610+
611+void OAuth2PluginTest::testRefreshToken()
612+{
613+ TEST_START
614+
615+ SignOn::UiSessionData info;
616+ OAuth2PluginData data;
617+ data.setHost("localhost");
618+ data.setAuthPath("authorize");
619+ data.setTokenPath("access_token");
620+ data.setClientId("104660106251471");
621+ data.setClientSecret("fa28f40b5a1f8c1d5628963d880636fbkjkjkj");
622+ data.setRedirectUri("http://localhost/resp.html");
623+
624+ /* Pretend that we have stored an expired access token, but have a refresh
625+ * token */
626+ QVariantMap tokens;
627+ QVariantMap token;
628+ token.insert("Token", QLatin1String("tokenfromtest"));
629+ token.insert("timestamp", QDateTime::currentDateTime().toTime_t() - 10000);
630+ token.insert("Expiry", 1000);
631+ token.insert("refresh_token", QString("r3fr3sh"));
632+ tokens.insert(data.ClientId(), QVariant::fromValue(token));
633+ data.m_data.insert("Tokens", tokens);
634+
635+ QObject::connect(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)),
636+ this, SLOT(result(const SignOn::SessionData&)),
637+ Qt::QueuedConnection);
638+ QObject::connect(m_testPlugin, SIGNAL(error(const SignOn::Error & )),
639+ this, SLOT(pluginError(const SignOn::Error &)),
640+ Qt::QueuedConnection);
641+ QObject::connect(m_testPlugin, SIGNAL(userActionRequired(const SignOn::UiSessionData&)),
642+ this, SLOT(uiRequest(const SignOn::UiSessionData&)),
643+ Qt::QueuedConnection);
644+ QTimer::singleShot(10*1000, &m_loop, SLOT(quit()));
645+
646+ TestNetworkAccessManager *nam = new TestNetworkAccessManager;
647+ m_testPlugin->m_networkAccessManager = nam;
648+ TestNetworkReply *reply = new TestNetworkReply(this);
649+ reply->setStatusCode(200);
650+ reply->setContentType("application/json");
651+ reply->setContent("{ \"access_token\":\"n3w-t0k3n\", \"expires_in\": 3600 }");
652+ nam->setNextReply(reply);
653+
654+ m_testPlugin->process(data, QString("web_server"));
655+ m_loop.exec();
656+
657+ QCOMPARE(m_error.type(), -1);
658+ QCOMPARE(nam->m_lastRequest.url(), QUrl("https://localhost/access_token"));
659+ QCOMPARE(QString::fromUtf8(nam->m_lastRequestData),
660+ QString("grant_type=refresh_token&refresh_token=r3fr3sh"));
661+
662+ QVariantMap expectedResponse;
663+ expectedResponse.insert("AccessToken", "n3w-t0k3n");
664+ expectedResponse.insert("ExpiresIn", 3600);
665+ expectedResponse.insert("RefreshToken", QString());
666+ qDebug() << "got response" << m_response.toMap();
667+ qDebug() << "expected" << expectedResponse;
668+ QCOMPARE(m_response.toMap(), expectedResponse);
669+
670+ delete nam;
671+
672+ TEST_DONE
673+}
674+
675+void OAuth2PluginTest::testClientAuthentication_data()
676+{
677+ QTest::addColumn<QString>("clientSecret");
678+ QTest::addColumn<bool>("forceAuthViaRequestBody");
679+ QTest::addColumn<QString>("postContents");
680+ QTest::addColumn<QString>("postAuthorization");
681+
682+ QTest::newRow("no secret, std auth") <<
683+ "" << false <<
684+ "grant_type=authorization_code&code=c0d3"
685+ "&redirect_uri=http://localhost/resp.html&client_id=104660106251471" <<
686+ "";
687+ QTest::newRow("no secret, auth in body") <<
688+ "" << true <<
689+ "grant_type=authorization_code&code=c0d3"
690+ "&redirect_uri=http://localhost/resp.html&client_id=104660106251471" <<
691+ "";
692+
693+ QTest::newRow("with secret, std auth") <<
694+ "s3cr3t" << false <<
695+ "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" <<
696+ "Basic MTA0NjYwMTA2MjUxNDcxOnMzY3IzdA==";
697+ QTest::newRow("with secret, auth in body") <<
698+ "s3cr3t" << true <<
699+ "grant_type=authorization_code&code=c0d3"
700+ "&redirect_uri=http://localhost/resp.html"
701+ "&client_id=104660106251471&client_secret=s3cr3t" <<
702+ "";
703+}
704+
705+void OAuth2PluginTest::testClientAuthentication()
706+{
707+ TEST_START
708+
709+ QFETCH(QString, clientSecret);
710+ QFETCH(bool, forceAuthViaRequestBody);
711+ QFETCH(QString, postContents);
712+ QFETCH(QString, postAuthorization);
713+
714+ SignOn::UiSessionData info;
715+ OAuth2PluginData data;
716+ data.setHost("localhost");
717+ data.setAuthPath("authorize");
718+ data.setTokenPath("access_token");
719+ data.setClientId("104660106251471");
720+ data.setClientSecret(clientSecret);
721+ data.setRedirectUri("http://localhost/resp.html");
722+ data.setForceClientAuthViaRequestBody(forceAuthViaRequestBody);
723+
724+ QObject::connect(m_testPlugin, SIGNAL(result(const SignOn::SessionData&)),
725+ this, SLOT(result(const SignOn::SessionData&)),
726+ Qt::QueuedConnection);
727+ QObject::connect(m_testPlugin, SIGNAL(error(const SignOn::Error & )),
728+ this, SLOT(pluginError(const SignOn::Error &)),
729+ Qt::QueuedConnection);
730+ QObject::connect(m_testPlugin, SIGNAL(userActionRequired(const SignOn::UiSessionData&)),
731+ this, SLOT(uiRequest(const SignOn::UiSessionData&)),
732+ Qt::QueuedConnection);
733+ QTimer::singleShot(10*1000, &m_loop, SLOT(quit()));
734+
735+ TestNetworkAccessManager *nam = new TestNetworkAccessManager;
736+ m_testPlugin->m_networkAccessManager = nam;
737+ TestNetworkReply *reply = new TestNetworkReply(this);
738+ reply->setStatusCode(200);
739+ reply->setContentType("application/json");
740+ reply->setContent("{ \"access_token\":\"t0k3n\", \"expires_in\": 3600 }");
741+ nam->setNextReply(reply);
742+
743+ m_testPlugin->process(data, QString("web_server"));
744+ m_loop.exec();
745+
746+ info.setUrlResponse("http://localhost/resp.html?code=c0d3");
747+ m_testPlugin->userActionFinished(info);
748+ m_loop.exec();
749+
750+ QCOMPARE(m_error.type(), -1);
751+ QCOMPARE(nam->m_lastRequest.url(), QUrl("https://localhost/access_token"));
752+ QCOMPARE(QString::fromUtf8(nam->m_lastRequestData), postContents);
753+ QCOMPARE(QString::fromUtf8(nam->m_lastRequest.rawHeader("Authorization")),
754+ postAuthorization);
755+
756+ delete nam;
757
758 TEST_DONE
759 }
760@@ -561,4 +1051,4 @@
761 //end test cases
762
763 QTEST_MAIN(OAuth2PluginTest)
764-
765+#include "oauth2plugintest.moc"
766
767=== modified file 'tests/oauth2plugintest.h'
768--- tests/oauth2plugintest.h 2013-06-04 05:04:43 +0000
769+++ tests/oauth2plugintest.h 2014-09-12 09:09:50 +0000
770@@ -56,7 +56,13 @@
771 void testPluginProcess();
772 void testPluginHmacSha1Process();
773 void testPluginUseragentUserActionFinished();
774+ void testPluginWebserverUserActionFinished_data();
775 void testPluginWebserverUserActionFinished();
776+ void testOAuth2Errors_data();
777+ void testOAuth2Errors();
778+ void testRefreshToken();
779+ void testClientAuthentication_data();
780+ void testClientAuthentication();
781
782 private:
783 Plugin *m_testPlugin;

Subscribers

People subscribed via source and target branches

to all changes: