Merge lp:~mardy/signon/rtm-fixes into lp:~online-accounts/signon/rtm-14.09
- rtm-fixes
- Merge into rtm-14.09
Proposed by
Alberto Mardegan
Status: | Approved | ||||
---|---|---|---|---|---|
Approved by: | David Barth | ||||
Approved revision: | 623 | ||||
Proposed branch: | lp:~mardy/signon/rtm-fixes | ||||
Merge into: | lp:~online-accounts/signon/rtm-14.09 | ||||
Diff against target: |
909 lines (+506/-196) 17 files modified
debian/changelog (+6/-0) lib/plugins/SignOn/uisessiondata_priv.h (+2/-0) src/signond/accesscontrolmanagerhelper.cpp (+1/-1) src/signond/signondaemonadaptor.cpp (+1/-1) src/signond/signonidentity.cpp (+8/-30) src/signond/signonidentityinfo.cpp (+12/-0) src/signond/signonidentityinfo.h (+2/-0) src/signond/signonsessioncore.cpp (+6/-2) tests/libsignon-qt-tests/ssotestclient.cpp (+127/-161) tests/libsignon-qt-tests/ssotestclient.h (+1/-1) tests/libsignon-qt-tests/testauthsession.cpp (+1/-0) tests/signond-tests/.gitignore (+1/-0) tests/signond-tests/signond-tests.pri (+2/-0) tests/signond-tests/signond-tests.pro (+1/-0) tests/signond-tests/timeouts.cpp (+2/-0) tests/signond-tests/tst_access_control_manager_helper.cpp (+320/-0) tests/signond-tests/tst_access_control_manager_helper.pro (+13/-0) |
||||
To merge this branch: | bzr merge lp:~mardy/signon/rtm-fixes | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
David Barth (community) | Approve | ||
Review via email: mp+243137@code.launchpad.net |
Commit message
Don't bypass the ACL if the identity has no owner
This includes some fixes and refactoring to the unit tests.
Description of the change
Don't bypass the ACL if the identity has no owner
This includes some fixes and refactoring to the unit tests.
To post a comment you must log in.
lp:~mardy/signon/rtm-fixes
updated
- 623. By Alberto Mardegan
-
Fix changelog
Unmerged revisions
- 623. By Alberto Mardegan
-
Fix changelog
- 622. By Alberto Mardegan
-
Don't bypass the ACL if the identity has no owner
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'debian/changelog' |
2 | --- debian/changelog 2014-10-06 07:57:10 +0000 |
3 | +++ debian/changelog 2014-11-28 12:00:40 +0000 |
4 | @@ -1,3 +1,9 @@ |
5 | +signon (8.57+14.10.20141006-0ubuntu2) UNRELEASED; urgency=medium |
6 | + |
7 | + * Don't bypass the ACL if the identity has no owner. (LP: #1392380) |
8 | + |
9 | + -- Alberto Mardegan <alberto.mardegan@canonical.com> Fri, 28 Nov 2014 13:54:25 +0200 |
10 | + |
11 | signon (8.57+14.10.20141006-0ubuntu1) utopic; urgency=low |
12 | |
13 | [ Alberto Mardegan ] |
14 | |
15 | === modified file 'lib/plugins/SignOn/uisessiondata_priv.h' |
16 | --- lib/plugins/SignOn/uisessiondata_priv.h 2014-10-02 13:57:24 +0000 |
17 | +++ lib/plugins/SignOn/uisessiondata_priv.h 2014-11-28 12:00:40 +0000 |
18 | @@ -68,6 +68,8 @@ |
19 | |
20 | /* Process ID of the client application */ |
21 | #define SSOUI_KEY_PID QLatin1String("Pid") |
22 | +/* Application ID (security context) of the client application */ |
23 | +#define SSOUI_KEY_APP_ID QLatin1String("AppId") |
24 | |
25 | #define SSOUI_KEY_SLOT_ACCEPT "accept" |
26 | #define SSOUI_KEY_SLOT_REJECT "reject" |
27 | |
28 | === modified file 'src/signond/accesscontrolmanagerhelper.cpp' |
29 | --- src/signond/accesscontrolmanagerhelper.cpp 2013-08-20 08:01:44 +0000 |
30 | +++ src/signond/accesscontrolmanagerhelper.cpp 2014-11-28 12:00:40 +0000 |
31 | @@ -89,7 +89,7 @@ |
32 | |
33 | IdentityOwnership ownership = |
34 | isPeerOwnerOfIdentity(peerConnection, peerMessage, identityId); |
35 | - if (ownership == ApplicationIsOwner || ownership == IdentityDoesNotHaveOwner) |
36 | + if (ownership == ApplicationIsOwner) |
37 | return true; |
38 | |
39 | if (acl.isEmpty()) |
40 | |
41 | === modified file 'src/signond/signondaemonadaptor.cpp' |
42 | --- src/signond/signondaemonadaptor.cpp 2013-08-20 08:01:44 +0000 |
43 | +++ src/signond/signondaemonadaptor.cpp 2014-11-28 12:00:40 +0000 |
44 | @@ -172,7 +172,7 @@ |
45 | |
46 | /* Access Control */ |
47 | if (id != SIGNOND_NEW_IDENTITY) { |
48 | - if (!acm->isPeerAllowedToUseAuthSession(conn, msg, id)) { |
49 | + if (!acm->isPeerAllowedToUseIdentity(conn, msg, id)) { |
50 | SignOn::AccessReply *reply = |
51 | acm->requestAccessToIdentity(conn, msg, id); |
52 | /* If the request is accepted, we'll need the method name ("type") |
53 | |
54 | === modified file 'src/signond/signonidentity.cpp' |
55 | --- src/signond/signonidentity.cpp 2014-08-21 07:33:45 +0000 |
56 | +++ src/signond/signonidentity.cpp 2014-11-28 12:00:40 +0000 |
57 | @@ -471,41 +471,19 @@ |
58 | MethodMap methods = container.isValid() ? |
59 | qdbus_cast<MethodMap>(container.value<QDBusArgument>()) : MethodMap(); |
60 | |
61 | - //Add creator to owner list if it has AID |
62 | - QStringList ownerList = |
63 | - info.value(SIGNOND_IDENTITY_INFO_OWNER).toStringList(); |
64 | - if (!appId.isNull()) |
65 | - ownerList.append(appId); |
66 | - |
67 | if (m_pInfo == 0) { |
68 | m_pInfo = new SignonIdentityInfo(info); |
69 | m_pInfo->setMethods(methods); |
70 | + //Add creator to owner list if it has AID |
71 | + QStringList ownerList = |
72 | + info.value(SIGNOND_IDENTITY_INFO_OWNER).toStringList(); |
73 | + if (!appId.isNull()) { |
74 | + ownerList.append(appId); |
75 | + } |
76 | m_pInfo->setOwnerList(ownerList); |
77 | } else { |
78 | - if (info.contains(SIGNOND_IDENTITY_INFO_SECRET)) { |
79 | - QString secret = info.value(SIGNOND_IDENTITY_INFO_SECRET).toString(); |
80 | - m_pInfo->setPassword(secret); |
81 | - } |
82 | - bool storeSecret = |
83 | - info.value(SIGNOND_IDENTITY_INFO_STORESECRET).toBool(); |
84 | - QString userName = |
85 | - info.value(SIGNOND_IDENTITY_INFO_USERNAME).toString(); |
86 | - QString caption = |
87 | - info.value(SIGNOND_IDENTITY_INFO_CAPTION).toString(); |
88 | - QStringList realms = |
89 | - info.value(SIGNOND_IDENTITY_INFO_REALMS).toStringList(); |
90 | - QStringList accessControlList = |
91 | - info.value(SIGNOND_IDENTITY_INFO_ACL).toStringList(); |
92 | - int type = info.value(SIGNOND_IDENTITY_INFO_TYPE).toInt(); |
93 | - |
94 | - m_pInfo->setStorePassword(storeSecret); |
95 | - m_pInfo->setUserName(userName); |
96 | - m_pInfo->setCaption(caption); |
97 | - m_pInfo->setMethods(methods); |
98 | - m_pInfo->setRealms(realms); |
99 | - m_pInfo->setAccessControlList(accessControlList); |
100 | - m_pInfo->setOwnerList(ownerList); |
101 | - m_pInfo->setType(type); |
102 | + SignonIdentityInfo newInfo(info); |
103 | + m_pInfo->update(newInfo); |
104 | } |
105 | |
106 | m_id = storeCredentials(*m_pInfo); |
107 | |
108 | === modified file 'src/signond/signonidentityinfo.cpp' |
109 | --- src/signond/signonidentityinfo.cpp 2013-11-26 14:23:18 +0000 |
110 | +++ src/signond/signonidentityinfo.cpp 2014-11-28 12:00:40 +0000 |
111 | @@ -60,6 +60,18 @@ |
112 | return *this; |
113 | } |
114 | |
115 | +void SignonIdentityInfo::update(const SignonIdentityInfo &info) |
116 | +{ |
117 | + QMapIterator<QString, QVariant> it(info); |
118 | + while (it.hasNext()) { |
119 | + it.next(); |
120 | + // We don't allow updating the ID |
121 | + if (it.key() == SIGNOND_IDENTITY_INFO_ID) continue; |
122 | + |
123 | + insert(it.key(), it.value()); |
124 | + } |
125 | +} |
126 | + |
127 | bool SignonIdentityInfo::checkMethodAndMechanism(const QString &method, |
128 | const QString &mechanism, |
129 | QString &allowedMechanism) |
130 | |
131 | === modified file 'src/signond/signonidentityinfo.h' |
132 | --- src/signond/signonidentityinfo.h 2013-11-26 14:23:18 +0000 |
133 | +++ src/signond/signonidentityinfo.h 2014-11-28 12:00:40 +0000 |
134 | @@ -46,6 +46,8 @@ |
135 | |
136 | const QVariantMap toMap() const; |
137 | |
138 | + void update(const SignonIdentityInfo &info); |
139 | + |
140 | void setNew() { setId(SIGNOND_NEW_IDENTITY); } |
141 | bool isNew() const { return id() == SIGNOND_NEW_IDENTITY; } |
142 | void setId(quint32 id) { insert(SIGNOND_IDENTITY_INFO_ID, id); } |
143 | |
144 | === modified file 'src/signond/signonsessioncore.cpp' |
145 | --- src/signond/signonsessioncore.cpp 2014-10-02 13:57:24 +0000 |
146 | +++ src/signond/signonsessioncore.cpp 2014-11-28 12:00:40 +0000 |
147 | @@ -705,8 +705,12 @@ |
148 | request.m_params[SSOUI_KEY_CLIENT_DATA] = m_clientData; |
149 | request.m_params[SSOUI_KEY_METHOD] = m_method; |
150 | request.m_params[SSOUI_KEY_MECHANISM] = request.m_mechanism; |
151 | - request.m_params[SSOUI_KEY_PID] = |
152 | - AccessControlManagerHelper::instance()->pidOfPeer(request.m_conn, |
153 | + /* Pass some data about the requesting client */ |
154 | + AccessControlManagerHelper *acm = |
155 | + AccessControlManagerHelper::instance(); |
156 | + request.m_params[SSOUI_KEY_PID] = acm->pidOfPeer(request.m_conn, |
157 | + request.m_msg); |
158 | + request.m_params[SSOUI_KEY_APP_ID] = acm->appIdOfPeer(request.m_conn, |
159 | request.m_msg); |
160 | |
161 | CredentialsAccessManager *camManager = |
162 | |
163 | === modified file 'tests/libsignon-qt-tests/ssotestclient.cpp' |
164 | --- tests/libsignon-qt-tests/ssotestclient.cpp 2013-11-22 14:46:01 +0000 |
165 | +++ tests/libsignon-qt-tests/ssotestclient.cpp 2014-11-28 12:00:40 +0000 |
166 | @@ -257,16 +257,137 @@ |
167 | TEST_DONE |
168 | } |
169 | |
170 | +void SsoTestClient::storeCredentials_data() |
171 | +{ |
172 | + QTest::addColumn<bool>("addMethods"); |
173 | + |
174 | + QTest::newRow("with methods") << true; |
175 | + QTest::newRow("without methods") << false; |
176 | +} |
177 | + |
178 | void SsoTestClient::storeCredentials() |
179 | { |
180 | TEST_START |
181 | |
182 | - if (!testAddingNewCredentials()) { |
183 | - QFAIL("Adding new credentials test failed."); |
184 | - } |
185 | - |
186 | - if (!testUpdatingCredentials()) { |
187 | - QFAIL("Updating existing credentials test failed."); |
188 | + QFETCH(bool, addMethods); |
189 | + |
190 | + m_identityResult.reset(); |
191 | + |
192 | + QMap<MethodName, MechanismsList> methods; |
193 | + if (addMethods) { |
194 | + methods.insert("dummy", QStringList() << "mech1" << "mech2" << "mech3"); |
195 | + methods.insert("dummy1", QStringList() << "mech11" << "mech12" << "mech13"); |
196 | + } |
197 | + IdentityInfo info("TEST_CAPTION", "TEST_USERNAME", methods); |
198 | + info.setSecret("TEST_SECRET"); |
199 | + info.setRealms(QStringList() << "TEST_REALM1" << "TEST_REALM2"); |
200 | + info.setAccessControlList(QStringList() << "*"); |
201 | + |
202 | + Identity *identity = Identity::newIdentity(info, this); |
203 | + |
204 | + QEventLoop loop; |
205 | + |
206 | + connect(identity, SIGNAL(error(const SignOn::Error &)), |
207 | + &m_identityResult, SLOT(error(const SignOn::Error &))); |
208 | + |
209 | + connect(identity, SIGNAL(credentialsStored(const quint32)), |
210 | + &m_identityResult, SLOT(credentialsStored(const quint32))); |
211 | + connect(&m_identityResult, SIGNAL(testCompleted()), &loop, SLOT(quit())); |
212 | + |
213 | + identity->storeCredentials(); |
214 | + |
215 | + QTimer::singleShot(test_timeout, &loop, SLOT(quit())); |
216 | + loop.exec(); |
217 | + |
218 | + if (m_identityResult.m_responseReceived == |
219 | + TestIdentityResult::InexistentResp) { |
220 | + QFAIL("A response was not received."); |
221 | + } |
222 | + |
223 | + if (m_identityResult.m_responseReceived == TestIdentityResult::NormalResp) { |
224 | + QCOMPARE(m_identityResult.m_id, identity->id()); |
225 | + |
226 | + Identity *existingIdentity = |
227 | + Identity::existingIdentity(m_identityResult.m_id, this); |
228 | + QVERIFY2(existingIdentity != NULL, |
229 | + "Could not create existing identity. '0' ID provided?"); |
230 | + connect(existingIdentity, SIGNAL(info(const SignOn::IdentityInfo &)), |
231 | + &m_identityResult, SLOT(info(const SignOn::IdentityInfo &))); |
232 | + |
233 | + existingIdentity->queryInfo(); |
234 | + |
235 | + QTimer::singleShot(test_timeout, &loop, SLOT(quit())); |
236 | + loop.exec(); |
237 | + delete existingIdentity; |
238 | + |
239 | + if (!TestIdentityResult::compareIdentityInfos(m_identityResult.m_idInfo, |
240 | + info)) { |
241 | + QFAIL("Compared identity infos are not the same."); |
242 | + } |
243 | + } else { |
244 | + QString codeStr = errCodeAsStr(m_identityResult.m_error); |
245 | + qDebug() << "Error reply: " << m_serviceResult.m_errMsg |
246 | + << ".\nError code: " << codeStr; |
247 | + QFAIL("Error received"); |
248 | + } |
249 | + |
250 | + // Test update credentials functionality |
251 | + |
252 | + Identity *existingIdentity = Identity::existingIdentity(m_identityResult.m_id, this); |
253 | + QVERIFY2(existingIdentity != NULL, |
254 | + "Could not create existing identity. '0' ID provided?"); |
255 | + |
256 | + methods.clear(); |
257 | + if (addMethods) { |
258 | + methods.insert("dummy1", QStringList() << "mech11" << "mech12" << "mech13"); |
259 | + methods.insert("dummy2", QStringList() << "mech1_updated" << "mech2" << "mech1_updated2"); |
260 | + methods.insert("dummy3", QStringList() << "mech1_updated" << "mech2" << "mech1_updated2"); |
261 | + } |
262 | + |
263 | + IdentityInfo updateInfo("TEST_CAPTION", "TEST_USERNAME_UPDATED", methods); |
264 | + updateInfo.setSecret("TEST_SECRET_YES", false); |
265 | + |
266 | + do |
267 | + { |
268 | + QEventLoop loop; |
269 | + |
270 | + connect(existingIdentity, SIGNAL(error(const SignOn::Error &)), |
271 | + &m_identityResult, SLOT(error(const SignOn::Error &))); |
272 | + |
273 | + connect(existingIdentity, SIGNAL(credentialsStored(const quint32)), |
274 | + &m_identityResult, SLOT(credentialsStored(const quint32))); |
275 | + connect(&m_identityResult, SIGNAL(testCompleted()), &loop, SLOT(quit())); |
276 | + |
277 | + existingIdentity->storeCredentials(updateInfo); |
278 | + qDebug(); |
279 | + QTimer::singleShot(test_timeout, &loop, SLOT(quit())); |
280 | + loop.exec(); |
281 | + } while(0); |
282 | + |
283 | + if (m_identityResult.m_responseReceived == |
284 | + TestIdentityResult::InexistentResp) { |
285 | + QFAIL("A response was not received."); |
286 | + } |
287 | + |
288 | + if (m_identityResult.m_responseReceived == TestIdentityResult::NormalResp) { |
289 | + QEventLoop loop; |
290 | + connect(&m_identityResult, SIGNAL(testCompleted()), &loop, SLOT(quit())); |
291 | + connect(existingIdentity, SIGNAL(info(const SignOn::IdentityInfo &)), |
292 | + &m_identityResult, SLOT(info(const SignOn::IdentityInfo &))); |
293 | + |
294 | + existingIdentity->queryInfo(); |
295 | + QTimer::singleShot(test_timeout, &loop, SLOT(quit())); |
296 | + loop.exec(); |
297 | + |
298 | + qDebug() << "ID:" << existingIdentity->id(); |
299 | + QCOMPARE(m_identityResult.m_idInfo.caption(), updateInfo.caption()); |
300 | + QCOMPARE(m_identityResult.m_idInfo.methods(), updateInfo.methods()); |
301 | + QCOMPARE(m_identityResult.m_idInfo.userName(), updateInfo.userName()); |
302 | + } else { |
303 | + QString codeStr = errCodeAsStr(m_identityResult.m_error); |
304 | + qDebug() << "Error reply: " << m_serviceResult.m_errMsg |
305 | + << ".\nError code: " << codeStr; |
306 | + QFAIL("Error received"); |
307 | } |
308 | |
309 | TEST_DONE |
310 | @@ -566,21 +687,6 @@ |
311 | TEST_DONE |
312 | } |
313 | |
314 | -void SsoTestClient::storeCredentialsWithoutAuthMethodsTest() |
315 | -{ |
316 | - TEST_START |
317 | - |
318 | - if (!testAddingNewCredentials(false)) { |
319 | - QFAIL("Adding new credentials test failed."); |
320 | - } |
321 | - |
322 | - if (!testUpdatingCredentials()) { |
323 | - QFAIL("Updating existing credentials test failed."); |
324 | - } |
325 | - |
326 | - TEST_DONE |
327 | -} |
328 | - |
329 | void SsoTestClient::queryInfo() |
330 | { |
331 | TEST_START |
332 | @@ -1448,146 +1554,6 @@ |
333 | TEST_DONE |
334 | } |
335 | |
336 | -bool SsoTestClient::testAddingNewCredentials(bool addMethods) |
337 | -{ |
338 | - m_identityResult.reset(); |
339 | - |
340 | - QMap<MethodName, MechanismsList> methods; |
341 | - if (addMethods) { |
342 | - methods.insert("dummy", QStringList() << "mech1" << "mech2" << "mech3"); |
343 | - methods.insert("dummy1", QStringList() << "mech11" << "mech12" << "mech13"); |
344 | - } |
345 | - IdentityInfo info("TEST_CAPTION", "TEST_USERNAME", methods); |
346 | - info.setSecret("TEST_SECRET"); |
347 | - info.setRealms(QStringList() << "TEST_REALM1" << "TEST_REALM2"); |
348 | - |
349 | - Identity *identity = Identity::newIdentity(info, this); |
350 | - |
351 | - QEventLoop loop; |
352 | - |
353 | - connect(identity, SIGNAL(error(const SignOn::Error &)), |
354 | - &m_identityResult, SLOT(error(const SignOn::Error &))); |
355 | - |
356 | - connect(identity, SIGNAL(credentialsStored(const quint32)), |
357 | - &m_identityResult, SLOT(credentialsStored(const quint32))); |
358 | - connect(&m_identityResult, SIGNAL(testCompleted()), &loop, SLOT(quit())); |
359 | - |
360 | - identity->storeCredentials(); |
361 | - |
362 | - QTimer::singleShot(test_timeout, &loop, SLOT(quit())); |
363 | - loop.exec(); |
364 | - |
365 | - if (m_identityResult.m_responseReceived == |
366 | - TestIdentityResult::InexistentResp) { |
367 | - qDebug() << "A response was not received."; |
368 | - return false; |
369 | - } |
370 | - |
371 | - if (m_identityResult.m_responseReceived == TestIdentityResult::NormalResp) { |
372 | - if (m_identityResult.m_id != identity->id()) { |
373 | - qDebug() << "Queried identity id does not match with stored data."; |
374 | - return false; |
375 | - } |
376 | - |
377 | - Identity *existingIdentity = |
378 | - Identity::existingIdentity(m_identityResult.m_id, this); |
379 | - if (existingIdentity == NULL) { |
380 | - qDebug() << "Could not create existing identity. '0' ID provided?"; |
381 | - return false; |
382 | - } |
383 | - connect(existingIdentity, SIGNAL(info(const SignOn::IdentityInfo &)), |
384 | - &m_identityResult, SLOT(info(const SignOn::IdentityInfo &))); |
385 | - |
386 | - existingIdentity->queryInfo(); |
387 | - |
388 | - QTimer::singleShot(test_timeout, &loop, SLOT(quit())); |
389 | - loop.exec(); |
390 | - delete existingIdentity; |
391 | - |
392 | - if (!TestIdentityResult::compareIdentityInfos(m_identityResult.m_idInfo, |
393 | - info)) { |
394 | - qDebug() << "Compared identity infos are not the same."; |
395 | - return false; |
396 | - } |
397 | - } else { |
398 | - QString codeStr = errCodeAsStr(m_identityResult.m_error); |
399 | - qDebug() << "Error reply: " << m_serviceResult.m_errMsg |
400 | - << ".\nError code: " << codeStr; |
401 | - return false; |
402 | - } |
403 | - return true; |
404 | -} |
405 | - |
406 | -bool SsoTestClient::testUpdatingCredentials(bool addMethods) |
407 | -{ |
408 | - // Test update credentials functionality |
409 | - |
410 | - Identity *existingIdentity = Identity::existingIdentity(m_identityResult.m_id, this); |
411 | - if (existingIdentity == NULL) { |
412 | - qDebug() << "Could not create existing identity. '0' ID provided?"; |
413 | - return false; |
414 | - } |
415 | - |
416 | - QMap<MethodName, MechanismsList> methods; |
417 | - if (addMethods) { |
418 | - methods.insert("dummy1", QStringList() << "mech11" << "mech12" << "mech13"); |
419 | - methods.insert("dummy2", QStringList() << "mech1_updated" << "mech2" << "mech1_updated2"); |
420 | - methods.insert("dummy3", QStringList() << "mech1_updated" << "mech2" << "mech1_updated2"); |
421 | - } |
422 | - |
423 | - IdentityInfo updateInfo("TEST_CAPTION", "TEST_USERNAME_UPDATED", methods); |
424 | - updateInfo.setSecret("TEST_SECRET_YES", false); |
425 | - |
426 | - do |
427 | - { |
428 | - QEventLoop loop; |
429 | - |
430 | - connect(existingIdentity, SIGNAL(error(const SignOn::Error &)), |
431 | - &m_identityResult, SLOT(error(const SignOn::Error &))); |
432 | - |
433 | - connect(existingIdentity, SIGNAL(credentialsStored(const quint32)), |
434 | - &m_identityResult, SLOT(credentialsStored(const quint32))); |
435 | - connect(&m_identityResult, SIGNAL(testCompleted()), &loop, SLOT(quit())); |
436 | - |
437 | - existingIdentity->storeCredentials(updateInfo); |
438 | - qDebug(); |
439 | - QTimer::singleShot(test_timeout, &loop, SLOT(quit())); |
440 | - loop.exec(); |
441 | - } while(0); |
442 | - |
443 | - qDebug(); |
444 | - if (m_identityResult.m_responseReceived == |
445 | - TestIdentityResult::InexistentResp) { |
446 | - qDebug() << "A response was not received."; |
447 | - return false; |
448 | - } |
449 | - |
450 | - if (m_identityResult.m_responseReceived == TestIdentityResult::NormalResp) { |
451 | - QEventLoop loop; |
452 | - connect(&m_identityResult, SIGNAL(testCompleted()), &loop, SLOT(quit())); |
453 | - connect(existingIdentity, SIGNAL(info(const SignOn::IdentityInfo &)), |
454 | - &m_identityResult, SLOT(info(const SignOn::IdentityInfo &))); |
455 | - |
456 | - existingIdentity->queryInfo(); |
457 | - QTimer::singleShot(test_timeout, &loop, SLOT(quit())); |
458 | - loop.exec(); |
459 | - |
460 | - qDebug() << "ID:" << existingIdentity->id(); |
461 | - if (!TestIdentityResult::compareIdentityInfos(m_identityResult.m_idInfo, |
462 | - updateInfo)) { |
463 | - qDebug() << "Compared identity infos are not the same."; |
464 | - return false; |
465 | - } |
466 | - } else { |
467 | - QString codeStr = errCodeAsStr(m_identityResult.m_error); |
468 | - qDebug() << "Error reply: " << m_serviceResult.m_errMsg |
469 | - << ".\nError code: " << codeStr; |
470 | - |
471 | - return false; |
472 | - } |
473 | - return true; |
474 | -} |
475 | - |
476 | void SsoTestClient::emptyPasswordRegression() |
477 | { |
478 | TEST_START |
479 | |
480 | === modified file 'tests/libsignon-qt-tests/ssotestclient.h' |
481 | --- tests/libsignon-qt-tests/ssotestclient.h 2013-11-22 14:46:01 +0000 |
482 | +++ tests/libsignon-qt-tests/ssotestclient.h 2014-11-28 12:00:40 +0000 |
483 | @@ -56,6 +56,7 @@ |
484 | * Identity tests |
485 | */ |
486 | void queryAvailableMetods(); |
487 | + void storeCredentials_data(); |
488 | void storeCredentials(); |
489 | void requestCredentialsUpdate(); |
490 | void queryInfo(); |
491 | @@ -65,7 +66,6 @@ |
492 | void verifySecret(); |
493 | void signOut(); |
494 | void remove(); |
495 | - void storeCredentialsWithoutAuthMethodsTest(); |
496 | void sessionTest(); |
497 | void multipleRemove(); |
498 | void removeStoreRemove(); |
499 | |
500 | === modified file 'tests/libsignon-qt-tests/testauthsession.cpp' |
501 | --- tests/libsignon-qt-tests/testauthsession.cpp 2013-11-12 09:09:04 +0000 |
502 | +++ tests/libsignon-qt-tests/testauthsession.cpp 2014-11-28 12:00:40 +0000 |
503 | @@ -361,6 +361,7 @@ |
504 | methods.insert(QLatin1String("ssotest"), mechs); |
505 | IdentityInfo info("test_caption", "test_user_name", methods); |
506 | info.setSecret("test_secret"); |
507 | + info.setAccessControlList(QStringList() << "*"); |
508 | Identity *id = Identity::newIdentity(info, this); |
509 | |
510 | QSignalSpy spyResponseStoreCreds(id, SIGNAL(credentialsStored(const quint32))); |
511 | |
512 | === modified file 'tests/signond-tests/.gitignore' |
513 | --- tests/signond-tests/.gitignore 2013-08-20 08:01:44 +0000 |
514 | +++ tests/signond-tests/.gitignore 2014-11-28 12:00:40 +0000 |
515 | @@ -1,6 +1,7 @@ |
516 | /identity-tool |
517 | /mock-ac-plugin/identity-ac-helper |
518 | /tst_access_control |
519 | +/tst_access_control_manager_helper |
520 | /tst_backup |
521 | /tst_database |
522 | /tst_pluginproxy |
523 | |
524 | === modified file 'tests/signond-tests/signond-tests.pri' |
525 | --- tests/signond-tests/signond-tests.pri 2013-08-20 08:01:43 +0000 |
526 | +++ tests/signond-tests/signond-tests.pri 2014-11-28 12:00:40 +0000 |
527 | @@ -23,6 +23,8 @@ |
528 | $${TOP_BUILD_DIR}/lib/signond/SignOn |
529 | QMAKE_RPATHDIR = $${QMAKE_LIBDIR} |
530 | |
531 | +SIGNOND_SRC = $${TOP_SRC_DIR}/src/signond |
532 | + |
533 | DEFINES += SIGNOND_TRACE |
534 | DEFINES += SIGNON_PLUGIN_TRACE |
535 | |
536 | |
537 | === modified file 'tests/signond-tests/signond-tests.pro' |
538 | --- tests/signond-tests/signond-tests.pro 2013-08-20 08:01:44 +0000 |
539 | +++ tests/signond-tests/signond-tests.pro 2014-11-28 12:00:40 +0000 |
540 | @@ -1,5 +1,6 @@ |
541 | TEMPLATE = subdirs |
542 | SUBDIRS = \ |
543 | + tst_access_control_manager_helper.pro \ |
544 | tst_timeouts.pro \ |
545 | tst_pluginproxy.pro \ |
546 | tst_database.pro \ |
547 | |
548 | === modified file 'tests/signond-tests/timeouts.cpp' |
549 | --- tests/signond-tests/timeouts.cpp 2013-08-20 08:01:43 +0000 |
550 | +++ tests/signond-tests/timeouts.cpp 2014-11-28 12:00:40 +0000 |
551 | @@ -62,6 +62,7 @@ |
552 | IdentityInfo info = IdentityInfo(QLatin1String("timeout test"), |
553 | QLatin1String("timeout@test"), |
554 | methods); |
555 | + info.setAccessControlList(QStringList() << "*"); |
556 | Identity *identity = Identity::newIdentity(info); |
557 | QVERIFY(identity != NULL); |
558 | |
559 | @@ -135,6 +136,7 @@ |
560 | IdentityInfo info = IdentityInfo(QLatin1String("timeout test"), |
561 | QLatin1String("timeout@test"), |
562 | methods); |
563 | + info.setAccessControlList(QStringList() << "*"); |
564 | Identity *identity = Identity::newIdentity(info); |
565 | QVERIFY(identity != NULL); |
566 | |
567 | |
568 | === added file 'tests/signond-tests/tst_access_control_manager_helper.cpp' |
569 | --- tests/signond-tests/tst_access_control_manager_helper.cpp 1970-01-01 00:00:00 +0000 |
570 | +++ tests/signond-tests/tst_access_control_manager_helper.cpp 2014-11-28 12:00:40 +0000 |
571 | @@ -0,0 +1,320 @@ |
572 | +/* |
573 | + * This file is part of signon |
574 | + * |
575 | + * Copyright (C) 2014 Canonical Ltd. |
576 | + * |
577 | + * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> |
578 | + * |
579 | + * This library is free software; you can redistribute it and/or |
580 | + * modify it under the terms of the GNU Lesser General Public License |
581 | + * version 2.1 as published by the Free Software Foundation. |
582 | + * |
583 | + * This library is distributed in the hope that it will be useful, but |
584 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
585 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
586 | + * Lesser General Public License for more details. |
587 | + * |
588 | + * You should have received a copy of the GNU Lesser General Public |
589 | + * License along with this library; if not, write to the Free Software |
590 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
591 | + * 02110-1301 USA |
592 | + */ |
593 | + |
594 | +#include <QByteArray> |
595 | +#include <QDBusConnection> |
596 | +#include <QDBusMessage> |
597 | +#include <QDebug> |
598 | +#include <QSignalSpy> |
599 | +#include <QTest> |
600 | + |
601 | +#include <SignOn/AbstractAccessControlManager> |
602 | +#include "accesscontrolmanagerhelper.h" |
603 | +#include "credentialsaccessmanager.h" |
604 | +#include "credentialsdb.h" |
605 | + |
606 | +using namespace SignOn; |
607 | +using namespace SignonDaemonNS; |
608 | + |
609 | +// mock AbstractAccessControlManager { |
610 | +class AcmPlugin: public SignOn::AbstractAccessControlManager |
611 | +{ |
612 | + Q_OBJECT |
613 | + |
614 | +public: |
615 | + AcmPlugin(QObject *parent = 0): |
616 | + SignOn::AbstractAccessControlManager(parent) {} |
617 | + ~AcmPlugin() {} |
618 | + |
619 | + bool isPeerAllowedToAccess(const QDBusConnection &peerConnection, |
620 | + const QDBusMessage &peerMessage, |
621 | + const QString &securityContext) { |
622 | + QStringList appPermissions = |
623 | + m_permissions.value(appIdOfPeer(peerConnection, peerMessage)); |
624 | + return appPermissions.contains(securityContext); |
625 | + } |
626 | + |
627 | + QString appIdOfPeer(const QDBusConnection &peerConnection, |
628 | + const QDBusMessage &peerMessage) { |
629 | + Q_UNUSED(peerConnection); |
630 | + return peerMessage.service(); |
631 | + } |
632 | + |
633 | + QString keychainWidgetAppId() { return m_keychainWidgetAppId; } |
634 | + |
635 | + SignOn::AccessReply *handleRequest(const SignOn::AccessRequest &request) { |
636 | + Q_UNUSED(request); |
637 | + return 0; |
638 | + } |
639 | + |
640 | +private: |
641 | + friend class AccessControlManagerHelperTest; |
642 | + QMap<QString,QStringList> m_permissions; |
643 | + QString m_keychainWidgetAppId; |
644 | +}; |
645 | +// } mock AbstractAccessControlManager |
646 | + |
647 | +class AccessControlManagerHelperTest: public QObject |
648 | +{ |
649 | + Q_OBJECT |
650 | + |
651 | +public: |
652 | + AccessControlManagerHelperTest(); |
653 | + |
654 | +private Q_SLOTS: |
655 | + void init(); |
656 | + void testOwnership_data(); |
657 | + void testOwnership(); |
658 | + void testIdentityAccess_data(); |
659 | + void testIdentityAccess(); |
660 | + |
661 | +public: |
662 | + static AccessControlManagerHelperTest *instance() { return m_instance; } |
663 | + SignonDaemonNS::CredentialsDB *credentialsDB() { return &m_db; } |
664 | + |
665 | +private: |
666 | + void setDbOwners(const QStringList &owners) { |
667 | + if (owners.contains("db-error")) { |
668 | + m_dbOwners = QStringList(); |
669 | + m_dbLastError = CredentialsDBError("DB error!", |
670 | + CredentialsDBError::ConnectionError); |
671 | + } else { |
672 | + m_dbOwners = owners; |
673 | + } |
674 | + } |
675 | + |
676 | + void setDbAcl(const QStringList &acl) { |
677 | + if (acl.contains("db-error")) { |
678 | + m_dbAcl = QStringList(); |
679 | + m_dbLastError = CredentialsDBError("DB error!", |
680 | + CredentialsDBError::ConnectionError); |
681 | + } else { |
682 | + m_dbAcl = acl; |
683 | + } |
684 | + } |
685 | + |
686 | +private: |
687 | + friend class SignonDaemonNS::CredentialsDB; |
688 | + static AccessControlManagerHelperTest *m_instance; |
689 | + AcmPlugin m_acmPlugin; |
690 | + SignonDaemonNS::CredentialsDB m_db; |
691 | + SignOn::CredentialsDBError m_dbLastError; |
692 | + QStringList m_dbAcl; |
693 | + QStringList m_dbOwners; |
694 | + QDBusConnection m_conn; |
695 | +}; |
696 | + |
697 | +AccessControlManagerHelperTest *AccessControlManagerHelperTest::m_instance = 0; |
698 | + |
699 | +namespace SignonDaemonNS { |
700 | +// mock CredentialsDB { |
701 | +CredentialsDB::CredentialsDB(const QString &metaDataDbName, |
702 | + SignOn::AbstractSecretsStorage *secretsStorage): |
703 | + QObject() |
704 | +{ |
705 | + Q_UNUSED(metaDataDbName); |
706 | + Q_UNUSED(secretsStorage); |
707 | +} |
708 | + |
709 | +CredentialsDB::~CredentialsDB() |
710 | +{ |
711 | +} |
712 | + |
713 | +SignOn::CredentialsDBError CredentialsDB::lastError() const |
714 | +{ |
715 | + return AccessControlManagerHelperTest::instance()->m_dbLastError; |
716 | +} |
717 | + |
718 | +QStringList CredentialsDB::accessControlList(const quint32 identityId) |
719 | +{ |
720 | + Q_UNUSED(identityId); |
721 | + return AccessControlManagerHelperTest::instance()->m_dbAcl; |
722 | +} |
723 | + |
724 | +QStringList CredentialsDB::ownerList(const quint32 identityId) |
725 | +{ |
726 | + Q_UNUSED(identityId); |
727 | + return AccessControlManagerHelperTest::instance()->m_dbOwners; |
728 | +} |
729 | +// } mock CredentialsDB |
730 | + |
731 | +// mock CredentialsAccessManager { |
732 | +CredentialsDB *CredentialsAccessManager::credentialsDB() const { |
733 | + return AccessControlManagerHelperTest::instance()->credentialsDB(); |
734 | +} |
735 | +CredentialsAccessManager *CredentialsAccessManager::instance() { |
736 | + return 0; |
737 | +} |
738 | +} // namespace |
739 | +// } mock CredentialsAccessManager |
740 | + |
741 | +AccessControlManagerHelperTest::AccessControlManagerHelperTest(): |
742 | + QObject(), |
743 | + m_db(QString(), 0), |
744 | + m_conn(QLatin1String("test-connection")) |
745 | +{ |
746 | + m_instance = this; |
747 | +} |
748 | + |
749 | +void AccessControlManagerHelperTest::init() |
750 | +{ |
751 | + m_dbOwners = QStringList(); |
752 | + m_dbAcl = QStringList(); |
753 | + m_dbLastError = CredentialsDBError(); |
754 | +} |
755 | + |
756 | +void AccessControlManagerHelperTest::testOwnership_data() |
757 | +{ |
758 | + QTest::addColumn<QString>("peer"); |
759 | + QTest::addColumn<QStringList>("ownerList"); |
760 | + QTest::addColumn<int>("expectedOwnership"); |
761 | + |
762 | + QTest::newRow("DB error") << |
763 | + "tom" << |
764 | + (QStringList() << "db-error") << |
765 | + int(AccessControlManagerHelper::ApplicationIsNotOwner); |
766 | + |
767 | + QTest::newRow("empty") << |
768 | + "tom" << |
769 | + QStringList() << |
770 | + int(AccessControlManagerHelper::IdentityDoesNotHaveOwner); |
771 | + |
772 | + QTest::newRow("is only owner") << |
773 | + "tom" << |
774 | + (QStringList() << "tom") << |
775 | + int(AccessControlManagerHelper::ApplicationIsOwner); |
776 | + |
777 | + QTest::newRow("is co-owner") << |
778 | + "tom" << |
779 | + (QStringList() << "Bob" << "tom" << "harry") << |
780 | + int(AccessControlManagerHelper::ApplicationIsOwner); |
781 | +} |
782 | + |
783 | +void AccessControlManagerHelperTest::testOwnership() |
784 | +{ |
785 | + QFETCH(QString, peer); |
786 | + QFETCH(QStringList, ownerList); |
787 | + QFETCH(int, expectedOwnership); |
788 | + |
789 | + setDbOwners(ownerList); |
790 | + |
791 | + m_acmPlugin.m_permissions["tom"] = QStringList() << "tom" << "Tom"; |
792 | + |
793 | + /* forge a QDBusMessage */ |
794 | + QDBusMessage msg = |
795 | + QDBusMessage::createMethodCall(peer, "/", "interface", "hi"); |
796 | + |
797 | + SignonDaemonNS::AccessControlManagerHelper helper(&m_acmPlugin); |
798 | + |
799 | + AccessControlManagerHelper::IdentityOwnership ownership = |
800 | + helper.isPeerOwnerOfIdentity(m_conn, msg, 3); |
801 | + |
802 | + QCOMPARE(int(ownership), expectedOwnership); |
803 | +} |
804 | + |
805 | +void AccessControlManagerHelperTest::testIdentityAccess_data() |
806 | +{ |
807 | + QTest::addColumn<QString>("peer"); |
808 | + QTest::addColumn<QStringList>("ownerList"); |
809 | + QTest::addColumn<QStringList>("acl"); |
810 | + QTest::addColumn<bool>("expectedIsAllowed"); |
811 | + |
812 | + QTest::newRow("DB error") << |
813 | + "tom" << |
814 | + (QStringList() << "tom") << |
815 | + (QStringList() << "db-error") << |
816 | + false; |
817 | + |
818 | + QTest::newRow("is owner, ACL empty") << |
819 | + "tom" << |
820 | + (QStringList() << "tom") << |
821 | + QStringList() << |
822 | + true; |
823 | + |
824 | + QTest::newRow("is owner, not in ACL") << |
825 | + "tom" << |
826 | + (QStringList() << "tom") << |
827 | + (QStringList() << "bob") << |
828 | + true; |
829 | + |
830 | + QTest::newRow("is owner, in ACL") << |
831 | + "tom" << |
832 | + (QStringList() << "tom") << |
833 | + (QStringList() << "bob" << "tom" << "harry") << |
834 | + true; |
835 | + |
836 | + QTest::newRow("is owner, ACL=*") << |
837 | + "tom" << |
838 | + (QStringList() << "tom") << |
839 | + (QStringList() << "*") << |
840 | + true; |
841 | + |
842 | + QTest::newRow("not owner, ACL empty") << |
843 | + "tom" << |
844 | + (QStringList() << "bob") << |
845 | + QStringList() << |
846 | + false; |
847 | + |
848 | + QTest::newRow("not owner, not in ACL") << |
849 | + "tom" << |
850 | + (QStringList() << "bob") << |
851 | + (QStringList() << "bob") << |
852 | + false; |
853 | + |
854 | + QTest::newRow("not owner, in ACL") << |
855 | + "tom" << |
856 | + (QStringList() << "bob") << |
857 | + (QStringList() << "bob" << "tom" << "harry") << |
858 | + true; |
859 | + |
860 | + QTest::newRow("not owner, ACL=*") << |
861 | + "tom" << |
862 | + (QStringList() << "bob") << |
863 | + (QStringList() << "*") << |
864 | + true; |
865 | +} |
866 | + |
867 | +void AccessControlManagerHelperTest::testIdentityAccess() |
868 | +{ |
869 | + QFETCH(QString, peer); |
870 | + QFETCH(QStringList, ownerList); |
871 | + QFETCH(QStringList, acl); |
872 | + QFETCH(bool, expectedIsAllowed); |
873 | + |
874 | + setDbOwners(ownerList); |
875 | + setDbAcl(acl); |
876 | + |
877 | + m_acmPlugin.m_permissions["tom"] = QStringList() << "tom" << "Tom"; |
878 | + |
879 | + /* forge a QDBusMessage */ |
880 | + QDBusMessage msg = |
881 | + QDBusMessage::createMethodCall(peer, "/", "interface", "hi"); |
882 | + |
883 | + SignonDaemonNS::AccessControlManagerHelper helper(&m_acmPlugin); |
884 | + |
885 | + bool isAllowed = helper.isPeerAllowedToUseIdentity(m_conn, msg, 3); |
886 | + |
887 | + QCOMPARE(isAllowed, expectedIsAllowed); |
888 | +} |
889 | + |
890 | +QTEST_MAIN(AccessControlManagerHelperTest) |
891 | +#include "tst_access_control_manager_helper.moc" |
892 | |
893 | === added file 'tests/signond-tests/tst_access_control_manager_helper.pro' |
894 | --- tests/signond-tests/tst_access_control_manager_helper.pro 1970-01-01 00:00:00 +0000 |
895 | +++ tests/signond-tests/tst_access_control_manager_helper.pro 2014-11-28 12:00:40 +0000 |
896 | @@ -0,0 +1,13 @@ |
897 | +TARGET = tst_access_control_manager_helper |
898 | + |
899 | +include(signond-tests.pri) |
900 | + |
901 | +SOURCES = \ |
902 | + $${SIGNOND_SRC}/accesscontrolmanagerhelper.cpp \ |
903 | + tst_access_control_manager_helper.cpp |
904 | + |
905 | +HEADERS = \ |
906 | + $${SIGNOND_SRC}/accesscontrolmanagerhelper.h \ |
907 | + $${SIGNOND_SRC}/credentialsdb.h |
908 | + |
909 | +check.commands = "./$$TARGET" |