Merge lp:~alecu/ubuntu-sso-client/credentials-interface into lp:ubuntu-sso-client
- credentials-interface
- Merge into trunk
Proposed by
Alejandro J. Cura
Status: | Merged |
---|---|
Approved by: | Rodrigo Moya |
Approved revision: | 565 |
Merged at revision: | 559 |
Proposed branch: | lp:~alecu/ubuntu-sso-client/credentials-interface |
Merge into: | lp:ubuntu-sso-client |
Diff against target: |
577 lines (+340/-36) 6 files modified
bin/ubuntu-sso-login (+7/-2) ubuntu_sso/__init__.py (+1/-0) ubuntu_sso/keyring.py (+111/-0) ubuntu_sso/main.py (+74/-18) ubuntu_sso/tests/test_gui.py (+0/-10) ubuntu_sso/tests/test_main.py (+147/-6) |
To merge this branch: | bzr merge lp:~alecu/ubuntu-sso-client/credentials-interface |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Rodrigo Moya (community) | Approve | ||
Natalia Bidart (community) | Approve | ||
Review via email: mp+31896@code.launchpad.net |
Commit message
DBus interface for getting the credentials from the keyring, or show a dialog to login/register
Description of the change
DBus interface for getting the credentials from the keyring, or show a dialog to login/register
To post a comment you must log in.
- 564. By Alejandro J. Cura
-
nessita's eagle eye spotted this pring
- 565. By Alejandro J. Cura
-
do not store the keyring tokens yet
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bin/ubuntu-sso-login' | |||
2 | --- bin/ubuntu-sso-login 2010-08-03 20:03:44 +0000 | |||
3 | +++ bin/ubuntu-sso-login 2010-08-06 02:49:40 +0000 | |||
4 | @@ -30,12 +30,13 @@ | |||
5 | 30 | 30 | ||
6 | 31 | from dbus.mainloop.glib import DBusGMainLoop | 31 | from dbus.mainloop.glib import DBusGMainLoop |
7 | 32 | 32 | ||
10 | 33 | from ubuntu_sso import DBUS_IFACE_AUTH_NAME, DBUS_BUS_NAME | 33 | from ubuntu_sso import DBUS_IFACE_AUTH_NAME, DBUS_BUS_NAME, DBUS_CRED_PATH |
11 | 34 | from ubuntu_sso.main import Login, SSOLogin | 34 | from ubuntu_sso.main import Login, SSOLogin, SSOCredentials |
12 | 35 | 35 | ||
13 | 36 | from ubuntu_sso.logger import setupLogging | 36 | from ubuntu_sso.logger import setupLogging |
14 | 37 | logger = setupLogging("ubuntu-sso-login") | 37 | logger = setupLogging("ubuntu-sso-login") |
15 | 38 | 38 | ||
16 | 39 | gtk.gdk.threads_init() | ||
17 | 39 | DBusGMainLoop(set_as_default=True) | 40 | DBusGMainLoop(set_as_default=True) |
18 | 40 | 41 | ||
19 | 41 | _ = gettext.gettext | 42 | _ = gettext.gettext |
20 | @@ -235,5 +236,9 @@ | |||
21 | 235 | bus=dbus.SessionBus())) | 236 | bus=dbus.SessionBus())) |
22 | 236 | ssoLogin = SSOLogin(dbus.service.BusName(DBUS_BUS_NAME, | 237 | ssoLogin = SSOLogin(dbus.service.BusName(DBUS_BUS_NAME, |
23 | 237 | bus=dbus.SessionBus())) | 238 | bus=dbus.SessionBus())) |
24 | 239 | SSOCredentials(dbus.service.BusName(DBUS_BUS_NAME, | ||
25 | 240 | bus=dbus.SessionBus()), | ||
26 | 241 | object_path=DBUS_CRED_PATH) | ||
27 | 242 | |||
28 | 238 | manager = LoginMain() | 243 | manager = LoginMain() |
29 | 239 | manager.main() | 244 | manager.main() |
30 | 240 | 245 | ||
31 | === modified file 'ubuntu_sso/__init__.py' | |||
32 | --- ubuntu_sso/__init__.py 2010-08-03 15:02:15 +0000 | |||
33 | +++ ubuntu_sso/__init__.py 2010-08-06 02:49:40 +0000 | |||
34 | @@ -19,6 +19,7 @@ | |||
35 | 19 | DBUS_PATH_AUTH = "/" | 19 | DBUS_PATH_AUTH = "/" |
36 | 20 | DBUS_BUS_NAME = "com.ubuntu.sso" | 20 | DBUS_BUS_NAME = "com.ubuntu.sso" |
37 | 21 | DBUS_PATH = "/sso" | 21 | DBUS_PATH = "/sso" |
38 | 22 | DBUS_CRED_PATH = "/credentials" | ||
39 | 22 | DBUS_IFACE_AUTH_NAME = "com.ubuntu.sso" | 23 | DBUS_IFACE_AUTH_NAME = "com.ubuntu.sso" |
40 | 23 | DBUS_IFACE_USER_NAME = "com.ubuntu.sso.UserManagement" | 24 | DBUS_IFACE_USER_NAME = "com.ubuntu.sso.UserManagement" |
41 | 24 | DBUS_IFACE_CRED_NAME = "com.ubuntu.sso.ApplicationCredentials" | 25 | DBUS_IFACE_CRED_NAME = "com.ubuntu.sso.ApplicationCredentials" |
42 | 25 | 26 | ||
43 | === added file 'ubuntu_sso/keyring.py' | |||
44 | --- ubuntu_sso/keyring.py 1970-01-01 00:00:00 +0000 | |||
45 | +++ ubuntu_sso/keyring.py 2010-08-06 02:49:40 +0000 | |||
46 | @@ -0,0 +1,111 @@ | |||
47 | 1 | # Copyright (C) 2010 Canonical | ||
48 | 2 | # | ||
49 | 3 | # Authors: | ||
50 | 4 | # Andrew Higginson | ||
51 | 5 | # | ||
52 | 6 | # This program is free software; you can redistribute it and/or modify it under | ||
53 | 7 | # the terms of the GNU General Public License as published by the Free Software | ||
54 | 8 | # Foundation; version 3. | ||
55 | 9 | # | ||
56 | 10 | # This program is distributed in the hope that it will be useful, but WITHOUT | ||
57 | 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
58 | 12 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | ||
59 | 13 | # details. | ||
60 | 14 | # | ||
61 | 15 | # You should have received a copy of the GNU General Public License along with | ||
62 | 16 | # this program; if not, write to the Free Software Foundation, Inc., | ||
63 | 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
64 | 18 | |||
65 | 19 | import gnomekeyring | ||
66 | 20 | |||
67 | 21 | from urllib import urlencode | ||
68 | 22 | from urlparse import parse_qs | ||
69 | 23 | |||
70 | 24 | class Keyring(object): | ||
71 | 25 | |||
72 | 26 | KEYRING_NAME = "login" | ||
73 | 27 | |||
74 | 28 | def __init__(self, app_name): | ||
75 | 29 | |||
76 | 30 | if not gnomekeyring.is_available(): | ||
77 | 31 | raise gnomekeyring.NoKeyringDaemonError | ||
78 | 32 | self.app_name = app_name | ||
79 | 33 | |||
80 | 34 | def _create_keyring(self, name): | ||
81 | 35 | """ | ||
82 | 36 | Creates a keyring, if it already exists, | ||
83 | 37 | it does nothing | ||
84 | 38 | """ | ||
85 | 39 | keyring_names = gnomekeyring.list_keyring_names_sync() | ||
86 | 40 | if not name in keyring_names: | ||
87 | 41 | gnomekeyring.create_sync(name) | ||
88 | 42 | |||
89 | 43 | def _item_exists(self, sync, name): | ||
90 | 44 | """ | ||
91 | 45 | Returns whether a named item exists in a | ||
92 | 46 | named keyring | ||
93 | 47 | """ | ||
94 | 48 | return self._get_item_id_from_name(sync, name) != None | ||
95 | 49 | |||
96 | 50 | def _get_item_id_from_name(self, sync, name): | ||
97 | 51 | """ | ||
98 | 52 | Returns the ID for a named item | ||
99 | 53 | """ | ||
100 | 54 | for item_id in gnomekeyring.list_item_ids_sync(sync): | ||
101 | 55 | item_info = gnomekeyring.item_get_info_sync(sync, item_id) | ||
102 | 56 | display_name = item_info.get_display_name() | ||
103 | 57 | if display_name == name: | ||
104 | 58 | return item_id | ||
105 | 59 | return None | ||
106 | 60 | |||
107 | 61 | def _get_item_info_from_name(self, sync, name): | ||
108 | 62 | """ | ||
109 | 63 | Returns the ID for a named item | ||
110 | 64 | """ | ||
111 | 65 | for item_id in gnomekeyring.list_item_ids_sync(sync): | ||
112 | 66 | item_info = gnomekeyring.item_get_info_sync(sync, item_id) | ||
113 | 67 | display_name = item_info.get_display_name() | ||
114 | 68 | if display_name == name: | ||
115 | 69 | return item_info | ||
116 | 70 | return None | ||
117 | 71 | |||
118 | 72 | def set_ubuntusso_attr(self, attr): | ||
119 | 73 | """ | ||
120 | 74 | Sets the attributes of the Ubuntu SSO item | ||
121 | 75 | """ | ||
122 | 76 | # Creates the secret from the attributes | ||
123 | 77 | secret = urlencode(attr) | ||
124 | 78 | |||
125 | 79 | # Create the keyring | ||
126 | 80 | self._create_keyring(self.KEYRING_NAME) | ||
127 | 81 | |||
128 | 82 | # If the item already exists, delete it | ||
129 | 83 | if self._item_exists(self.KEYRING_NAME, self.app_name): | ||
130 | 84 | item_id = self._get_item_id_from_name(self.KEYRING_NAME, | ||
131 | 85 | self.app_name) | ||
132 | 86 | gnomekeyring.item_delete_sync(self.KEYRING_NAME, item_id) | ||
133 | 87 | |||
134 | 88 | # Add our SSO item | ||
135 | 89 | gnomekeyring.item_create_sync(self.KEYRING_NAME, | ||
136 | 90 | gnomekeyring.ITEM_GENERIC_SECRET, self.app_name, {}, | ||
137 | 91 | secret, True) | ||
138 | 92 | |||
139 | 93 | def get_ubuntusso_attr(self): | ||
140 | 94 | """ | ||
141 | 95 | Returns the secret of the SSO item in a dictionary | ||
142 | 96 | """ | ||
143 | 97 | # If we have no attributes, return None | ||
144 | 98 | if self._get_item_info_from_name(self.KEYRING_NAME, | ||
145 | 99 | self.app_name) == None: | ||
146 | 100 | return None | ||
147 | 101 | secret = self._get_item_info_from_name(self.KEYRING_NAME, | ||
148 | 102 | self.app_name).get_secret() | ||
149 | 103 | return parse_qs(secret) | ||
150 | 104 | |||
151 | 105 | if __name__ == "__main__": | ||
152 | 106 | SSO_ITEM_NAME = "Software Center UbuntuSSO token" | ||
153 | 107 | keyring = Keyring(SSO_ITEM_NAME) | ||
154 | 108 | keyring.set_ubuntusso_attr({"ha":"hehddddeff", "hi":"hggehes", "ho":"he"}) | ||
155 | 109 | print keyring.get_ubuntusso_attr() | ||
156 | 110 | |||
157 | 111 | |||
158 | 0 | 112 | ||
159 | === modified file 'ubuntu_sso/main.py' | |||
160 | --- ubuntu_sso/main.py 2010-08-05 02:24:33 +0000 | |||
161 | +++ ubuntu_sso/main.py 2010-08-06 02:49:40 +0000 | |||
162 | @@ -34,6 +34,7 @@ | |||
163 | 34 | 34 | ||
164 | 35 | import dbus.service | 35 | import dbus.service |
165 | 36 | import gobject | 36 | import gobject |
166 | 37 | import gtk | ||
167 | 37 | import pynotify | 38 | import pynotify |
168 | 38 | 39 | ||
169 | 39 | from dbus.mainloop.glib import DBusGMainLoop | 40 | from dbus.mainloop.glib import DBusGMainLoop |
170 | @@ -43,20 +44,18 @@ | |||
171 | 43 | from lazr.restfulclient.resource import ServiceRoot | 44 | from lazr.restfulclient.resource import ServiceRoot |
172 | 44 | from oauth.oauth import OAuthToken | 45 | from oauth.oauth import OAuthToken |
173 | 45 | 46 | ||
174 | 47 | from keyring import Keyring | ||
175 | 46 | from ubuntu_sso import (DBUS_IFACE_AUTH_NAME, | 48 | from ubuntu_sso import (DBUS_IFACE_AUTH_NAME, |
176 | 47 | DBUS_IFACE_USER_NAME, | 49 | DBUS_IFACE_USER_NAME, |
177 | 48 | DBUS_IFACE_CRED_NAME, | 50 | DBUS_IFACE_CRED_NAME, |
178 | 51 | DBUS_CRED_PATH, | ||
179 | 49 | DBUS_BUS_NAME) | 52 | DBUS_BUS_NAME) |
180 | 50 | from ubuntu_sso.config import get_config | 53 | from ubuntu_sso.config import get_config |
181 | 51 | 54 | ||
182 | 52 | from ubuntu_sso.logger import setupLogging | 55 | from ubuntu_sso.logger import setupLogging |
183 | 53 | logger = setupLogging("ubuntu_sso.main") | 56 | logger = setupLogging("ubuntu_sso.main") |
184 | 54 | 57 | ||
185 | 55 | |||
186 | 56 | DBusGMainLoop(set_as_default=True) | 58 | DBusGMainLoop(set_as_default=True) |
187 | 57 | dbus.mainloop.glib.threads_init() | ||
188 | 58 | gobject.threads_init() | ||
189 | 59 | |||
190 | 60 | # Disable the invalid name warning, as we have a lot of DBus style names | 59 | # Disable the invalid name warning, as we have a lot of DBus style names |
191 | 61 | # pylint: disable-msg=C0103 | 60 | # pylint: disable-msg=C0103 |
192 | 62 | 61 | ||
193 | @@ -92,6 +91,21 @@ | |||
194 | 92 | """The email token is not valid.""" | 91 | """The email token is not valid.""" |
195 | 93 | 92 | ||
196 | 94 | 93 | ||
197 | 94 | def keyring_store_token(token_name, token): | ||
198 | 95 | """Store the credentials in the keyring.""" | ||
199 | 96 | attr = {"token": token} | ||
200 | 97 | Keyring(token_name).set_ubuntusso_attr(attr) | ||
201 | 98 | |||
202 | 99 | |||
203 | 100 | def keyring_get_token(token_name): | ||
204 | 101 | """Get the credentials from the keyring or None if not there.""" | ||
205 | 102 | d = Keyring(token_name).get_ubuntusso_attr() | ||
206 | 103 | if d is not None: | ||
207 | 104 | return d["token"] | ||
208 | 105 | else: | ||
209 | 106 | return None | ||
210 | 107 | |||
211 | 108 | |||
212 | 95 | class SSOLoginProcessor(object): | 109 | class SSOLoginProcessor(object): |
213 | 96 | """Login and register users using the Ubuntu Single Sign On service.""" | 110 | """Login and register users using the Ubuntu Single Sign On service.""" |
214 | 97 | 111 | ||
215 | @@ -208,7 +222,7 @@ | |||
216 | 208 | try: | 222 | try: |
217 | 209 | result_cb(f()) | 223 | result_cb(f()) |
218 | 210 | except Exception, e: | 224 | except Exception, e: |
220 | 211 | logger.error(e) | 225 | logger.exception(e) |
221 | 212 | error_cb(str(e)) | 226 | error_cb(str(e)) |
222 | 213 | threading.Thread(target=_in_thread).start() | 227 | threading.Thread(target=_in_thread).start() |
223 | 214 | 228 | ||
224 | @@ -230,9 +244,6 @@ | |||
225 | 230 | return self.sso_login_processor_class( | 244 | return self.sso_login_processor_class( |
226 | 231 | sso_service_class=self.sso_service_class) | 245 | sso_service_class=self.sso_service_class) |
227 | 232 | 246 | ||
228 | 233 | # ======================================== | ||
229 | 234 | # DBUS_IFACE_USER_NAME methods and signals | ||
230 | 235 | |||
231 | 236 | # generate_capcha signals | 247 | # generate_capcha signals |
232 | 237 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="s") | 248 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="s") |
233 | 238 | def CaptchaGenerated(self, result): | 249 | def CaptchaGenerated(self, result): |
234 | @@ -285,7 +296,10 @@ | |||
235 | 285 | """Call the matching method in the processor.""" | 296 | """Call the matching method in the processor.""" |
236 | 286 | def f(): | 297 | def f(): |
237 | 287 | """Inner function that will be run in a thread.""" | 298 | """Inner function that will be run in a thread.""" |
239 | 288 | return self.processor().login(email, password, token_name) | 299 | token = self.processor().login(email, password, token_name) |
240 | 300 | # XXX: will be fixed in upcoming branch | ||
241 | 301 | #keyring_store_token(token_name, token) | ||
242 | 302 | return "Ok" | ||
243 | 289 | return blocking(f, self.LoggedIn, self.LoginError) | 303 | return blocking(f, self.LoggedIn, self.LoginError) |
244 | 290 | 304 | ||
245 | 291 | # validate_email signals | 305 | # validate_email signals |
246 | @@ -307,8 +321,9 @@ | |||
247 | 307 | token_name, email_token) | 321 | token_name, email_token) |
248 | 308 | return blocking(f, self.EmailValidated, self.EmailValidationError) | 322 | return blocking(f, self.EmailValidated, self.EmailValidationError) |
249 | 309 | 323 | ||
252 | 310 | # ---------------------------------------- | 324 | |
253 | 311 | # DBUS_IFACE_CRED_NAME methods and signals | 325 | class SSOCredentials(dbus.service.Object): |
254 | 326 | """DBus object that gets credentials, and login/registers if needed.""" | ||
255 | 312 | 327 | ||
256 | 313 | @dbus.service.signal(DBUS_IFACE_CRED_NAME, signature="s") | 328 | @dbus.service.signal(DBUS_IFACE_CRED_NAME, signature="s") |
257 | 314 | def CredentialsFound(self, result): | 329 | def CredentialsFound(self, result): |
258 | @@ -319,17 +334,53 @@ | |||
259 | 319 | """Signal thrown when there is a problem finding the credentials.""" | 334 | """Signal thrown when there is a problem finding the credentials.""" |
260 | 320 | 335 | ||
261 | 321 | @dbus.service.method(dbus_interface=DBUS_IFACE_CRED_NAME, | 336 | @dbus.service.method(dbus_interface=DBUS_IFACE_CRED_NAME, |
266 | 322 | in_signature="s", out_signature="") | 337 | in_signature="s", out_signature="s") |
267 | 323 | def find_credentials(self, application_name): | 338 | def find_credentials(self, token_name): |
268 | 324 | # XXX: placeholder; coming in the following branch | 339 | """Get the credentials from the keyring or '' if not there.""" |
269 | 325 | pass | 340 | token = keyring_get_token(token_name) |
270 | 341 | if token is None: | ||
271 | 342 | return "" | ||
272 | 343 | else: | ||
273 | 344 | return token | ||
274 | 345 | |||
275 | 346 | def _response_cb(self, dialog, response, token_name): | ||
276 | 347 | """Handles the response from the UI dialog.""" | ||
277 | 348 | # XXX: to be replaced in the following branch | ||
278 | 349 | try: | ||
279 | 350 | token = "token%d" % response | ||
280 | 351 | keyring_store_token(token_name, token) | ||
281 | 352 | self.CredentialsFound(token) | ||
282 | 353 | except Exception, e: | ||
283 | 354 | self.CredentialsError(str(e)) | ||
284 | 355 | dialog.destroy() | ||
285 | 356 | |||
286 | 357 | def _show_login_or_register_ui(self, token_name, terms_and_conditions_url): | ||
287 | 358 | """Shows the UI so the user can login or register.""" | ||
288 | 359 | # XXX: to be replaced in the following branch | ||
289 | 360 | try: | ||
290 | 361 | dialog = gtk.MessageDialog(None, | ||
291 | 362 | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, | ||
292 | 363 | gtk.BUTTONS_CLOSE, terms_and_conditions_url) | ||
293 | 364 | dialog.connect("response", self._response_cb, token_name) | ||
294 | 365 | dialog.show() | ||
295 | 366 | except Exception, e: | ||
296 | 367 | self.CredentialsError(str(e)) | ||
297 | 326 | 368 | ||
298 | 327 | @dbus.service.method(dbus_interface=DBUS_IFACE_CRED_NAME, | 369 | @dbus.service.method(dbus_interface=DBUS_IFACE_CRED_NAME, |
299 | 328 | in_signature="ss", out_signature="") | 370 | in_signature="ss", out_signature="") |
301 | 329 | def login_or_register_to_get_credentials(self, application_name, | 371 | def login_or_register_to_get_credentials(self, token_name, |
302 | 330 | terms_and_conditions_url): | 372 | terms_and_conditions_url): |
305 | 331 | # XXX: placeholder; coming in the following branch | 373 | |
306 | 332 | pass | 374 | """Get credentials if found else prompt to login or register first.""" |
307 | 375 | try: | ||
308 | 376 | token = keyring_get_token(token_name) | ||
309 | 377 | if token is None: | ||
310 | 378 | gobject.idle_add(self._show_login_or_register_ui, token_name, | ||
311 | 379 | terms_and_conditions_url) | ||
312 | 380 | else: | ||
313 | 381 | self.CredentialsFound(token) | ||
314 | 382 | except Exception, e: | ||
315 | 383 | self.CredentialsError(str(e)) | ||
316 | 333 | 384 | ||
317 | 334 | 385 | ||
318 | 335 | class LoginProcessor: | 386 | class LoginProcessor: |
319 | @@ -558,6 +609,8 @@ | |||
320 | 558 | 609 | ||
321 | 559 | def main(): | 610 | def main(): |
322 | 560 | """Start everything""" | 611 | """Start everything""" |
323 | 612 | dbus.mainloop.glib.threads_init() | ||
324 | 613 | gobject.threads_init() | ||
325 | 561 | logger.debug("Starting up at %s", time.asctime()) | 614 | logger.debug("Starting up at %s", time.asctime()) |
326 | 562 | logger.debug("Installing the Twisted glib2reactor") | 615 | logger.debug("Installing the Twisted glib2reactor") |
327 | 563 | from twisted.internet import glib2reactor # for non-GUI apps | 616 | from twisted.internet import glib2reactor # for non-GUI apps |
328 | @@ -569,6 +622,9 @@ | |||
329 | 569 | bus=dbus.SessionBus())) | 622 | bus=dbus.SessionBus())) |
330 | 570 | SSOLogin(dbus.service.BusName(DBUS_BUS_NAME, | 623 | SSOLogin(dbus.service.BusName(DBUS_BUS_NAME, |
331 | 571 | bus=dbus.SessionBus())) | 624 | bus=dbus.SessionBus())) |
332 | 625 | SSOCredentials(dbus.service.BusName(DBUS_BUS_NAME, | ||
333 | 626 | bus=dbus.SessionBus()), | ||
334 | 627 | object_path=DBUS_CRED_PATH) | ||
335 | 572 | # cleverness here to say: | 628 | # cleverness here to say: |
336 | 573 | # am I already running (bound to this d-bus name)? | 629 | # am I already running (bound to this d-bus name)? |
337 | 574 | # if so, send a signal to the already running instance | 630 | # if so, send a signal to the already running instance |
338 | 575 | 631 | ||
339 | === modified file 'ubuntu_sso/tests/test_gui.py' | |||
340 | --- ubuntu_sso/tests/test_gui.py 2010-08-05 02:24:33 +0000 | |||
341 | +++ ubuntu_sso/tests/test_gui.py 2010-08-06 02:49:40 +0000 | |||
342 | @@ -46,12 +46,6 @@ | |||
343 | 46 | EMAIL_TOKEN = 'B2Pgtf' | 46 | EMAIL_TOKEN = 'B2Pgtf' |
344 | 47 | 47 | ||
345 | 48 | 48 | ||
346 | 49 | def process_pending(): | ||
347 | 50 | """Process all the pending GTK events.""" | ||
348 | 51 | while gtk.events_pending(): | ||
349 | 52 | gtk.main_iteration() | ||
350 | 53 | |||
351 | 54 | |||
352 | 55 | class FakedSSOBackend(object): | 49 | class FakedSSOBackend(object): |
353 | 56 | """Fake a SSO Backend (acts as a dbus.Interface as well).""" | 50 | """Fake a SSO Backend (acts as a dbus.Interface as well).""" |
354 | 57 | 51 | ||
355 | @@ -149,7 +143,6 @@ | |||
356 | 149 | """Grab focus on widget, if None use self.entry.""" | 143 | """Grab focus on widget, if None use self.entry.""" |
357 | 150 | direction = 'in' if focus_in else 'out' | 144 | direction = 'in' if focus_in else 'out' |
358 | 151 | self.entry.emit('focus-%s-event' % direction, None) | 145 | self.entry.emit('focus-%s-event' % direction, None) |
359 | 152 | process_pending() | ||
360 | 153 | 146 | ||
361 | 154 | def assert_correct_label(self): | 147 | def assert_correct_label(self): |
362 | 155 | """Check that the entry has the correct label.""" | 148 | """Check that the entry has the correct label.""" |
363 | @@ -212,7 +205,6 @@ | |||
364 | 212 | self.grab_focus() # grab focus | 205 | self.grab_focus() # grab focus |
365 | 213 | 206 | ||
366 | 214 | self.entry.set_text(' ') # add empty text to the entry | 207 | self.entry.set_text(' ') # add empty text to the entry |
367 | 215 | process_pending() | ||
368 | 216 | 208 | ||
369 | 217 | self.grab_focus(focus_in=False) # loose focus | 209 | self.grab_focus(focus_in=False) # loose focus |
370 | 218 | 210 | ||
371 | @@ -227,7 +219,6 @@ | |||
372 | 227 | self.grab_focus() # grab focus | 219 | self.grab_focus() # grab focus |
373 | 228 | 220 | ||
374 | 229 | self.entry.set_text(expected) # add empty text to the entry | 221 | self.entry.set_text(expected) # add empty text to the entry |
375 | 230 | process_pending() | ||
376 | 231 | 222 | ||
377 | 232 | self.grab_focus(focus_in=False) # loose focus | 223 | self.grab_focus(focus_in=False) # loose focus |
378 | 233 | 224 | ||
379 | @@ -241,7 +232,6 @@ | |||
380 | 241 | self.grab_focus() # grab focus | 232 | self.grab_focus() # grab focus |
381 | 242 | 233 | ||
382 | 243 | self.entry.set_text(expected) # add text to the entry | 234 | self.entry.set_text(expected) # add text to the entry |
383 | 244 | process_pending() | ||
384 | 245 | 235 | ||
385 | 246 | self.grab_focus(focus_in=False) # loose focus | 236 | self.grab_focus(focus_in=False) # loose focus |
386 | 247 | self.grab_focus() # grab focus again! | 237 | self.grab_focus() # grab focus again! |
387 | 248 | 238 | ||
388 | === modified file 'ubuntu_sso/tests/test_main.py' | |||
389 | --- ubuntu_sso/tests/test_main.py 2010-08-04 00:10:14 +0000 | |||
390 | +++ ubuntu_sso/tests/test_main.py 2010-08-06 02:49:40 +0000 | |||
391 | @@ -31,7 +31,8 @@ | |||
392 | 31 | from ubuntu_sso import config | 31 | from ubuntu_sso import config |
393 | 32 | from ubuntu_sso.main import ( | 32 | from ubuntu_sso.main import ( |
394 | 33 | AuthenticationError, BadRealmError, blocking, EmailTokenError, | 33 | AuthenticationError, BadRealmError, blocking, EmailTokenError, |
396 | 34 | InvalidEmailError, InvalidPasswordError, SSOLogin, | 34 | InvalidEmailError, InvalidPasswordError, SSOLogin, SSOCredentials, |
397 | 35 | keyring_get_token, keyring_store_token, | ||
398 | 35 | LoginProcessor, SSOLoginProcessor, RegistrationError) | 36 | LoginProcessor, SSOLoginProcessor, RegistrationError) |
399 | 36 | 37 | ||
400 | 37 | 38 | ||
401 | @@ -110,7 +111,7 @@ | |||
402 | 110 | self.accounts = FakedAccounts() | 111 | self.accounts = FakedAccounts() |
403 | 111 | 112 | ||
404 | 112 | 113 | ||
406 | 113 | class SSOLoginProcessorTestCase(TestCase): | 114 | class SSOLoginProcessorTestCase(TestCase, MockerTestCase): |
407 | 114 | """Test suite for the SSO login processor.""" | 115 | """Test suite for the SSO login processor.""" |
408 | 115 | 116 | ||
409 | 116 | def setUp(self): | 117 | def setUp(self): |
410 | @@ -436,14 +437,14 @@ | |||
411 | 436 | email = "sample email" | 437 | email = "sample email" |
412 | 437 | password = "sample password" | 438 | password = "sample password" |
413 | 438 | token_name = "sample token_name" | 439 | token_name = "sample token_name" |
415 | 439 | expected_result = "expected result" | 440 | sample_result = {"sample": "tokens"} |
416 | 440 | self.create_mock_processor().login(email, password, token_name) | 441 | self.create_mock_processor().login(email, password, token_name) |
418 | 441 | self.mocker.result(expected_result) | 442 | self.mocker.result(sample_result) |
419 | 442 | self.patch(ubuntu_sso.main, "blocking", self.fake_ok_blocking) | 443 | self.patch(ubuntu_sso.main, "blocking", self.fake_ok_blocking) |
420 | 443 | self.mocker.replay() | 444 | self.mocker.replay() |
421 | 444 | 445 | ||
422 | 445 | def verify(result): | 446 | def verify(result): |
424 | 446 | self.assertEqual(result, expected_result) | 447 | self.assertEqual(result, "Ok") |
425 | 447 | d.callback(result) | 448 | d.callback(result) |
426 | 448 | 449 | ||
427 | 449 | client = SSOLogin(self.mockbusname, | 450 | client = SSOLogin(self.mockbusname, |
428 | @@ -556,8 +557,148 @@ | |||
429 | 556 | raise BlockingSampleException(expected_error_message) | 557 | raise BlockingSampleException(expected_error_message) |
430 | 557 | 558 | ||
431 | 558 | def verify(error): | 559 | def verify(error): |
433 | 559 | self.assertEquals(error, expected_error_message) | 560 | self.assertEqual(error, expected_error_message) |
434 | 560 | d.callback("Ok") | 561 | d.callback("Ok") |
435 | 561 | 562 | ||
436 | 562 | blocking(f, d.errback, verify) | 563 | blocking(f, d.errback, verify) |
437 | 563 | return d | 564 | return d |
438 | 565 | |||
439 | 566 | |||
440 | 567 | class KeyringTokenTestCase(MockerTestCase): | ||
441 | 568 | """Checks the functions that access the keyring.""" | ||
442 | 569 | |||
443 | 570 | def test_keyring_store_token(self): | ||
444 | 571 | """Verify the method that stores tokens.""" | ||
445 | 572 | token_name = "token_name" | ||
446 | 573 | token_value = "token value" | ||
447 | 574 | mockKeyringClass = self.mocker.replace("ubuntu_sso.keyring.Keyring") | ||
448 | 575 | mockKeyringClass(token_name) | ||
449 | 576 | mockKeyring = self.mocker.mock() | ||
450 | 577 | self.mocker.result(mockKeyring) | ||
451 | 578 | mockKeyring.set_ubuntusso_attr({"token": token_value}) | ||
452 | 579 | self.mocker.replay() | ||
453 | 580 | |||
454 | 581 | keyring_store_token(token_name, token_value) | ||
455 | 582 | |||
456 | 583 | def test_keyring_get_token(self): | ||
457 | 584 | """The method returns the right token.""" | ||
458 | 585 | token_name = "token_name" | ||
459 | 586 | token_value = "token value" | ||
460 | 587 | mockKeyringClass = self.mocker.replace("ubuntu_sso.keyring.Keyring") | ||
461 | 588 | mockKeyringClass(token_name) | ||
462 | 589 | mockKeyring = self.mocker.mock() | ||
463 | 590 | self.mocker.result(mockKeyring) | ||
464 | 591 | mockKeyring.get_ubuntusso_attr() | ||
465 | 592 | self.mocker.result({"token": token_value}) | ||
466 | 593 | self.mocker.replay() | ||
467 | 594 | |||
468 | 595 | token = keyring_get_token(token_name) | ||
469 | 596 | self.assertEqual(token, token_value) | ||
470 | 597 | |||
471 | 598 | def test_keyring_get_token_not_found(self): | ||
472 | 599 | """The method returns None when the token is not found.""" | ||
473 | 600 | token_name = "token_name" | ||
474 | 601 | mockKeyringClass = self.mocker.replace("ubuntu_sso.keyring.Keyring") | ||
475 | 602 | mockKeyringClass(token_name) | ||
476 | 603 | mockKeyring = self.mocker.mock() | ||
477 | 604 | self.mocker.result(mockKeyring) | ||
478 | 605 | mockKeyring.get_ubuntusso_attr() | ||
479 | 606 | self.mocker.result(None) | ||
480 | 607 | self.mocker.replay() | ||
481 | 608 | |||
482 | 609 | token = keyring_get_token(token_name) | ||
483 | 610 | self.assertEqual(token, None) | ||
484 | 611 | |||
485 | 612 | |||
486 | 613 | class RegisterSampleException(Exception): | ||
487 | 614 | """A mock exception thrown just when testing.""" | ||
488 | 615 | |||
489 | 616 | |||
490 | 617 | class CredentialsTestCase(TestCase, MockerTestCase): | ||
491 | 618 | """Tests for the credentials related DBus methods.""" | ||
492 | 619 | |||
493 | 620 | def test_find_credentials(self): | ||
494 | 621 | """find_credentials immediately returns the token when found.""" | ||
495 | 622 | expected_token = "expected token" | ||
496 | 623 | kgt = self.mocker.replace("ubuntu_sso.main.keyring_get_token") | ||
497 | 624 | kgt(ARGS) | ||
498 | 625 | self.mocker.result(expected_token) | ||
499 | 626 | self.mocker.replay() | ||
500 | 627 | |||
501 | 628 | client = SSOCredentials(self.mocker.mock()) | ||
502 | 629 | token = client.find_credentials("token_name") | ||
503 | 630 | self.assertEqual(token, expected_token) | ||
504 | 631 | |||
505 | 632 | def test_credentials_not_found(self): | ||
506 | 633 | """find_credentials immediately returns '' when no token found.""" | ||
507 | 634 | expected_token = "" | ||
508 | 635 | kgt = self.mocker.replace("ubuntu_sso.main.keyring_get_token") | ||
509 | 636 | kgt(ARGS) | ||
510 | 637 | self.mocker.result(None) | ||
511 | 638 | self.mocker.replay() | ||
512 | 639 | |||
513 | 640 | client = SSOCredentials(self.mocker.mock()) | ||
514 | 641 | token = client.find_credentials("token_name") | ||
515 | 642 | self.assertEqual(token, expected_token) | ||
516 | 643 | |||
517 | 644 | def test_login_or_register(self): | ||
518 | 645 | """login_or_register_... throws the signal when token is found.""" | ||
519 | 646 | expected_token = "expected token" | ||
520 | 647 | d = Deferred() | ||
521 | 648 | |||
522 | 649 | def verify(result): | ||
523 | 650 | self.assertEqual(result, expected_token) | ||
524 | 651 | d.callback("ok") | ||
525 | 652 | |||
526 | 653 | kgt = self.mocker.replace("ubuntu_sso.main.keyring_get_token") | ||
527 | 654 | kgt(ARGS) | ||
528 | 655 | self.mocker.result(expected_token) | ||
529 | 656 | self.mocker.replay() | ||
530 | 657 | client = SSOCredentials(self.mocker.mock()) | ||
531 | 658 | self.patch(client, "_show_login_or_register_ui", self.fail) | ||
532 | 659 | self.patch(client, "CredentialsFound", verify) | ||
533 | 660 | self.patch(client, "CredentialsError", self.fail) | ||
534 | 661 | client.login_or_register_to_get_credentials("token name", "tcurl") | ||
535 | 662 | return d | ||
536 | 663 | |||
537 | 664 | def test_login_or_register_not_found(self): | ||
538 | 665 | """Check that login_or_register_... opens the ui when no cred found.""" | ||
539 | 666 | token_name = "token name" | ||
540 | 667 | d = Deferred() | ||
541 | 668 | |||
542 | 669 | def verify(result, *a): | ||
543 | 670 | self.assertEqual(result, token_name) | ||
544 | 671 | d.callback("ok") | ||
545 | 672 | |||
546 | 673 | kgt = self.mocker.replace("ubuntu_sso.main.keyring_get_token") | ||
547 | 674 | kgt(ARGS) | ||
548 | 675 | self.mocker.result(None) | ||
549 | 676 | self.mocker.replay() | ||
550 | 677 | |||
551 | 678 | client = SSOCredentials(self.mocker.mock()) | ||
552 | 679 | self.patch(client, "_show_login_or_register_ui", verify) | ||
553 | 680 | self.patch(client, "CredentialsFound", self.fail) | ||
554 | 681 | self.patch(client, "CredentialsError", self.fail) | ||
555 | 682 | client.login_or_register_to_get_credentials(token_name, "tcurl") | ||
556 | 683 | return d | ||
557 | 684 | |||
558 | 685 | def test_login_or_register_problem(self): | ||
559 | 686 | """login_or_register_... returns the right signal on error.""" | ||
560 | 687 | expected_error = "Sample Error - not for resale" | ||
561 | 688 | d = Deferred() | ||
562 | 689 | |||
563 | 690 | def verify(result, *a): | ||
564 | 691 | self.assertEqual(result, expected_error) | ||
565 | 692 | d.callback("ok") | ||
566 | 693 | |||
567 | 694 | kgt = self.mocker.replace("ubuntu_sso.main.keyring_get_token") | ||
568 | 695 | kgt(ARGS) | ||
569 | 696 | self.mocker.throw(RegisterSampleException(expected_error)) | ||
570 | 697 | self.mocker.replay() | ||
571 | 698 | |||
572 | 699 | client = SSOCredentials(self.mocker.mock()) | ||
573 | 700 | self.patch(client, "_show_login_or_register_ui", self.fail) | ||
574 | 701 | self.patch(client, "CredentialsFound", self.fail) | ||
575 | 702 | self.patch(client, "CredentialsError", verify) | ||
576 | 703 | client.login_or_register_to_get_credentials("token name", "tcurl") | ||
577 | 704 | return d |
keyring.py needs tests but they are coming on a different branch.