Merge lp:~mandel/ubuntuone-client/provide_credentials_management into lp:ubuntuone-client
- provide_credentials_management
- Merge into trunk
Proposed by
Manuel de la Peña
Status: | Merged |
---|---|
Approved by: | Roberto Alsina |
Approved revision: | 995 |
Merged at revision: | 984 |
Proposed branch: | lp:~mandel/ubuntuone-client/provide_credentials_management |
Merge into: | lp:ubuntuone-client |
Prerequisite: | lp:~mandel/ubuntuone-client/pass_main_to_ipc_root |
Diff against target: |
1019 lines (+702/-230) 8 files modified
po/POTFILES.in (+1/-0) tests/platform/linux/test_credentials.py (+4/-5) tests/platform/windows/test_credentials.py (+155/-0) tests/test_credentials.py (+99/-0) ubuntuone/credentials.py (+255/-0) ubuntuone/platform/linux/__init__.py (+1/-1) ubuntuone/platform/linux/credentials.py (+56/-224) ubuntuone/platform/windows/credentials.py (+131/-0) |
To merge this branch: | bzr merge lp:~mandel/ubuntuone-client/provide_credentials_management |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Roberto Alsina (community) | Approve | ||
Shane Fagan (community) | Approve | ||
Review via email: mp+59743@code.launchpad.net |
Commit message
This branch fixed the issue where windows does not have credential management code. This branch does the following:
* Refactor the CredentialsMana
* Implemented the CredentialsMana
Description of the change
This branch fixed the issue where windows does not have credential management code. This branch does the following:
* Refactor the CredentialsMana
* Implemented the CredentialsMana
This branch might break control panel (to be confirmed) and has to be tested in both platforms (windows/linux)
On Linux:
$ ./autogen
$ make check
On Windows:
python C:\Python27\
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'po/POTFILES.in' |
2 | --- po/POTFILES.in 2011-02-21 23:16:03 +0000 |
3 | +++ po/POTFILES.in 2011-05-03 09:17:06 +0000 |
4 | @@ -1,6 +1,7 @@ |
5 | ubuntuone/clientdefs.py.in |
6 | ubuntuone/status/aggregator.py |
7 | ubuntuone/platform/linux/credentials.py |
8 | +ubuntuone/platform/windows/credentials.py |
9 | data/emblem-ubuntuone-downloading.icon.in |
10 | data/emblem-ubuntuone-unsynchronized.icon.in |
11 | data/emblem-ubuntuone-uploading.icon.in |
12 | |
13 | === modified file 'tests/platform/linux/test_credentials.py' |
14 | --- tests/platform/linux/test_credentials.py 2011-02-15 20:32:42 +0000 |
15 | +++ tests/platform/linux/test_credentials.py 2011-05-03 09:17:06 +0000 |
16 | @@ -25,12 +25,11 @@ |
17 | from ubuntuone.devtools.handlers import MementoHandler |
18 | |
19 | from ubuntuone.platform.linux.credentials import (dbus, logger, logging, |
20 | - CredentialsManagement, CredentialsManagementTool, CredentialsError, |
21 | - ubuntu_sso, |
22 | - DBUS_BUS_NAME, DBUS_CREDENTIALS_PATH, DBUS_CREDENTIALS_IFACE, |
23 | - APP_NAME, HELP_TEXT_KEY, DESCRIPTION, TC_URL_KEY, TC_URL, |
24 | - PING_URL_KEY, PING_URL, TIMEOUT_INTERVAL, |
25 | + CredentialsManagement, ubuntu_sso, DBUS_BUS_NAME, DBUS_CREDENTIALS_PATH, |
26 | + DBUS_CREDENTIALS_IFACE, APP_NAME, HELP_TEXT_KEY, DESCRIPTION, |
27 | + TC_URL_KEY, TC_URL, PING_URL_KEY, PING_URL, TIMEOUT_INTERVAL, |
28 | ) |
29 | +from ubuntuone.credentials import CredentialsManagementTool, CredentialsError |
30 | |
31 | FAKED_CREDENTIALS = { |
32 | 'consumer_key': 'faked_consumer_key', |
33 | |
34 | === added file 'tests/platform/windows/test_credentials.py' |
35 | --- tests/platform/windows/test_credentials.py 1970-01-01 00:00:00 +0000 |
36 | +++ tests/platform/windows/test_credentials.py 2011-05-03 09:17:06 +0000 |
37 | @@ -0,0 +1,155 @@ |
38 | +#!/usr/bin/env python |
39 | +# -*- coding: utf-8 -*- |
40 | +# Author: Manuel de la Pena <manuel@canonical.com> |
41 | +# |
42 | +# Copyright 2011 Canonical Ltd. |
43 | +# |
44 | +# This program is free software: you can redistribute it and/or modify it |
45 | +# under the terms of the GNU General Public License version 3, as published |
46 | +# by the Free Software Foundation. |
47 | +# |
48 | +# This program is distributed in the hope that it will be useful, but |
49 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
50 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
51 | +# PURPOSE. See the GNU General Public License for more details. |
52 | +# |
53 | +# You should have received a copy of the GNU General Public License along |
54 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
55 | +"""Tests for the credentials management on Windows.""" |
56 | + |
57 | +from mocker import MockerTestCase |
58 | + |
59 | +from ubuntu_sso.credentials import HELP_TEXT_KEY, PING_URL_KEY, TC_URL_KEY |
60 | +from ubuntuone.platform.windows.credentials import ( |
61 | + CredentialsManagement, |
62 | + APP_NAME, |
63 | + DESCRIPTION, |
64 | + PING_URL, |
65 | + TC_URL) |
66 | + |
67 | + |
68 | +class TestCredentialsManagement(MockerTestCase): |
69 | + """Test that the credentials management is correctly used.""" |
70 | + |
71 | + def setUp(self): |
72 | + """Set the different tests.""" |
73 | + super(TestCredentialsManagement, self).setUp() |
74 | + self.proxy = self.mocker.mock() |
75 | + self.management = CredentialsManagement(self.proxy) |
76 | + |
77 | + def test_find_credentials(self): |
78 | + """Ensure we do ask corectly for the credentials.""" |
79 | + reply_handler = lambda: None |
80 | + error_handler = lambda: None |
81 | + self.proxy.find_credentials(APP_NAME, {}, reply_handler=reply_handler, |
82 | + error_handler=error_handler) |
83 | + self.mocker.replay() |
84 | + self.management.find_credentials(reply_handler=reply_handler, |
85 | + error_handler=error_handler) |
86 | + |
87 | + def test_clear_credentials(self): |
88 | + """Ensure we do clear the credentials.""" |
89 | + reply_handler = lambda: None |
90 | + error_handler = lambda: None |
91 | + self.proxy.clear_credentials(APP_NAME, {}, reply_handler=reply_handler, |
92 | + error_handler=error_handler) |
93 | + self.mocker.replay() |
94 | + self.management.clear_credentials(reply_handler=reply_handler, |
95 | + error_handler=error_handler) |
96 | + |
97 | + def test_store_credentials(self): |
98 | + """Store the token for Ubuntu One application.""" |
99 | + credentials = 'creds' |
100 | + reply_handler = lambda: None |
101 | + error_handler = lambda: None |
102 | + self.proxy.store_credentials(APP_NAME, credentials, |
103 | + reply_handler=reply_handler, error_handler=error_handler) |
104 | + self.mocker.replay() |
105 | + self.management.store_credentials(credentials, |
106 | + reply_handler=reply_handler, error_handler=error_handler) |
107 | + |
108 | + def test_register(self): |
109 | + """Get credentials if found else prompt to register to Ubuntu One.""" |
110 | + reply_handler = lambda: None |
111 | + error_handler = lambda: None |
112 | + args = dict(test='test', args='args') |
113 | + extra_params = {HELP_TEXT_KEY: DESCRIPTION, TC_URL_KEY: TC_URL, |
114 | + PING_URL_KEY: PING_URL} |
115 | + extra_params.update(args) |
116 | + self.proxy.register(APP_NAME, extra_params, |
117 | + reply_handler=reply_handler, error_handler=error_handler) |
118 | + self.mocker.replay() |
119 | + self.management.register(args, reply_handler, error_handler) |
120 | + |
121 | + def test_login(self): |
122 | + """Get credentials if found else prompt to login to Ubuntu One.""" |
123 | + reply_handler = lambda: None |
124 | + error_handler = lambda: None |
125 | + args = dict(test='test', args='args') |
126 | + extra_params = {HELP_TEXT_KEY: DESCRIPTION, TC_URL_KEY: TC_URL, |
127 | + PING_URL_KEY: PING_URL} |
128 | + extra_params.update(args) |
129 | + self.proxy.login(APP_NAME, extra_params, |
130 | + reply_handler=reply_handler, error_handler=error_handler) |
131 | + self.mocker.replay() |
132 | + self.management.login(args, reply_handler, error_handler) |
133 | + |
134 | + def test_register_to_credentials_stored(self): |
135 | + """Register to the CredentialsStored dbus signal.""" |
136 | + callback = lambda: None |
137 | + self.proxy.on_credentials_stored_cb = callback |
138 | + self.proxy.on_credentials_stored_cb |
139 | + self.mocker.result(callback) |
140 | + self.mocker.replay() |
141 | + self.assertIs(callback, |
142 | + self.management.register_to_credentials_stored(callback)) |
143 | + |
144 | + def test_register_to_credentials_cleared(self): |
145 | + """Register to the CredentialsCleared dbus signal.""" |
146 | + callback = lambda: None |
147 | + self.proxy.on_credentials_cleared_cb = callback |
148 | + self.proxy.on_credentials_cleared_cb |
149 | + self.mocker.result(callback) |
150 | + self.mocker.replay() |
151 | + self.assertIs(callback, |
152 | + self.management.register_to_credentials_cleared(callback)) |
153 | + |
154 | + def test_register_to_credentials_found(self): |
155 | + """Register to the CredentialsFound dbus signal.""" |
156 | + callback = lambda: None |
157 | + self.proxy.on_credentials_found_cb = callback |
158 | + self.proxy.on_credentials_found_cb |
159 | + self.mocker.result(callback) |
160 | + self.mocker.replay() |
161 | + self.assertIs(callback, |
162 | + self.management.register_to_credentials_found(callback)) |
163 | + |
164 | + def test_register_to_credentials_not_found(self): |
165 | + """Register to the CredentialsFound dbus signal.""" |
166 | + callback = lambda: None |
167 | + self.proxy.on_credentials_not_found_cb = callback |
168 | + self.proxy.on_credentials_not_found_cb |
169 | + self.mocker.result(callback) |
170 | + self.mocker.replay() |
171 | + self.assertIs(callback, |
172 | + self.management.register_to_credentials_not_found(callback)) |
173 | + |
174 | + def test_register_to_authorization_denied(self): |
175 | + """Register to the AuthorizationDenied dbus signal.""" |
176 | + callback = lambda: None |
177 | + self.proxy.on_authorization_denied_cb = callback |
178 | + self.proxy.on_authorization_denied_cb |
179 | + self.mocker.result(callback) |
180 | + self.mocker.replay() |
181 | + self.assertIs(callback, |
182 | + self.management.register_to_authorization_denied(callback)) |
183 | + |
184 | + def test_register_to_credentials_error(self): |
185 | + """Register to the CredentialsError dbus signal.""" |
186 | + callback = lambda: None |
187 | + self.proxy.on_credentials_error_cb = callback |
188 | + self.proxy.on_credentials_error_cb |
189 | + self.mocker.result(callback) |
190 | + self.mocker.replay() |
191 | + self.assertIs(callback, |
192 | + self.management.register_to_credentials_error(callback)) |
193 | |
194 | === added file 'tests/test_credentials.py' |
195 | --- tests/test_credentials.py 1970-01-01 00:00:00 +0000 |
196 | +++ tests/test_credentials.py 2011-05-03 09:17:06 +0000 |
197 | @@ -0,0 +1,99 @@ |
198 | +#!/usr/bin/env python |
199 | +# -*- coding: utf-8 -*- |
200 | +# |
201 | +# Author: Manuel de la Pena<manuel@canonical.com> |
202 | +# |
203 | +# Copyright 2011 Canonical Ltd. |
204 | +# |
205 | +# This program is free software: you can redistribute it and/or modify it |
206 | +# under the terms of the GNU General Public License version 3, as published |
207 | +# by the Free Software Foundation. |
208 | +# |
209 | +# This program is distributed in the hope that it will be useful, but |
210 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
211 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
212 | +# PURPOSE. See the GNU General Public License for more details. |
213 | +# |
214 | +# You should have received a copy of the GNU General Public License along |
215 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
216 | +"""Platform independent tests for the credentials management.""" |
217 | + |
218 | +from mocker import MockerTestCase, MATCH |
219 | + |
220 | +from ubuntuone.credentials import CredentialsManagementTool |
221 | + |
222 | + |
223 | +class TestCredentialsManagementTool(MockerTestCase): |
224 | + """Test the crendentials management tool mocking the proxy.""" |
225 | + |
226 | + def setUp(self): |
227 | + """Set the diff tests.""" |
228 | + super(TestCredentialsManagementTool, self).setUp() |
229 | + self.get_cred_proxy = self.mocker.replace( |
230 | + 'ubuntuone.platform.get_creds_proxy') |
231 | + self.proxy = self.mocker.mock() |
232 | + self.management_tool = CredentialsManagementTool() |
233 | + |
234 | + def test_find_credentials(self): |
235 | + """Test that we do ask for the credentials correctly.""" |
236 | + signals = ['creds_found', 'creds_not_found', 'creds_erro'] |
237 | + self.get_cred_proxy() |
238 | + self.mocker.result(self.proxy) |
239 | + self.proxy.register_to_credentials_found(MATCH(callable)) |
240 | + self.mocker.result(signals[0]) |
241 | + self.proxy.register_to_credentials_not_found(MATCH(callable)) |
242 | + self.mocker.result(signals[1]) |
243 | + self.proxy.register_to_credentials_error(MATCH(callable)) |
244 | + self.mocker.result(signals[2]) |
245 | + self.proxy.find_credentials(reply_handler=MATCH(callable), |
246 | + error_handler=MATCH(callable)) |
247 | + self.mocker.replay() |
248 | + return self.management_tool.find_credentials() |
249 | + |
250 | + def test_clear_credentials(self): |
251 | + """Test that we clear the credentials correctly.""" |
252 | + signals = ['creds_cleared', 'creds_error'] |
253 | + self.get_cred_proxy() |
254 | + self.mocker.result(self.proxy) |
255 | + self.proxy.register_to_credentials_cleared(MATCH(callable)) |
256 | + self.mocker.result(signals[0]) |
257 | + self.proxy.register_to_credentials_error(MATCH(callable)) |
258 | + self.mocker.result(signals[1]) |
259 | + self.proxy.clear_credentials(reply_handler=MATCH(callable), |
260 | + error_handler=MATCH(callable)) |
261 | + self.mocker.replay() |
262 | + return self.management_tool.clear_credentials() |
263 | + |
264 | + def test_store_credentials(self): |
265 | + """Test that we store the credentials correctly.""" |
266 | + token = 'token' |
267 | + signals = ['creds_stored','creds_error'] |
268 | + self.get_cred_proxy() |
269 | + self.mocker.result(self.proxy) |
270 | + self.proxy.register_to_credentials_stored(MATCH(callable)) |
271 | + self.mocker.result(signals[0]) |
272 | + self.proxy.register_to_credentials_error(MATCH(callable)) |
273 | + self.mocker.result(signals[1]) |
274 | + self.proxy.store_credentials(token, reply_handler=MATCH(callable), |
275 | + error_handler=MATCH(callable)) |
276 | + self.mocker.replay() |
277 | + return self.management_tool.store_credentials(token) |
278 | + |
279 | + def test_register(self): |
280 | + """Test that we correctly register.""" |
281 | + window_id = 10 |
282 | + window_id_dict = dict(window_id=str(window_id)) |
283 | + signals = ['creds_found', 'creds_denied', 'creds_error'] |
284 | + self.get_cred_proxy() |
285 | + self.mocker.result(self.proxy) |
286 | + self.proxy.register_to_credentials_found(MATCH(callable)) |
287 | + self.mocker.result(signals[0]) |
288 | + self.proxy.register_to_authorization_denied(MATCH(callable)) |
289 | + self.mocker.result(signals[1]) |
290 | + self.proxy.register_to_credentials_error(MATCH(callable)) |
291 | + self.mocker.result(signals[2]) |
292 | + self.proxy.register(window_id_dict, reply_handler=MATCH(callable), |
293 | + error_handler=MATCH(callable)) |
294 | + self.mocker.replay() |
295 | + return self.management_tool.register(window_id=window_id) |
296 | + |
297 | |
298 | === added file 'ubuntuone/credentials.py' |
299 | --- ubuntuone/credentials.py 1970-01-01 00:00:00 +0000 |
300 | +++ ubuntuone/credentials.py 2011-05-03 09:17:06 +0000 |
301 | @@ -0,0 +1,255 @@ |
302 | +#!/usr/bin/env python |
303 | +# -*- coding: utf-8 -*- |
304 | +# |
305 | +# Author: Natalia B. Bidart <natalia.bidart@canonical.com> |
306 | +# Author: Manuel de la Pena<manuel@canonical.com> |
307 | +# |
308 | +# Copyright 2011 Canonical Ltd. |
309 | +# |
310 | +# This program is free software: you can redistribute it and/or modify it |
311 | +# under the terms of the GNU General Public License version 3, as published |
312 | +# by the Free Software Foundation. |
313 | +# |
314 | +# This program is distributed in the hope that it will be useful, but |
315 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
316 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
317 | +# PURPOSE. See the GNU General Public License for more details. |
318 | +# |
319 | +# You should have received a copy of the GNU General Public License along |
320 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
321 | +"""Common code for the credentials management.""" |
322 | + |
323 | +import os |
324 | + |
325 | +from twisted.internet import defer |
326 | + |
327 | +from ubuntuone.logger import (basic_formatter, logging, |
328 | + CustomRotatingFileHandler, LOGFOLDER) |
329 | +from ubuntuone.platform import get_creds_proxy |
330 | + |
331 | +LOG_LEVEL = logging.DEBUG |
332 | +path = os.path.join(LOGFOLDER, 'credentials.log') |
333 | +MAIN_HANDLER = CustomRotatingFileHandler(path) |
334 | +MAIN_HANDLER.setFormatter(basic_formatter) |
335 | +MAIN_HANDLER.setLevel(LOG_LEVEL) |
336 | + |
337 | +logger = logging.getLogger("ubuntuone.credentials") |
338 | +logger.setLevel(LOG_LEVEL) |
339 | +logger.addHandler(MAIN_HANDLER) |
340 | + |
341 | + |
342 | +class CredentialsError(Exception): |
343 | + """A general exception when hadling credentilas.""" |
344 | + |
345 | + |
346 | +class CredentialsManagementTool(object): |
347 | + """Wrapper to CredentialsManagement. |
348 | + |
349 | + The goal of this class is to abstract the caller from calling the DBus |
350 | + service implemented in the class CredentialsManagement. |
351 | + |
352 | + """ |
353 | + |
354 | + def __init__(self): |
355 | + self._cleanup_signals = [] |
356 | + |
357 | + def cleanup(self, _): |
358 | + """Disconnect all the DBus signals.""" |
359 | + for sig in self._cleanup_signals: |
360 | + logger.debug('cleanup: removing signal match %r', sig) |
361 | + sig.remove() |
362 | + |
363 | + return _ |
364 | + |
365 | + @defer.inlineCallbacks |
366 | + def find_credentials(self): |
367 | + """Find credentials for Ubuntu One. |
368 | + |
369 | + Return a deferred that, when fired, will return the credentials for |
370 | + Ubuntu One for the current logged in user. |
371 | + |
372 | + The credentials is a dictionary with both string keys and values. The |
373 | + dictionary may be either empty if there are no credentials for the |
374 | + user, or will hold five items as follow: |
375 | + |
376 | + - "name" |
377 | + - "token" |
378 | + - "token_secret" |
379 | + - "consumer_key" |
380 | + - "consumer_secret" |
381 | + |
382 | + """ |
383 | + d = defer.Deferred() |
384 | + d.addBoth(self.cleanup) |
385 | + |
386 | + proxy = get_creds_proxy() |
387 | + |
388 | + sig = proxy.register_to_credentials_found(d.callback) |
389 | + self._cleanup_signals.append(sig) |
390 | + |
391 | + sig = proxy.register_to_credentials_not_found(lambda: d.callback({})) |
392 | + self._cleanup_signals.append(sig) |
393 | + |
394 | + sig = proxy.register_to_credentials_error( |
395 | + lambda error_dict: d.errback(CredentialsError(error_dict))) |
396 | + self._cleanup_signals.append(sig) |
397 | + |
398 | + done = defer.Deferred() |
399 | + proxy.find_credentials(reply_handler=lambda: done.callback(None), |
400 | + error_handler=lambda *a: done.errback(a)) |
401 | + |
402 | + yield done |
403 | + |
404 | + result = yield d |
405 | + defer.returnValue(result) |
406 | + |
407 | + @defer.inlineCallbacks |
408 | + def clear_credentials(self): |
409 | + """Clear credentials for Ubuntu One. |
410 | + |
411 | + Return a deferred that, when fired, will return no result but will |
412 | + indicate that the Ubuntu One credentials for the current user were |
413 | + removed from the local keyring. |
414 | + |
415 | + """ |
416 | + d = defer.Deferred() |
417 | + d.addBoth(self.cleanup) |
418 | + |
419 | + proxy = get_creds_proxy() |
420 | + sig = proxy.register_to_credentials_cleared(lambda: d.callback(None)) |
421 | + self._cleanup_signals.append(sig) |
422 | + |
423 | + sig = proxy.register_to_credentials_error( |
424 | + lambda error_dict: d.errback(CredentialsError(error_dict))) |
425 | + self._cleanup_signals.append(sig) |
426 | + |
427 | + done = defer.Deferred() |
428 | + proxy.clear_credentials(reply_handler=lambda: done.callback(None), |
429 | + error_handler=lambda *a: done.errback(a)) |
430 | + |
431 | + yield done |
432 | + |
433 | + yield d |
434 | + |
435 | + @defer.inlineCallbacks |
436 | + def store_credentials(self, token): |
437 | + """Store credentials for Ubuntu One. |
438 | + |
439 | + The parameter 'token' should be a dictionary that matches the |
440 | + description of the result of 'find_credentials'. |
441 | + |
442 | + Return a deferred that, when fired, will return no result but will |
443 | + indicate that 'token' was stored in the local keyring as the new Ubuntu |
444 | + One credentials for the current user. |
445 | + |
446 | + """ |
447 | + d = defer.Deferred() |
448 | + d.addBoth(self.cleanup) |
449 | + |
450 | + proxy = get_creds_proxy() |
451 | + sig = proxy.register_to_credentials_stored(lambda: d.callback(None)) |
452 | + self._cleanup_signals.append(sig) |
453 | + |
454 | + sig = proxy.register_to_credentials_error( |
455 | + lambda error_dict: d.errback(CredentialsError(error_dict))) |
456 | + self._cleanup_signals.append(sig) |
457 | + |
458 | + done = defer.Deferred() |
459 | + proxy.store_credentials(token, |
460 | + reply_handler=lambda: done.callback(None), |
461 | + error_handler=lambda *a: done.errback(a)) |
462 | + |
463 | + yield done |
464 | + |
465 | + yield d |
466 | + |
467 | + @defer.inlineCallbacks |
468 | + def register(self, window_id=0): |
469 | + """Register to Ubuntu One. |
470 | + |
471 | + Return a deferred that, when fired, will return the credentials for |
472 | + Ubuntu One for the current logged in user. |
473 | + |
474 | + If there are no credentials for the current user, a GTK UI will be |
475 | + opened to invite the user to register to Ubuntu One. This UI provides |
476 | + options to either register (main screen) or login (secondary screen). |
477 | + |
478 | + You can pass an optional 'window_id' parameter that will be used by the |
479 | + GTK UI to be set transient for it. |
480 | + |
481 | + The returned credentials will be either a non-empty dictionary like the |
482 | + one described in 'find_credentials', or None. The latter indicates that |
483 | + there were no credentials for the user in the local keyring and that |
484 | + the user refused to register to Ubuntu One. |
485 | + |
486 | + """ |
487 | + d = defer.Deferred() |
488 | + d.addBoth(self.cleanup) |
489 | + |
490 | + proxy = get_creds_proxy() |
491 | + |
492 | + sig = proxy.register_to_credentials_found(d.callback) |
493 | + self._cleanup_signals.append(sig) |
494 | + |
495 | + sig = proxy.register_to_authorization_denied(lambda: d.callback(None)) |
496 | + self._cleanup_signals.append(sig) |
497 | + |
498 | + sig = proxy.register_to_credentials_error( |
499 | + lambda error_dict: d.errback(CredentialsError(error_dict))) |
500 | + self._cleanup_signals.append(sig) |
501 | + |
502 | + done = defer.Deferred() |
503 | + proxy.register({'window_id': str(window_id)}, |
504 | + reply_handler=lambda: done.callback(None), |
505 | + error_handler=lambda *a: done.errback(a)) |
506 | + |
507 | + yield done |
508 | + |
509 | + result = yield d |
510 | + defer.returnValue(result) |
511 | + |
512 | + @defer.inlineCallbacks |
513 | + def login(self, window_id=0): |
514 | + """Login to Ubuntu One. |
515 | + |
516 | + Return a deferred that, when fired, will return the credentials for |
517 | + Ubuntu One for the current logged in user. |
518 | + |
519 | + If there are no credentials for the current user, a GTK UI will be |
520 | + opened to invite the user to login to Ubuntu One. This UI provides |
521 | + options to either login (main screen) or retrieve password (secondary |
522 | + screen). |
523 | + |
524 | + You can pass an optional 'window_id' parameter that will be used by the |
525 | + GTK UI to be set transient for it. |
526 | + |
527 | + The returned credentials will be either a non-empty dictionary like the |
528 | + one described in 'find_credentials', or None. The latter indicates that |
529 | + there were no credentials for the user in the local keyring and that |
530 | + the user refused to login to Ubuntu One. |
531 | + |
532 | + """ |
533 | + d = defer.Deferred() |
534 | + d.addBoth(self.cleanup) |
535 | + |
536 | + proxy = get_creds_proxy() |
537 | + |
538 | + sig = proxy.register_to_credentials_found(d.callback) |
539 | + self._cleanup_signals.append(sig) |
540 | + |
541 | + sig = proxy.register_to_authorization_denied(lambda: d.callback(None)) |
542 | + self._cleanup_signals.append(sig) |
543 | + |
544 | + sig = proxy.register_to_credentials_error( |
545 | + lambda error_dict: d.errback(CredentialsError(error_dict))) |
546 | + self._cleanup_signals.append(sig) |
547 | + |
548 | + done = defer.Deferred() |
549 | + proxy.login({'window_id': str(window_id)}, |
550 | + reply_handler=lambda: done.callback(None), |
551 | + error_handler=lambda *a: done.errback(a)) |
552 | + |
553 | + yield done |
554 | + |
555 | + result = yield d |
556 | + defer.returnValue(result) |
557 | |
558 | === modified file 'ubuntuone/platform/linux/__init__.py' |
559 | --- ubuntuone/platform/linux/__init__.py 2011-03-30 16:17:37 +0000 |
560 | +++ ubuntuone/platform/linux/__init__.py 2011-05-03 09:17:06 +0000 |
561 | @@ -51,7 +51,7 @@ |
562 | get_udf_path, |
563 | VMMetadataUpgraderMixIn |
564 | ) |
565 | -from ubuntuone.platform.linux.credentials import CredentialsManagement |
566 | +from ubuntuone.platform.linux.credentials import get_creds_proxy |
567 | from ubuntuone.platform.linux.logger import setup_filesystem_logging, get_filesystem_logger |
568 | from ubuntuone.platform.linux.filesystem_notifications import FilesystemMonitor |
569 | from ubuntuone.platform.linux.notification import Notification |
570 | |
571 | === modified file 'ubuntuone/platform/linux/credentials.py' |
572 | --- ubuntuone/platform/linux/credentials.py 2011-02-24 14:07:32 +0000 |
573 | +++ ubuntuone/platform/linux/credentials.py 2011-05-03 09:17:06 +0000 |
574 | @@ -15,7 +15,6 @@ |
575 | # |
576 | # You should have received a copy of the GNU General Public License along |
577 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
578 | - |
579 | """Ubuntu One credentials management dbus service.""" |
580 | |
581 | import os |
582 | @@ -24,7 +23,6 @@ |
583 | import gettext |
584 | import ubuntu_sso |
585 | |
586 | -from twisted.internet import defer |
587 | from ubuntu_sso.credentials import HELP_TEXT_KEY, PING_URL_KEY, TC_URL_KEY |
588 | |
589 | from ubuntuone.logger import (basic_formatter, logging, |
590 | @@ -238,237 +236,71 @@ |
591 | reply_handler=reply_handler, error_handler=error_handler) |
592 | |
593 | |
594 | -class CredentialsError(Exception): |
595 | - """A general exception when hadling credentilas.""" |
596 | - |
597 | - |
598 | -class CredentialsManagementTool(object): |
599 | - """Wrapper to CredentialsManagement. |
600 | - |
601 | - The goal of this class is to abstract the caller from calling the DBus |
602 | - service implemented in the class CredentialsManagement. |
603 | - |
604 | +class CredentialsManagementProxy(object): |
605 | + """Proxy that allows to work with the dbus api. |
606 | + |
607 | + This proxy has been added to hide the exact details of |
608 | + how the signals are connected. This allows the reuse of |
609 | + the CredentialsManagementTool in diff platforms. |
610 | """ |
611 | |
612 | def __init__(self): |
613 | - self._cleanup_signals = [] |
614 | - |
615 | - def _get_creds_proxy(self): |
616 | - """Get the CredentialsManagement dbus proxy.""" |
617 | + """Create a new instance.""" |
618 | bus = dbus.SessionBus() |
619 | try: |
620 | obj = bus.get_object(DBUS_BUS_NAME, |
621 | DBUS_CREDENTIALS_PATH, |
622 | follow_name_owner_changes=True) |
623 | - proxy = dbus.Interface(obj, DBUS_CREDENTIALS_IFACE) |
624 | + self.proxy = dbus.Interface(obj, DBUS_CREDENTIALS_IFACE) |
625 | except: |
626 | logger.exception('get_creds_proxy:') |
627 | raise |
628 | |
629 | - return proxy |
630 | - |
631 | - def cleanup(self, _): |
632 | - """Disconnect all the DBus signals.""" |
633 | - for sig in self._cleanup_signals: |
634 | - logger.debug('cleanup: removing signal match %r', sig) |
635 | - sig.remove() |
636 | - |
637 | - return _ |
638 | - |
639 | - @defer.inlineCallbacks |
640 | - def find_credentials(self): |
641 | - """Find credentials for Ubuntu One. |
642 | - |
643 | - Return a deferred that, when fired, will return the credentials for |
644 | - Ubuntu One for the current logged in user. |
645 | - |
646 | - The credentials is a dictionary with both string keys and values. The |
647 | - dictionary may be either empty if there are no credentials for the |
648 | - user, or will hold five items as follow: |
649 | - |
650 | - - "name" |
651 | - - "token" |
652 | - - "token_secret" |
653 | - - "consumer_key" |
654 | - - "consumer_secret" |
655 | - |
656 | - """ |
657 | - d = defer.Deferred() |
658 | - d.addBoth(self.cleanup) |
659 | - |
660 | - proxy = self._get_creds_proxy() |
661 | - |
662 | - sig = proxy.connect_to_signal('CredentialsFound', d.callback) |
663 | - self._cleanup_signals.append(sig) |
664 | - |
665 | - sig = proxy.connect_to_signal('CredentialsNotFound', |
666 | - lambda: d.callback({})) |
667 | - self._cleanup_signals.append(sig) |
668 | - |
669 | - sig = proxy.connect_to_signal('CredentialsError', |
670 | - lambda error_dict: d.errback(CredentialsError(error_dict))) |
671 | - self._cleanup_signals.append(sig) |
672 | - |
673 | - done = defer.Deferred() |
674 | - proxy.find_credentials(reply_handler=lambda: done.callback(None), |
675 | - error_handler=lambda *a: done.errback(a)) |
676 | - |
677 | - yield done |
678 | - |
679 | - result = yield d |
680 | - defer.returnValue(result) |
681 | - |
682 | - @defer.inlineCallbacks |
683 | - def clear_credentials(self): |
684 | - """Clear credentials for Ubuntu One. |
685 | - |
686 | - Return a deferred that, when fired, will return no result but will |
687 | - indicate that the Ubuntu One credentials for the current user were |
688 | - removed from the local keyring. |
689 | - |
690 | - """ |
691 | - d = defer.Deferred() |
692 | - d.addBoth(self.cleanup) |
693 | - |
694 | - proxy = self._get_creds_proxy() |
695 | - sig = proxy.connect_to_signal('CredentialsCleared', |
696 | - lambda: d.callback(None)) |
697 | - self._cleanup_signals.append(sig) |
698 | - |
699 | - sig = proxy.connect_to_signal('CredentialsError', |
700 | - lambda error_dict: d.errback(CredentialsError(error_dict))) |
701 | - self._cleanup_signals.append(sig) |
702 | - |
703 | - done = defer.Deferred() |
704 | - proxy.clear_credentials(reply_handler=lambda: done.callback(None), |
705 | - error_handler=lambda *a: done.errback(a)) |
706 | - |
707 | - yield done |
708 | - |
709 | - yield d |
710 | - |
711 | - @defer.inlineCallbacks |
712 | - def store_credentials(self, token): |
713 | - """Store credentials for Ubuntu One. |
714 | - |
715 | - The parameter 'token' should be a dictionary that matches the |
716 | - description of the result of 'find_credentials'. |
717 | - |
718 | - Return a deferred that, when fired, will return no result but will |
719 | - indicate that 'token' was stored in the local keyring as the new Ubuntu |
720 | - One credentials for the current user. |
721 | - |
722 | - """ |
723 | - d = defer.Deferred() |
724 | - d.addBoth(self.cleanup) |
725 | - |
726 | - proxy = self._get_creds_proxy() |
727 | - sig = proxy.connect_to_signal('CredentialsStored', |
728 | - lambda: d.callback(None)) |
729 | - self._cleanup_signals.append(sig) |
730 | - |
731 | - sig = proxy.connect_to_signal('CredentialsError', |
732 | - lambda error_dict: d.errback(CredentialsError(error_dict))) |
733 | - self._cleanup_signals.append(sig) |
734 | - |
735 | - done = defer.Deferred() |
736 | - proxy.store_credentials(token, |
737 | - reply_handler=lambda: done.callback(None), |
738 | - error_handler=lambda *a: done.errback(a)) |
739 | - |
740 | - yield done |
741 | - |
742 | - yield d |
743 | - |
744 | - @defer.inlineCallbacks |
745 | - def register(self, window_id=0): |
746 | - """Register to Ubuntu One. |
747 | - |
748 | - Return a deferred that, when fired, will return the credentials for |
749 | - Ubuntu One for the current logged in user. |
750 | - |
751 | - If there are no credentials for the current user, a GTK UI will be |
752 | - opened to invite the user to register to Ubuntu One. This UI provides |
753 | - options to either register (main screen) or login (secondary screen). |
754 | - |
755 | - You can pass an optional 'window_id' parameter that will be used by the |
756 | - GTK UI to be set transient for it. |
757 | - |
758 | - The returned credentials will be either a non-empty dictionary like the |
759 | - one described in 'find_credentials', or None. The latter indicates that |
760 | - there were no credentials for the user in the local keyring and that |
761 | - the user refused to register to Ubuntu One. |
762 | - |
763 | - """ |
764 | - d = defer.Deferred() |
765 | - d.addBoth(self.cleanup) |
766 | - |
767 | - proxy = self._get_creds_proxy() |
768 | - |
769 | - sig = proxy.connect_to_signal('CredentialsFound', d.callback) |
770 | - self._cleanup_signals.append(sig) |
771 | - |
772 | - sig = proxy.connect_to_signal('AuthorizationDenied', |
773 | - lambda: d.callback(None)) |
774 | - self._cleanup_signals.append(sig) |
775 | - |
776 | - sig = proxy.connect_to_signal('CredentialsError', |
777 | - lambda error_dict: d.errback(CredentialsError(error_dict))) |
778 | - self._cleanup_signals.append(sig) |
779 | - |
780 | - done = defer.Deferred() |
781 | - proxy.register({'window_id': str(window_id)}, |
782 | - reply_handler=lambda: done.callback(None), |
783 | - error_handler=lambda *a: done.errback(a)) |
784 | - |
785 | - yield done |
786 | - |
787 | - result = yield d |
788 | - defer.returnValue(result) |
789 | - |
790 | - @defer.inlineCallbacks |
791 | - def login(self, window_id=0): |
792 | - """Login to Ubuntu One. |
793 | - |
794 | - Return a deferred that, when fired, will return the credentials for |
795 | - Ubuntu One for the current logged in user. |
796 | - |
797 | - If there are no credentials for the current user, a GTK UI will be |
798 | - opened to invite the user to login to Ubuntu One. This UI provides |
799 | - options to either login (main screen) or retrieve password (secondary |
800 | - screen). |
801 | - |
802 | - You can pass an optional 'window_id' parameter that will be used by the |
803 | - GTK UI to be set transient for it. |
804 | - |
805 | - The returned credentials will be either a non-empty dictionary like the |
806 | - one described in 'find_credentials', or None. The latter indicates that |
807 | - there were no credentials for the user in the local keyring and that |
808 | - the user refused to login to Ubuntu One. |
809 | - |
810 | - """ |
811 | - d = defer.Deferred() |
812 | - d.addBoth(self.cleanup) |
813 | - |
814 | - proxy = self._get_creds_proxy() |
815 | - |
816 | - sig = proxy.connect_to_signal('CredentialsFound', d.callback) |
817 | - self._cleanup_signals.append(sig) |
818 | - |
819 | - sig = proxy.connect_to_signal('AuthorizationDenied', |
820 | - lambda: d.callback(None)) |
821 | - self._cleanup_signals.append(sig) |
822 | - |
823 | - sig = proxy.connect_to_signal('CredentialsError', |
824 | - lambda error_dict: d.errback(CredentialsError(error_dict))) |
825 | - self._cleanup_signals.append(sig) |
826 | - |
827 | - done = defer.Deferred() |
828 | - proxy.login({'window_id': str(window_id)}, |
829 | - reply_handler=lambda: done.callback(None), |
830 | - error_handler=lambda *a: done.errback(a)) |
831 | - |
832 | - yield done |
833 | - |
834 | - result = yield d |
835 | - defer.returnValue(result) |
836 | + def find_credentials(self, *args, **kwargs): |
837 | + """Relay the find_credentials method.""" |
838 | + return self.proxy.find_credentials(*args, **kwargs) |
839 | + |
840 | + def clear_credentials(self, *args, **kwargs): |
841 | + """Relay the clear_credentials method.""" |
842 | + return self.proxy.clear_credentials(*args, **kwargs) |
843 | + |
844 | + def store_credentials(self, *args, **kwargs): |
845 | + """Relay the store_credentials method.""" |
846 | + return self.proxy.store_credentials(*args, **kwargs) |
847 | + |
848 | + def register(self, *args, **kwargs): |
849 | + """Relay the register method.""" |
850 | + return self.proxy.register(*args, **kwargs) |
851 | + |
852 | + def login(self, *args, **kwargs): |
853 | + """Relay the login method.""" |
854 | + return self.proxy.login(*args, **kwargs) |
855 | + |
856 | + def register_to_credentials_stored(self, callback): |
857 | + """Register to the CredentialsStored dbus signal.""" |
858 | + return self.proxy.connect_to_signal('CredentialsStored', callback) |
859 | + |
860 | + def register_to_credentials_cleared(self, callback): |
861 | + """Register to the CredentialsCleared dbus signal.""" |
862 | + return self.proxy.connect_to_signal('CredentialsCleared', callback) |
863 | + |
864 | + def register_to_credentials_found(self, callback): |
865 | + """Register to the CredentialsFound dbus signal.""" |
866 | + return self.proxy.connect_to_signal('CredentialsFound', callback) |
867 | + |
868 | + def register_to_credentials_not_found(self, callback): |
869 | + """Register to the CredentialsFound dbus signal.""" |
870 | + return self.proxy.connect_to_signal('CredentialsNotFound', callback) |
871 | + |
872 | + def register_to_authorization_denied(self, callback): |
873 | + """Register to the AuthorizationDenied dbus signal.""" |
874 | + return self.proxy.connect_to_signal('AuthorizationDenied', callback) |
875 | + |
876 | + def register_to_credentials_error(self, callback): |
877 | + """Register to the CredentialsError dbus signal.""" |
878 | + return self.proxy.connect_to_signal('CredentialsError', callback) |
879 | + |
880 | + |
881 | +def get_creds_proxy(): |
882 | + """Get the CredentialsManagement dbus proxy.""" |
883 | + return CredentialsManagementProxy() |
884 | |
885 | === added file 'ubuntuone/platform/windows/credentials.py' |
886 | --- ubuntuone/platform/windows/credentials.py 1970-01-01 00:00:00 +0000 |
887 | +++ ubuntuone/platform/windows/credentials.py 2011-05-03 09:17:06 +0000 |
888 | @@ -0,0 +1,131 @@ |
889 | +#!/usr/bin/env python |
890 | +# -*- coding: utf-8 -*- |
891 | +# |
892 | +# Author: Manuel de la Pena<manuel@canonical.com> |
893 | +# |
894 | +# Copyright 2011 Canonical Ltd. |
895 | +# |
896 | +# This program is free software: you can redistribute it and/or modify it |
897 | +# under the terms of the GNU General Public License version 3, as published |
898 | +# by the Free Software Foundation. |
899 | +# |
900 | +# This program is distributed in the hope that it will be useful, but |
901 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
902 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
903 | +# PURPOSE. See the GNU General Public License for more details. |
904 | +# |
905 | +# You should have received a copy of the GNU General Public License along |
906 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
907 | +"""Ubuntu One credentials management IPC service.""" |
908 | + |
909 | +import os |
910 | + |
911 | +import gettext |
912 | + |
913 | +from ubuntu_sso.main.windows import UbuntuSSOClient |
914 | +from ubuntu_sso.credentials import HELP_TEXT_KEY, PING_URL_KEY, TC_URL_KEY |
915 | +from twisted.internet import defer |
916 | + |
917 | +from ubuntuone.logger import (basic_formatter, logging, |
918 | + CustomRotatingFileHandler, LOGFOLDER) |
919 | +from ubuntuone.clientdefs import GETTEXT_PACKAGE |
920 | + |
921 | + |
922 | +Q_ = lambda string: gettext.dgettext(GETTEXT_PACKAGE, string) |
923 | +NO_OP = lambda *args, **kwargs: None |
924 | + |
925 | +LOG_LEVEL = logging.DEBUG |
926 | +path = os.path.join(LOGFOLDER, 'credentials.log') |
927 | +MAIN_HANDLER = CustomRotatingFileHandler(path) |
928 | +MAIN_HANDLER.setFormatter(basic_formatter) |
929 | +MAIN_HANDLER.setLevel(LOG_LEVEL) |
930 | + |
931 | +logger = logging.getLogger("ubuntuone.credentials") |
932 | +logger.setLevel(LOG_LEVEL) |
933 | +logger.addHandler(MAIN_HANDLER) |
934 | + |
935 | +APP_NAME = "Ubuntu One" |
936 | +TC_URL = "https://one.ubuntu.com/terms/" |
937 | +PING_URL = "https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/" |
938 | +DESCRIPTION = Q_('Ubuntu One requires an Ubuntu Single Sign On (SSO) account. ' |
939 | + 'This process will allow you to create a new account, ' |
940 | + 'if you do not yet have one.') |
941 | + |
942 | + |
943 | +class CredentialsManagement(object): |
944 | + """Object that manages Ubuntu One credentials.""" |
945 | + |
946 | + def __init__(self, proxy, *args, **kwargs): |
947 | + super(CredentialsManagement, self).__init__(*args, **kwargs) |
948 | + self.sso_proxy = proxy |
949 | + |
950 | + def find_credentials(self, reply_handler=NO_OP, error_handler=NO_OP): |
951 | + """Ask the Ubuntu One credentials.""" |
952 | + self.sso_proxy.find_credentials(APP_NAME, {}, |
953 | + reply_handler=reply_handler, error_handler=error_handler) |
954 | + |
955 | + |
956 | + def clear_credentials(self, reply_handler=NO_OP, error_handler=NO_OP): |
957 | + """Clear the Ubuntu One credentials.""" |
958 | + self.sso_proxy.clear_credentials(APP_NAME, {}, |
959 | + reply_handler=reply_handler, error_handler=error_handler) |
960 | + |
961 | + def store_credentials(self, credentials, |
962 | + reply_handler=NO_OP, error_handler=NO_OP): |
963 | + """Store the token for Ubuntu One application.""" |
964 | + self.sso_proxy.store_credentials(APP_NAME, credentials, |
965 | + reply_handler=reply_handler, error_handler=error_handler) |
966 | + |
967 | + def register(self, args, reply_handler=NO_OP, error_handler=NO_OP): |
968 | + """Get credentials if found else prompt to register to Ubuntu One.""" |
969 | + params = {HELP_TEXT_KEY: DESCRIPTION, TC_URL_KEY: TC_URL, |
970 | + PING_URL_KEY: PING_URL} |
971 | + params.update(args) |
972 | + self.sso_proxy.register(APP_NAME, params, |
973 | + reply_handler=reply_handler, error_handler=error_handler) |
974 | + |
975 | + def login(self, args, reply_handler=NO_OP, error_handler=NO_OP): |
976 | + """Get credentials if found else prompt to login to Ubuntu One.""" |
977 | + params = {HELP_TEXT_KEY: DESCRIPTION, TC_URL_KEY: TC_URL, |
978 | + PING_URL_KEY: PING_URL} |
979 | + params.update(args) |
980 | + self.sso_proxy.login(APP_NAME, params, |
981 | + reply_handler=reply_handler, error_handler=error_handler) |
982 | + |
983 | + def register_to_credentials_stored(self, callback): |
984 | + """Register to the CredentialsStored dbus signal.""" |
985 | + self.sso_proxy.on_credentials_stored_cb = callback |
986 | + return self.sso_proxy.on_credentials_stored_cb |
987 | + |
988 | + def register_to_credentials_cleared(self, callback): |
989 | + """Register to the CredentialsCleared dbus signal.""" |
990 | + self.sso_proxy.on_credentials_cleared_cb = callback |
991 | + return self.sso_proxy.on_credentials_cleared_cb |
992 | + |
993 | + def register_to_credentials_found(self, callback): |
994 | + """Register to the CredentialsFound dbus signal.""" |
995 | + self.sso_proxy.on_credentials_found_cb = callback |
996 | + return self.sso_proxy.on_credentials_found_cb |
997 | + |
998 | + def register_to_credentials_not_found(self, callback): |
999 | + """Register to the CredentialsFound dbus signal.""" |
1000 | + self.sso_proxy.on_credentials_not_found_cb = callback |
1001 | + return self.sso_proxy.on_credentials_not_found_cb |
1002 | + |
1003 | + def register_to_authorization_denied(self, callback): |
1004 | + """Register to the AuthorizationDenied dbus signal.""" |
1005 | + self.sso_proxy.on_authorization_denied_cb = callback |
1006 | + return self.sso_proxy.on_authorization_denied_cb |
1007 | + |
1008 | + def register_to_credentials_error(self, callback): |
1009 | + """Register to the CredentialsError dbus signal.""" |
1010 | + self.sso_proxy.on_credentials_error_cb = callback |
1011 | + return self.sso_proxy.on_credentials_error_cb |
1012 | + |
1013 | + |
1014 | +@defer.inlineCallbacks |
1015 | +def get_creds_proxy(): |
1016 | + """Get the CredentialsManagement dbus proxy.""" |
1017 | + client = UbuntuSSOClient() |
1018 | + client = yield client.connect() |
1019 | + defer.returnValue(CredentialsManagement(client.cred_management)) |
Passes tests and nothing big pops out in the code