Merge lp:~alecu/ubuntu-sso-client/fix-708018 into lp:ubuntu-sso-client
- fix-708018
- Merge into trunk
Proposed by
Alejandro J. Cura
Status: | Merged |
---|---|
Approved by: | Alejandro J. Cura |
Approved revision: | 682 |
Merged at revision: | 674 |
Proposed branch: | lp:~alecu/ubuntu-sso-client/fix-708018 |
Merge into: | lp:ubuntu-sso-client |
Diff against target: |
424 lines (+200/-38) 2 files modified
ubuntu_sso/utils/tests/test_txsecrets.py (+133/-28) ubuntu_sso/utils/txsecrets.py (+67/-10) |
To merge this branch: | bzr merge lp:~alecu/ubuntu-sso-client/fix-708018 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Natalia Bidart (community) | Approve | ||
Roberto Alsina (community) | fieldtest | Approve | |
Sebastien Bacher | Pending | ||
Review via email:
|
Commit message
Create a keyring named "default" if no default keyring found. (LP:#708018)
Description of the change
Create a keyring named "default" if no default keyring found. (LP:#708018)
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alejandro J. Cura (alecu) wrote : | # |
- 681. By Alejandro J. Cura
-
clean up constants in the test file
- 682. By Alejandro J. Cura
-
get_collection_
by_alias was only used by the tests. removing it
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Natalia Bidart (nataliabidart) wrote : | # |
It works as advertised!
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'ubuntu_sso/utils/tests/test_txsecrets.py' |
2 | --- ubuntu_sso/utils/tests/test_txsecrets.py 2011-01-18 21:54:35 +0000 |
3 | +++ ubuntu_sso/utils/tests/test_txsecrets.py 2011-02-03 13:57:14 +0000 |
4 | @@ -37,6 +37,9 @@ |
5 | |
6 | |
7 | ERROR_CREATE_BUT_LOCKED = "Cannot create an item in a locked collection" |
8 | +PROMPT_BASE_PATH = "/org/freedesktop/secrets/prompt" |
9 | +SESSION_BASE_PATH = "/org/freedesktop/secrets/session" |
10 | +COLLECTION_BASE_PATH = "/org/freedesktop/secrets/collection/" |
11 | |
12 | |
13 | class SampleMiscException(Exception): |
14 | @@ -66,7 +69,7 @@ |
15 | raise SampleMiscException() |
16 | self.collection.items.remove(self) |
17 | if self.delete_prompt: |
18 | - prompt_path = create_object_path("/org/freedesktop/secrets/prompt") |
19 | + prompt_path = create_object_path(PROMPT_BASE_PATH) |
20 | prompt = self.dbus_publish(prompt_path, PromptMock, |
21 | result="", |
22 | dismissed=self.dismissed) |
23 | @@ -146,13 +149,12 @@ |
24 | attributes = properties[txsecrets.ATTRIBUTES_PROPERTY] |
25 | item_label = properties[txsecrets.LABEL_PROPERTY] |
26 | session, parameters, value = secret |
27 | - item_path = create_object_path("/org/freedesktop/secrets/collection/" + |
28 | - self.label) |
29 | + item_path = create_object_path(make_coll_path(self.label)) |
30 | item = self.dbus_publish(item_path, ItemMock, self, item_label, |
31 | attributes, value) |
32 | self.items.append(item) |
33 | if self.create_item_prompt: |
34 | - prompt_path = create_object_path("/org/freedesktop/secrets/prompt") |
35 | + prompt_path = create_object_path(PROMPT_BASE_PATH) |
36 | prompt = self.dbus_publish(prompt_path, PromptMock, |
37 | result=item, |
38 | dismissed=self.dismissed) |
39 | @@ -160,6 +162,13 @@ |
40 | else: |
41 | return item, "/" |
42 | |
43 | + @dbus.service.method(dbus_interface=txsecrets.PROPERTIES_IFACE, |
44 | + in_signature="ss", out_signature="v") |
45 | + def Get(self, interface, propname): |
46 | + """The only property implemented is Label.""" |
47 | + if interface == txsecrets.COLLECTION_IFACE and propname == "Label": |
48 | + return dbus.String(self.label) |
49 | + |
50 | |
51 | class SessionMock(dbus.service.Object): |
52 | """A session tracks state between the service and a client application.""" |
53 | @@ -169,6 +178,11 @@ |
54 | """Close this session.""" |
55 | |
56 | |
57 | +def make_coll_path(label): |
58 | + """Make the path to a collection with its label""" |
59 | + return COLLECTION_BASE_PATH + label |
60 | + |
61 | + |
62 | class SecretServiceMock(dbus.service.Object): |
63 | """The Secret Service manages all the sessions and collections.""" |
64 | create_collection_prompt = False |
65 | @@ -181,6 +195,7 @@ |
66 | super(SecretServiceMock, self).__init__(*args, **kwargs) |
67 | self.sessions = {} |
68 | self.collections = {} |
69 | + self.aliases = {} |
70 | |
71 | @dbus.service.method(dbus_interface=txsecrets.SERVICE_IFACE, |
72 | in_signature="sv", out_signature="vo") |
73 | @@ -188,15 +203,11 @@ |
74 | """Open a unique session for the caller application.""" |
75 | if self.open_session_fail: |
76 | raise SampleMiscException() |
77 | - session_path = create_object_path("/org/freedesktop/secrets/session") |
78 | + session_path = create_object_path(SESSION_BASE_PATH) |
79 | session = self.dbus_publish(session_path, SessionMock) |
80 | self.sessions[session_path] = session |
81 | return True, session |
82 | |
83 | - def make_coll_path(self, label): |
84 | - """Make the path to a collection with its label""" |
85 | - return "/org/freedesktop/secrets/collection/" + label |
86 | - |
87 | @dbus.service.method(dbus_interface=txsecrets.SERVICE_IFACE, |
88 | in_signature="a{sv}", out_signature="oo") |
89 | def CreateCollection(self, properties): |
90 | @@ -204,15 +215,12 @@ |
91 | if self.create_collection_fail: |
92 | raise SampleMiscException() |
93 | label = str(properties[txsecrets.LABEL_PROPERTY]) |
94 | - if len(self.collections): |
95 | - coll_path = self.make_coll_path(label) |
96 | - else: |
97 | - coll_path = txsecrets.DEFAULT_COLLECTION |
98 | + coll_path = make_coll_path(label) |
99 | collection = self.dbus_publish(coll_path, CollectionMock, label) |
100 | self.collections[label] = collection |
101 | |
102 | if self.create_collection_prompt: |
103 | - prompt_path = create_object_path("/org/freedesktop/secrets/prompt") |
104 | + prompt_path = create_object_path(PROMPT_BASE_PATH) |
105 | prompt = self.dbus_publish(prompt_path, PromptMock, |
106 | result=collection, |
107 | dismissed=self.dismissed) |
108 | @@ -240,11 +248,15 @@ |
109 | def unlock_objects(self, objects): |
110 | """Unlock the objects or its containers.""" |
111 | for c in self.collections.values(): |
112 | - if c.__dbus_object_path__ in objects: |
113 | - c.locked = False |
114 | - for i in c.items: |
115 | - if i.__dbus_object_path__ in objects: |
116 | + for l in c.locations: |
117 | + path = l[1] |
118 | + if path in objects: |
119 | c.locked = False |
120 | + for i in c.items: |
121 | + for l in i.locations: |
122 | + path = l[1] |
123 | + if path in objects: |
124 | + c.locked = False |
125 | |
126 | @dbus.service.method(dbus_interface=txsecrets.SERVICE_IFACE, |
127 | in_signature="ao", out_signature="aoo") |
128 | @@ -261,7 +273,7 @@ |
129 | else: |
130 | unlocked.append(path) |
131 | if locked: |
132 | - prompt_path = create_object_path("/org/freedesktop/secrets/prompt") |
133 | + prompt_path = create_object_path(PROMPT_BASE_PATH) |
134 | self.unlock_objects(objects) |
135 | prompt = self.dbus_publish(prompt_path, PromptMock, |
136 | result=locked, |
137 | @@ -271,12 +283,25 @@ |
138 | self.unlock_objects(objects) |
139 | return objects, "/" |
140 | |
141 | - @dbus.service.method(dbus_interface="org.freedesktop.DBus.Properties", |
142 | + @dbus.service.method(dbus_interface=txsecrets.SERVICE_IFACE, |
143 | + in_signature="s", out_signature="o") |
144 | + def ReadAlias(self, name): |
145 | + """Get the collection with the given alias.""" |
146 | + result = self.aliases.get(name, "/") |
147 | + return result |
148 | + |
149 | + @dbus.service.method(dbus_interface=txsecrets.SERVICE_IFACE, |
150 | + in_signature="so") |
151 | + def SetAlias(self, name, collection_path): |
152 | + """Setup a collection alias.""" |
153 | + self.aliases[name] = collection_path |
154 | + |
155 | + @dbus.service.method(dbus_interface=txsecrets.PROPERTIES_IFACE, |
156 | in_signature="ss", out_signature="v") |
157 | def Get(self, interface, propname): |
158 | """The only property implemented is Collections.""" |
159 | if interface == txsecrets.SERVICE_IFACE and propname == "Collections": |
160 | - coll_paths = [self.make_coll_path(l) for l in self.collections] |
161 | + coll_paths = [make_coll_path(l) for l in self.collections] |
162 | return dbus.Array(coll_paths, signature="o", variant_level=1) |
163 | |
164 | |
165 | @@ -304,14 +329,27 @@ |
166 | self.assertNotEqual(name, dbus.bus.REQUEST_NAME_REPLY_EXISTS) |
167 | mock_object = object_class(*args, object_path=object_path, |
168 | conn=self.session_bus, **kwargs) |
169 | - self.addCleanup(mock_object.remove_from_connection) |
170 | + self.addCleanup(mock_object.remove_from_connection, |
171 | + connection=self.session_bus, |
172 | + path=object_path) |
173 | mock_object.dbus_publish = self.dbus_publish |
174 | return mock_object |
175 | |
176 | @inlineCallbacks |
177 | - def create_sample_collection(self, label): |
178 | + def create_sample_collection(self, label, make_alias=True, |
179 | + publish_default_path=False): |
180 | """Create a collection with a given label.""" |
181 | coll = yield self.secretservice.create_collection(label) |
182 | + if make_alias: |
183 | + coll_path = make_coll_path(label) |
184 | + self.mock_service.SetAlias("default", coll_path) |
185 | + if publish_default_path: |
186 | + mock_object = self.mock_service.collections[label] |
187 | + mock_object.add_to_connection(self.session_bus, |
188 | + txsecrets.DEFAULT_COLLECTION) |
189 | + self.addCleanup(mock_object.remove_from_connection, |
190 | + connection=self.session_bus, |
191 | + path=txsecrets.DEFAULT_COLLECTION) |
192 | returnValue(coll) |
193 | |
194 | |
195 | @@ -528,16 +566,48 @@ |
196 | self.assertEqual(len(result), 3) |
197 | |
198 | @inlineCallbacks |
199 | - def test_get_default_collection(self): |
200 | - """The default collection is returned.""" |
201 | - yield self.secretservice.open_session() |
202 | - collection_name = "sample_keyring" |
203 | + def test_get_collections(self): |
204 | + """The list of all collections is returned.""" |
205 | + collection_names = ["collection1", "collection2"] |
206 | + |
207 | + yield self.secretservice.open_session() |
208 | + for name in collection_names: |
209 | + yield self.create_sample_collection(name) |
210 | + collections = yield self.secretservice.get_collections() |
211 | + self.assertEqual(len(collections), len(collection_names)) |
212 | + |
213 | + @inlineCallbacks |
214 | + def test_get_default_collection_honours_default_path(self): |
215 | + """The default collection is returned from the default path.""" |
216 | + yield self.secretservice.open_session() |
217 | + collection_name = "sample_default_keyring" |
218 | + yield self.create_sample_collection(collection_name, make_alias=False, |
219 | + publish_default_path=True) |
220 | + self.assertEqual(len(self.mock_service.collections), 1) |
221 | + yield self.secretservice.get_default_collection() |
222 | + self.assertEqual(len(self.mock_service.collections), 1) |
223 | + |
224 | + @inlineCallbacks |
225 | + def test_get_default_collection_honours_readalias(self): |
226 | + """The default collection is returned if default alias set.""" |
227 | + yield self.secretservice.open_session() |
228 | + collection_name = "sample_default_keyring" |
229 | yield self.create_sample_collection(collection_name) |
230 | self.assertEqual(len(self.mock_service.collections), 1) |
231 | yield self.secretservice.get_default_collection() |
232 | self.assertEqual(len(self.mock_service.collections), 1) |
233 | |
234 | @inlineCallbacks |
235 | + def test_get_default_collection_created_if_no_default(self): |
236 | + """The default collection is created if there's no default.""" |
237 | + yield self.secretservice.open_session() |
238 | + collection_name = "sample_nondefault_keyring" |
239 | + yield self.create_sample_collection(collection_name, make_alias=False) |
240 | + self.assertEqual(len(self.mock_service.collections), 1) |
241 | + yield self.secretservice.get_default_collection() |
242 | + self.assertEqual(len(self.mock_service.collections), 2) |
243 | + |
244 | + @inlineCallbacks |
245 | def test_get_default_collection_created_if_nonexistent(self): |
246 | """The default collection is created if it doesn't exist yet.""" |
247 | yield self.secretservice.open_session() |
248 | @@ -546,7 +616,32 @@ |
249 | self.assertEqual(len(self.mock_service.collections), 1) |
250 | |
251 | @inlineCallbacks |
252 | - def test_get_default_collection_is_unlocked(self): |
253 | + def test_get_default_collection_set_as_default_if_nonexistent(self): |
254 | + """The default collection is set as default if it doesn't exist yet.""" |
255 | + yield self.secretservice.open_session() |
256 | + yield self.secretservice.get_default_collection() |
257 | + self.assertIn(txsecrets.DEFAULT_LABEL, self.mock_service.aliases) |
258 | + |
259 | + @inlineCallbacks |
260 | + def test_get_default_collection_is_unlocked_default_path(self): |
261 | + """The default collection is unlocked before being returned.""" |
262 | + yield self.secretservice.open_session() |
263 | + collection_name = "sample_keyring" |
264 | + self.assertEqual(len(self.mock_service.collections), 0) |
265 | + coll = yield self.create_sample_collection(collection_name, |
266 | + make_alias=False, |
267 | + publish_default_path=True) |
268 | + self.assertEqual(len(self.mock_service.collections), 1) |
269 | + mock_collection = self.mock_service.collections[collection_name] |
270 | + mock_collection.locked = True |
271 | + yield self.secretservice.get_default_collection() |
272 | + attr = {"key-type": "Ubuntu 242 credentials"} |
273 | + sample_secret = "secret!" |
274 | + yield coll.create_item("Cucaracha", attr, sample_secret) |
275 | + self.assertEqual(len(mock_collection.items), 1) |
276 | + |
277 | + @inlineCallbacks |
278 | + def test_get_default_collection_is_unlocked_readalias(self): |
279 | """The default collection is unlocked before being returned.""" |
280 | yield self.secretservice.open_session() |
281 | collection_name = "sample_keyring" |
282 | @@ -566,6 +661,16 @@ |
283 | """Test the Collection class.""" |
284 | |
285 | @inlineCallbacks |
286 | + def test_get_label(self): |
287 | + """The collection gets its own label from the keyring.""" |
288 | + yield self.secretservice.open_session() |
289 | + expected_label = "sample_keyring" |
290 | + yield self.create_sample_collection(expected_label) |
291 | + coll = yield self.secretservice.get_default_collection() |
292 | + result = yield coll.get_label() |
293 | + self.assertEqual(result, expected_label) |
294 | + |
295 | + @inlineCallbacks |
296 | def test_create_item(self): |
297 | """The collection creates an item.""" |
298 | yield self.secretservice.open_session() |
299 | |
300 | === modified file 'ubuntu_sso/utils/txsecrets.py' |
301 | --- ubuntu_sso/utils/txsecrets.py 2011-01-18 21:54:35 +0000 |
302 | +++ ubuntu_sso/utils/txsecrets.py 2011-02-03 13:57:14 +0000 |
303 | @@ -40,6 +40,8 @@ |
304 | PROPERTIES_IFACE = "org.freedesktop.DBus.Properties" |
305 | SECRETS_SERVICE = "/org/freedesktop/secrets" |
306 | DEFAULT_COLLECTION = "/org/freedesktop/secrets/aliases/default" |
307 | +SESSION_COLLECTION = "/org/freedesktop/secrets/collection/session" |
308 | + |
309 | ALGORITHM = "plain" |
310 | ALGORITHM_PARAMS = "" |
311 | LABEL_PROPERTY = "Label" |
312 | @@ -168,8 +170,25 @@ |
313 | d.addCallback(lambda p: Collection(self, p)) |
314 | return d |
315 | |
316 | + def get_collections(self): |
317 | + """Return the list of all collections.""" |
318 | + d = Deferred() |
319 | + |
320 | + def propertyget_handler(collection_paths): |
321 | + """The list of collection paths was retrieved.""" |
322 | + result = [] |
323 | + for path in collection_paths: |
324 | + collection = Collection(self, path) |
325 | + result.append(collection) |
326 | + d.callback(result) |
327 | + |
328 | + self.properties.Get(SERVICE_IFACE, COLLECTIONS_PROPERTY, |
329 | + reply_handler=propertyget_handler, |
330 | + error_handler=d.errback) |
331 | + return d |
332 | + |
333 | def get_default_collection(self): |
334 | - """The collection were default items should be created.""" |
335 | + """The collection where default items should be created.""" |
336 | d = Deferred() |
337 | |
338 | def prompt_handle(unlocked): |
339 | @@ -186,21 +205,48 @@ |
340 | else: |
341 | d.callback(prompt_handle(unlocked)) |
342 | |
343 | - def propertyget_handler(collection_paths): |
344 | - """The list of collection paths was retrieved.""" |
345 | - if len(collection_paths) > 0: |
346 | + def set_default_alias(collection): |
347 | + """Set the newly created collection as the default one.""" |
348 | + d4 = Deferred() |
349 | + alias_set = lambda: d4.callback(collection) |
350 | + object_path = dbus.ObjectPath(collection.object_path) |
351 | + self.service.SetAlias(DEFAULT_LABEL, object_path, |
352 | + reply_handler=alias_set, |
353 | + error_handler=d4.errback) |
354 | + return d4 |
355 | + |
356 | + def readalias_handler(collection_path): |
357 | + """ReadAlias returned.""" |
358 | + if collection_path != "/": |
359 | # The collection was found, make sure it's unlocked |
360 | - objects = dbus.Array([DEFAULT_COLLECTION], signature="o") |
361 | + objects = dbus.Array([collection_path], signature="o") |
362 | self.service.Unlock(objects, |
363 | reply_handler=unlock_handler, |
364 | error_handler=d.errback) |
365 | else: |
366 | # The collection was not found, so create it |
367 | - self.create_collection(DEFAULT_LABEL).chainDeferred(d) |
368 | - |
369 | - self.properties.Get(SERVICE_IFACE, COLLECTIONS_PROPERTY, |
370 | - reply_handler=propertyget_handler, |
371 | - error_handler=d.errback) |
372 | + d3 = self.create_collection(DEFAULT_LABEL) |
373 | + d3.addCallback(set_default_alias) |
374 | + d3.chainDeferred(d) |
375 | + |
376 | + def default_collection_not_found(e): |
377 | + """Try the default alias.""" |
378 | + self.service.ReadAlias(DEFAULT_LABEL, |
379 | + reply_handler=readalias_handler, |
380 | + error_handler=d.errback) |
381 | + |
382 | + def found_default_collection(label): |
383 | + """Make sure the default collection is unlocked.""" |
384 | + objects = dbus.Array([DEFAULT_COLLECTION], signature="o") |
385 | + self.service.Unlock(objects, |
386 | + reply_handler=unlock_handler, |
387 | + error_handler=d.errback) |
388 | + |
389 | + collection = Collection(self, DEFAULT_COLLECTION) |
390 | + d0 = collection.get_label() |
391 | + d0.addCallback(found_default_collection) |
392 | + d0.addErrback(default_collection_not_found) |
393 | + |
394 | return d |
395 | |
396 | |
397 | @@ -210,9 +256,19 @@ |
398 | def __init__(self, service, object_path): |
399 | """Initialize a new collection.""" |
400 | self.service = service |
401 | + self.object_path = object_path |
402 | collection_object = service.bus.get_object(BUS_NAME, object_path) |
403 | self.collection_iface = dbus.Interface(collection_object, |
404 | dbus_interface=COLLECTION_IFACE) |
405 | + self.properties = dbus.Interface(collection_object, |
406 | + dbus_interface=PROPERTIES_IFACE) |
407 | + |
408 | + def get_label(self): |
409 | + """Return the label for this collection from the keyring.""" |
410 | + d = Deferred() |
411 | + self.properties.Get(COLLECTION_IFACE, LABEL_PROPERTY, |
412 | + reply_handler=d.callback, error_handler=d.errback) |
413 | + return d |
414 | |
415 | def create_item(self, label, attr, value, replace=True): |
416 | """Create an item with the given attributes, secret and label. |
417 | @@ -248,6 +304,7 @@ |
418 | def __init__(self, service, object_path): |
419 | """Initialize this new Item.""" |
420 | self.service = service |
421 | + self.object_path = object_path |
422 | item_object = service.bus.get_object(BUS_NAME, object_path) |
423 | self.item_iface = dbus.Interface(item_object, |
424 | dbus_interface=ITEM_IFACE) |
To test this branch: create a user with "System- >Administration ->Users and Groups", and check "Don't ask for password on login".
Then log as that user and try to connect to Ubuntu One. After registration or login, a dialog will pop up asking to create a "Default" keyring. Create a keyring, then verify that the connection to Ubuntu One was succesful, and that seahorse shows a new "Default" keyring.