Merge lp:~online-accounts/signon-plugin-oauth2/packaging into lp:signon-plugin-oauth2

Proposed by Alberto Mardegan on 2015-01-28
Status: Merged
Approved by: Timo Jyrinki on 2015-02-02
Approved revision: no longer in the source branch.
Merged at revision: 70
Proposed branch: lp:~online-accounts/signon-plugin-oauth2/packaging
Merge into: lp:signon-plugin-oauth2
Diff against target: 268 lines (+110/-59)
6 files modified
common-vars.pri (+1/-1)
debian/changelog (+11/-0)
src/oauth2plugin.cpp (+68/-54)
src/oauth2plugin.h (+4/-2)
tests/oauth2plugintest.cpp (+24/-0)
tests/tests.pro (+2/-2)
To merge this branch: bzr merge lp:~online-accounts/signon-plugin-oauth2/packaging
Reviewer Review Type Date Requested Status
David Barth (community) 2015-01-28 Approve on 2015-01-28
PS Jenkins bot continuous-integration Approve on 2015-01-28
Review via email: mp+247826@code.launchpad.net

Commit Message

New upstream release

- OAuth2: implement a fallback mechanism when parsing replies
  (LP: #1415376)

Description of the Change

New upstream release

- OAuth2: implement a fallback mechanism when parsing replies
  (LP: #1415376)

To post a comment you must log in.
David Barth (dbarth) wrote :

How is the version bump and extra functions affecting binary compatibility?

David Barth (dbarth) wrote :

Fine for submitting to vivid.

review: Approve
70. By Alberto Mardegan on 2015-01-28

New upstream release

- OAuth2: implement a fallback mechanism when parsing replies
  (LP: #1415376) Fixes: #1415376
Approved by: PS Jenkins bot, David Barth

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 2014-09-11 09:32:32 +0000
3+++ common-vars.pri 2015-01-28 12:16:47 +0000
4@@ -13,7 +13,7 @@
5 # Project version
6 # remember to update debian/* files if you changes this
7 #-----------------------------------------------------------------------------
8-PROJECT_VERSION = 0.20
9+PROJECT_VERSION = 0.21
10
11 #-----------------------------------------------------------------------------
12 # Library version
13
14=== modified file 'debian/changelog'
15--- debian/changelog 2014-11-10 09:45:53 +0000
16+++ debian/changelog 2015-01-28 12:16:47 +0000
17@@ -1,3 +1,14 @@
18+signon-plugin-oauth2 (0.21-0ubuntu1) UNRELEASED; urgency=medium
19+
20+ * New upstream release
21+ - Add ForceTokenRefresh flag for forcing a new token
22+ - OAuth2: implement a fallback mechanism when parsing replies
23+ (LP: #1415376)
24+ - Fixes build with -Werror=unused-variable
25+ - Improve test coverage
26+
27+ -- Alberto Mardegan <alberto.mardegan@canonical.com> Wed, 28 Jan 2015 13:09:28 +0100
28+
29 signon-plugin-oauth2 (0.20+15.04.20141110-0ubuntu1) vivid; urgency=low
30
31 [ Ubuntu daily release ]
32
33=== modified file 'src/oauth2plugin.cpp'
34--- src/oauth2plugin.cpp 2014-10-31 08:09:57 +0000
35+++ src/oauth2plugin.cpp 2015-01-28 12:16:47 +0000
36@@ -430,6 +430,47 @@
37 }
38 }
39
40+QVariantMap OAuth2Plugin::parseReply(const QByteArray &contentType,
41+ const QByteArray &replyContent)
42+{
43+ typedef QVariantMap (OAuth2Plugin::*Parser)(const QByteArray &replyContent);
44+ Parser preferredParser;
45+ Parser fallbackParser;
46+
47+ QVariantMap map;
48+
49+ // Handling application/json content type
50+ if (contentType.startsWith(CONTENT_APP_JSON)) {
51+ TRACE() << "application/json content received";
52+ preferredParser = &OAuth2Plugin::parseJSONReply;
53+ fallbackParser = &OAuth2Plugin::parseTextReply;
54+ }
55+ // Added for facebook Graph API's (handling text/plain content type)
56+ else if (contentType.startsWith(CONTENT_TEXT_PLAIN) ||
57+ contentType.startsWith(CONTENT_APP_URLENCODED)) {
58+ TRACE() << contentType << "content received";
59+ preferredParser = &OAuth2Plugin::parseTextReply;
60+ fallbackParser = &OAuth2Plugin::parseJSONReply;
61+ } else {
62+ TRACE() << "Unsupported content type received: " << contentType;
63+ Q_EMIT error(Error(Error::OperationFailed,
64+ QString("Unsupported content type received")));
65+ return map;
66+ }
67+
68+ map = (this->*preferredParser)(replyContent);
69+ if (Q_UNLIKELY(map.isEmpty())) {
70+ TRACE() << "Parse failed, trying fallback parser";
71+ map = (this->*fallbackParser)(replyContent);
72+ if (Q_UNLIKELY(map.isEmpty())) {
73+ TRACE() << "Parse failed";
74+ Q_EMIT error(Error(Error::NotAuthorized,
75+ QString("No access token found")));
76+ }
77+ }
78+ return map;
79+}
80+
81 // Method to handle responses for OAuth 2.0 requests
82 void OAuth2Plugin::serverReply(QNetworkReply *reply)
83 {
84@@ -446,55 +487,30 @@
85
86 // Handling 200 OK response (HTTP_STATUS_OK) WITH content
87 if (reply->hasRawHeader(CONTENT_TYPE)) {
88-
89- // Handling application/json content type
90- if (reply->rawHeader(CONTENT_TYPE).startsWith(CONTENT_APP_JSON)) {
91- TRACE()<< "application/json content received";
92- QVariantMap map = parseJSONReply(replyContent);
93- QByteArray accessToken = map["access_token"].toByteArray();
94- QVariant expiresIn = map["expires_in"];
95- QByteArray refreshToken = map["refresh_token"].toByteArray();
96-
97- if (accessToken.isEmpty()) {
98- TRACE()<< "Access token is empty";
99- emit error(Error(Error::NotAuthorized,
100- QString("Access token is empty")));
101- }
102- else {
103- OAuth2PluginTokenData response;
104- response.setAccessToken(accessToken);
105- response.setRefreshToken(refreshToken);
106- response.setExpiresIn(expiresIn.toInt());
107- storeResponse(response);
108- emit result(response);
109- }
110- }
111- // Added to test with facebook Graph API's (handling text/plain content type)
112- else if (reply->rawHeader(CONTENT_TYPE).startsWith(CONTENT_TEXT_PLAIN) ||
113- reply->rawHeader(CONTENT_TYPE).startsWith(CONTENT_APP_URLENCODED)) {
114- TRACE()<< reply->rawHeader(CONTENT_TYPE) << "content received";
115- QMap<QString,QString> map = parseTextReply(replyContent);
116- QByteArray accessToken = map["access_token"].toAscii();
117- QByteArray expiresIn = map["expires"].toAscii();
118- QByteArray refreshToken = map["refresh_token"].toAscii();
119-
120- if (accessToken.isEmpty()) {
121- TRACE()<< "Access token is empty";
122- emit error(Error(Error::NotAuthorized,
123- QString("Access token is empty")));
124- }
125- else {
126- OAuth2PluginTokenData response;
127- response.setAccessToken(accessToken);
128- response.setRefreshToken(refreshToken);
129- response.setExpiresIn(expiresIn.toInt());
130- storeResponse(response);
131- emit result(response);
132- }
133- }
134- else {
135- TRACE()<< "Unsupported content type received: " << reply->rawHeader(CONTENT_TYPE);
136- emit error(Error(Error::OperationFailed, QString("Unsupported content type received")));
137+ QVariantMap map = parseReply(reply->rawHeader(CONTENT_TYPE), replyContent);
138+ if (Q_UNLIKELY(map.isEmpty())) {
139+ // The error has already been delivered
140+ return;
141+ }
142+ QByteArray accessToken = map["access_token"].toByteArray();
143+ int expiresIn = map["expires_in"].toInt();
144+ if (expiresIn == 0) {
145+ // Facebook uses just "expires" as key
146+ expiresIn = map["expires"].toInt();
147+ }
148+ QByteArray refreshToken = map["refresh_token"].toByteArray();
149+
150+ if (accessToken.isEmpty()) {
151+ TRACE()<< "Access token is empty";
152+ Q_EMIT error(Error(Error::NotAuthorized,
153+ QString("Access token is empty")));
154+ } else {
155+ OAuth2PluginTokenData response;
156+ response.setAccessToken(accessToken);
157+ response.setRefreshToken(refreshToken);
158+ response.setExpiresIn(expiresIn);
159+ storeResponse(response);
160+ emit result(response);
161 }
162 }
163 // Handling 200 OK response (HTTP_STATUS_OK) WITHOUT content
164@@ -567,8 +583,6 @@
165
166 void OAuth2Plugin::refreshOAuth2Token(const QString &refreshToken)
167 {
168- Q_D(OAuth2Plugin);
169-
170 TRACE() << refreshToken;
171 QUrl url;
172 url.addQueryItem(GRANT_TYPE, REFRESH_TOKEN);
173@@ -648,7 +662,7 @@
174 TRACE() << d->m_tokens;
175 }
176
177-const QVariantMap OAuth2Plugin::parseJSONReply(const QByteArray &reply)
178+QVariantMap OAuth2Plugin::parseJSONReply(const QByteArray &reply)
179 {
180 TRACE();
181 bool ok = false;
182@@ -666,10 +680,10 @@
183 return QVariantMap();
184 }
185
186-const QMap<QString, QString> OAuth2Plugin::parseTextReply(const QByteArray &reply)
187+QVariantMap OAuth2Plugin::parseTextReply(const QByteArray &reply)
188 {
189 TRACE();
190- QMap<QString, QString> map;
191+ QVariantMap map;
192 QList<QByteArray> items = reply.split('&');
193 foreach (QByteArray item, items) {
194 int idx = item.indexOf("=");
195
196=== modified file 'src/oauth2plugin.h'
197--- src/oauth2plugin.h 2014-09-09 13:47:22 +0000
198+++ src/oauth2plugin.h 2015-01-28 12:16:47 +0000
199@@ -75,8 +75,10 @@
200 void sendOAuth2PostRequest(QUrl &postData,
201 GrantType::e grantType);
202 void storeResponse(const OAuth2PluginTokenData &response);
203- const QVariantMap parseJSONReply(const QByteArray &reply);
204- const QMap<QString, QString> parseTextReply(const QByteArray &reply);
205+ QVariantMap parseReply(const QByteArray &contentType,
206+ const QByteArray &replyContent);
207+ QVariantMap parseJSONReply(const QByteArray &reply);
208+ QVariantMap parseTextReply(const QByteArray &reply);
209 void handleOAuth2Error(const QByteArray &reply);
210 QString urlEncode(QString strData);
211
212
213=== modified file 'tests/oauth2plugintest.cpp'
214--- tests/oauth2plugintest.cpp 2014-10-31 08:09:57 +0000
215+++ tests/oauth2plugintest.cpp 2015-01-28 12:16:47 +0000
216@@ -847,6 +847,16 @@
217 "something else" <<
218 QVariantMap();
219
220+ QTest::newRow("reply code, no access token") <<
221+ "http://localhost/resp.html?code=c0d3" <<
222+ int(Error::NotAuthorized) <<
223+ "https://localhost/access_token" <<
224+ "grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html" <<
225+ int(200) <<
226+ "application/json" <<
227+ "{ \"expires_in\": 3600 }" <<
228+ QVariantMap();
229+
230 QTest::newRow("reply code, no content type") <<
231 "http://localhost/resp.html?code=c0d3" <<
232 int(Error::OperationFailed) <<
233@@ -934,6 +944,20 @@
234 "application/json" <<
235 "{ \"access_token\":\"t0k3n\", \"expires_in\": 3600 }" <<
236 response;
237+
238+ response.clear();
239+ response.insert("AccessToken", "t0k3n");
240+ response.insert("ExpiresIn", int(3600));
241+ response.insert("RefreshToken", QString());
242+ QTest::newRow("username-password, valid token, wrong content type") <<
243+ "http://localhost/resp.html?username=us3r&password=s3cr3t" <<
244+ int(-1) <<
245+ "https://localhost/access_token" <<
246+ "grant_type=user_basic&username=us3r&password=s3cr3t" <<
247+ int(200) <<
248+ "text/plain" <<
249+ "{ \"access_token\":\"t0k3n\", \"expires_in\": 3600 }" <<
250+ response;
251 }
252
253 void OAuth2PluginTest::testPluginWebserverUserActionFinished()
254
255=== modified file 'tests/tests.pro'
256--- tests/tests.pro 2014-10-31 13:34:21 +0000
257+++ tests/tests.pro 2015-01-28 12:16:47 +0000
258@@ -36,8 +36,8 @@
259 libsignon-qt5
260 }
261
262-target.path = /usr/bin
263-testsuite.path = /usr/share/$$TARGET
264+target.path = $${INSTALL_PREFIX}/bin
265+testsuite.path = $${INSTALL_PREFIX}/share/$$TARGET
266 testsuite.files = tests.xml
267 INSTALLS += target \
268 testsuite

Subscribers

No one subscribed via source and target branches