Merge lp:~alecu/ubuntu-sso-client/fix-708018 into lp:ubuntu-sso-client

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
Reviewer Review Type Date Requested Status
Natalia Bidart (community) Approve
Roberto Alsina (community) fieldtest Approve
Sebastien Bacher Pending
Review via email: mp+48411@code.launchpad.net

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
Alejandro J. Cura (alecu) wrote :

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.

681. By Alejandro J. Cura

clean up constants in the test file

Revision history for this message
Roberto Alsina (ralsina) wrote :

+1

review: Approve (fieldtest)
682. By Alejandro J. Cura

get_collection_by_alias was only used by the tests. removing it

Revision history for this message
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)

Subscribers

People subscribed via source and target branches