Merge lp:~nataliabidart/ubuntu-sso-client/isolate-sso-processor into lp:ubuntu-sso-client
- isolate-sso-processor
- Merge into trunk
Proposed by
Natalia Bidart
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Manuel de la Peña | ||||
Approved revision: | 639 | ||||
Merged at revision: | 637 | ||||
Proposed branch: | lp:~nataliabidart/ubuntu-sso-client/isolate-sso-processor | ||||
Merge into: | lp:ubuntu-sso-client | ||||
Diff against target: |
1200 lines (+591/-526) 4 files modified
ubuntu_sso/account.py (+231/-0) ubuntu_sso/main.py (+12/-196) ubuntu_sso/tests/test_account.py (+339/-0) ubuntu_sso/tests/test_main.py (+9/-330) |
||||
To merge this branch: | bzr merge lp:~nataliabidart/ubuntu-sso-client/isolate-sso-processor | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Manuel de la Peña (community) | Approve | ||
John Lenton (community) | Approve | ||
Review via email:
|
Commit message
* Isolating SSO login processor into a separated module (LP: #637204).
Description of the change
To post a comment you must log in.
- 637. By Natalia Bidart
-
Fixing copyright year.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Natalia Bidart (nataliabidart) wrote : | # |
> can I sugest firing a DeprecationWarning in the __init__ of SSOLoginProcessor?
Yes you can! Already done it. Thanks!
- 638. By Natalia Bidart
-
Added a DeprecationWarning to SSOLoginProcessor class.
- 639. By Natalia Bidart
-
Warning must be a DeprecationWarning!
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'ubuntu_sso/account.py' |
2 | --- ubuntu_sso/account.py 1970-01-01 00:00:00 +0000 |
3 | +++ ubuntu_sso/account.py 2010-10-01 17:16:44 +0000 |
4 | @@ -0,0 +1,231 @@ |
5 | +# -*- coding: utf-8 -*- |
6 | + |
7 | +# Author: Natalia Bidart <natalia.bidart@canonical.com> |
8 | +# |
9 | +# Copyright 2010 Canonical Ltd. |
10 | +# |
11 | +# This program is free software: you can redistribute it and/or modify it |
12 | +# under the terms of the GNU General Public License version 3, as published |
13 | +# by the Free Software Foundation. |
14 | +# |
15 | +# This program is distributed in the hope that it will be useful, but |
16 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
17 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
18 | +# PURPOSE. See the GNU General Public License for more details. |
19 | +# |
20 | +# You should have received a copy of the GNU General Public License along |
21 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
22 | +"""Single Sign On account management.""" |
23 | + |
24 | +import os |
25 | +import re |
26 | +import urllib2 |
27 | + |
28 | +# Unable to import 'lazr.restfulclient.*' |
29 | +# pylint: disable=F0401 |
30 | +from lazr.restfulclient.authorize import BasicHttpAuthorizer |
31 | +from lazr.restfulclient.authorize.oauth import OAuthAuthorizer |
32 | +from lazr.restfulclient.errors import HTTPError |
33 | +from lazr.restfulclient.resource import ServiceRoot |
34 | +# pylint: enable=F0401 |
35 | +from oauth import oauth |
36 | + |
37 | +from ubuntu_sso.logger import setup_logging |
38 | + |
39 | + |
40 | +logger = setup_logging("ubuntu_sso.account") |
41 | +SERVICE_URL = "https://login.ubuntu.com/api/1.0" |
42 | + |
43 | + |
44 | +class InvalidEmailError(Exception): |
45 | + """The email is not valid.""" |
46 | + |
47 | + |
48 | +class InvalidPasswordError(Exception): |
49 | + """The password is not valid. |
50 | + |
51 | + Must provide at least 8 characters, one upper case, one number. |
52 | + """ |
53 | + |
54 | + |
55 | +class RegistrationError(Exception): |
56 | + """The registration failed.""" |
57 | + |
58 | + |
59 | +class AuthenticationError(Exception): |
60 | + """The authentication failed.""" |
61 | + |
62 | + |
63 | +class EmailTokenError(Exception): |
64 | + """The email token is not valid.""" |
65 | + |
66 | + |
67 | +class ResetPasswordTokenError(Exception): |
68 | + """The token for password reset could not be generated.""" |
69 | + |
70 | + |
71 | +class NewPasswordError(Exception): |
72 | + """The new password could not be set.""" |
73 | + |
74 | + |
75 | +class Account(object): |
76 | + """Login and register users using the Ubuntu Single Sign On service.""" |
77 | + |
78 | + def __init__(self, sso_service_class=None): |
79 | + """Create a new SSO Account manager.""" |
80 | + if sso_service_class is None: |
81 | + self.sso_service_class = ServiceRoot |
82 | + else: |
83 | + self.sso_service_class = sso_service_class |
84 | + |
85 | + self.service_url = os.environ.get('USSOC_SERVICE_URL', SERVICE_URL) |
86 | + |
87 | + logger.info('Created a new SSO access layer for service url %r', |
88 | + self.service_url) |
89 | + |
90 | + def _valid_email(self, email): |
91 | + """Validate the given email.""" |
92 | + return email is not None and '@' in email |
93 | + |
94 | + def _valid_password(self, password): |
95 | + """Validate the given password.""" |
96 | + res = (len(password) > 7 and # at least 8 characters |
97 | + re.search('[A-Z]', password) and # one upper case |
98 | + re.search('\d+', password)) # one number |
99 | + return res |
100 | + |
101 | + def _format_webservice_errors(self, errdict): |
102 | + """Turn each list of strings in the errdict into a LF separated str.""" |
103 | + result = {} |
104 | + for key, val in errdict.iteritems(): |
105 | + # workaround until bug #624955 is solved |
106 | + if isinstance(val, basestring): |
107 | + result[key] = val |
108 | + else: |
109 | + result[key] = "\n".join(val) |
110 | + return result |
111 | + |
112 | + def generate_captcha(self, filename): |
113 | + """Generate a captcha using the SSO service.""" |
114 | + logger.debug('generate_captcha: requesting captcha, filename: %r', |
115 | + filename) |
116 | + sso_service = self.sso_service_class(None, self.service_url) |
117 | + captcha = sso_service.captchas.new() |
118 | + |
119 | + # download captcha and save to 'filename' |
120 | + logger.debug('generate_captcha: server answered: %r', captcha) |
121 | + try: |
122 | + res = urllib2.urlopen(captcha['image_url']) |
123 | + with open(filename, 'wb') as f: |
124 | + f.write(res.read()) |
125 | + except: |
126 | + msg = 'generate_captcha crashed while downloading the image.' |
127 | + logger.exception(msg) |
128 | + raise |
129 | + |
130 | + return captcha['captcha_id'] |
131 | + |
132 | + def register_user(self, email, password, captcha_id, captcha_solution): |
133 | + """Register a new user with 'email' and 'password'.""" |
134 | + logger.debug('register_user: email: %r password: <hidden>, ' |
135 | + 'captcha_id: %r, captcha_solution: %r', |
136 | + email, captcha_id, captcha_solution) |
137 | + sso_service = self.sso_service_class(None, self.service_url) |
138 | + if not self._valid_email(email): |
139 | + logger.error('register_user: InvalidEmailError for email: %r', |
140 | + email) |
141 | + raise InvalidEmailError() |
142 | + if not self._valid_password(password): |
143 | + logger.error('register_user: InvalidPasswordError') |
144 | + raise InvalidPasswordError() |
145 | + |
146 | + result = sso_service.registrations.register( |
147 | + email=email, password=password, captcha_id=captcha_id, |
148 | + captcha_solution=captcha_solution) |
149 | + logger.info('register_user: email: %r result: %r', email, result) |
150 | + |
151 | + if result['status'] == 'error': |
152 | + errorsdict = self._format_webservice_errors(result['errors']) |
153 | + raise RegistrationError(errorsdict) |
154 | + elif result['status'] != 'ok': |
155 | + raise RegistrationError('Received unknown status: %s' % result) |
156 | + else: |
157 | + return email |
158 | + |
159 | + def login(self, email, password, token_name): |
160 | + """Login a user with 'email' and 'password'.""" |
161 | + logger.debug('login: email: %r password: <hidden>, token_name: %r', |
162 | + email, token_name) |
163 | + basic = BasicHttpAuthorizer(email, password) |
164 | + sso_service = self.sso_service_class(basic, self.service_url) |
165 | + service = sso_service.authentications.authenticate |
166 | + |
167 | + try: |
168 | + credentials = service(token_name=token_name) |
169 | + except HTTPError: |
170 | + logger.exception('login failed with:') |
171 | + raise AuthenticationError() |
172 | + |
173 | + logger.debug('login: authentication successful! consumer_key: %r, ' \ |
174 | + 'token_name: %r', credentials['consumer_key'], token_name) |
175 | + return credentials |
176 | + |
177 | + def validate_email(self, email, password, email_token, token_name): |
178 | + """Validate an email token for user with 'email' and 'password'.""" |
179 | + logger.debug('validate_email: email: %r password: <hidden>, ' |
180 | + 'email_token: %r, token_name: %r.', |
181 | + email, email_token, token_name) |
182 | + token = self.login(email=email, password=password, |
183 | + token_name=token_name) |
184 | + |
185 | + oauth_token = oauth.OAuthToken(token['token'], token['token_secret']) |
186 | + authorizer = OAuthAuthorizer(token['consumer_key'], |
187 | + token['consumer_secret'], |
188 | + oauth_token) |
189 | + sso_service = self.sso_service_class(authorizer, self.service_url) |
190 | + result = sso_service.accounts.validate_email(email_token=email_token) |
191 | + logger.info('validate_email: email: %r result: %r', email, result) |
192 | + if 'errors' in result: |
193 | + errorsdict = self._format_webservice_errors(result['errors']) |
194 | + raise EmailTokenError(errorsdict) |
195 | + elif 'email' in result: |
196 | + return token |
197 | + else: |
198 | + raise EmailTokenError('Received invalid reply: %s' % result) |
199 | + |
200 | + def request_password_reset_token(self, email): |
201 | + """Request a token to reset the password for the account 'email'.""" |
202 | + sso_service = self.sso_service_class(None, self.service_url) |
203 | + service = sso_service.registrations.request_password_reset_token |
204 | + try: |
205 | + result = service(email=email) |
206 | + except HTTPError, e: |
207 | + logger.exception('request_password_reset_token failed with:') |
208 | + raise ResetPasswordTokenError(e.content.split('\n')[0]) |
209 | + |
210 | + if result['status'] == 'ok': |
211 | + return email |
212 | + else: |
213 | + raise ResetPasswordTokenError('Received invalid reply: %s' % |
214 | + result) |
215 | + |
216 | + def set_new_password(self, email, token, new_password): |
217 | + """Set a new password for the account 'email' to be 'new_password'. |
218 | + |
219 | + The 'token' has to be the one resulting from a call to |
220 | + 'request_password_reset_token'. |
221 | + |
222 | + """ |
223 | + sso_service = self.sso_service_class(None, self.service_url) |
224 | + service = sso_service.registrations.set_new_password |
225 | + try: |
226 | + result = service(email=email, token=token, |
227 | + new_password=new_password) |
228 | + except HTTPError, e: |
229 | + logger.exception('set_new_password failed with:') |
230 | + raise NewPasswordError(e.content.split('\n')[0]) |
231 | + |
232 | + if result['status'] == 'ok': |
233 | + return email |
234 | + else: |
235 | + raise NewPasswordError('Received invalid reply: %s' % result) |
236 | |
237 | === modified file 'ubuntu_sso/main.py' |
238 | --- ubuntu_sso/main.py 2010-09-30 21:09:44 +0000 |
239 | +++ ubuntu_sso/main.py 2010-10-01 17:16:44 +0000 |
240 | @@ -28,24 +28,18 @@ |
241 | """ |
242 | |
243 | import os |
244 | -import re |
245 | import threading |
246 | import traceback |
247 | import urllib2 |
248 | +import warnings |
249 | |
250 | import dbus.service |
251 | import gobject |
252 | |
253 | -# Unable to import 'lazr.restfulclient.*' |
254 | -# pylint: disable=F0401 |
255 | -from lazr.restfulclient.authorize import BasicHttpAuthorizer |
256 | -from lazr.restfulclient.authorize.oauth import OAuthAuthorizer |
257 | -from lazr.restfulclient.errors import HTTPError |
258 | -from lazr.restfulclient.resource import ServiceRoot |
259 | -# pylint: enable=F0401 |
260 | from oauth import oauth |
261 | |
262 | from ubuntu_sso import DBUS_IFACE_USER_NAME, DBUS_IFACE_CRED_NAME |
263 | +from ubuntu_sso.account import Account |
264 | from ubuntu_sso.keyring import Keyring, get_token_name, U1_APP_NAME |
265 | from ubuntu_sso.logger import setup_logging |
266 | |
267 | @@ -56,38 +50,6 @@ |
268 | |
269 | logger = setup_logging("ubuntu_sso.main") |
270 | PING_URL = "https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/" |
271 | -SERVICE_URL = "https://login.ubuntu.com/api/1.0" |
272 | - |
273 | - |
274 | -class InvalidEmailError(Exception): |
275 | - """The email is not valid.""" |
276 | - |
277 | - |
278 | -class InvalidPasswordError(Exception): |
279 | - """The password is not valid. |
280 | - |
281 | - Must provide at least 8 characters, one upper case, one number. |
282 | - """ |
283 | - |
284 | - |
285 | -class RegistrationError(Exception): |
286 | - """The registration failed.""" |
287 | - |
288 | - |
289 | -class AuthenticationError(Exception): |
290 | - """The authentication failed.""" |
291 | - |
292 | - |
293 | -class EmailTokenError(Exception): |
294 | - """The email token is not valid.""" |
295 | - |
296 | - |
297 | -class ResetPasswordTokenError(Exception): |
298 | - """The token for password reset could not be generated.""" |
299 | - |
300 | - |
301 | -class NewPasswordError(Exception): |
302 | - """The new password could not be set.""" |
303 | |
304 | |
305 | def keyring_store_credentials(app_name, credentials): |
306 | @@ -104,164 +66,18 @@ |
307 | return creds |
308 | |
309 | |
310 | -class SSOLoginProcessor(object): |
311 | - """Login and register users using the Ubuntu Single Sign On service.""" |
312 | +class SSOLoginProcessor(Account): |
313 | + """Login and register users using the Ubuntu Single Sign On service. |
314 | + |
315 | + Alias classname to maintain backwards compatibility. DO NOT USE, use |
316 | + ubuntu_sso.account.Account instead. |
317 | + """ |
318 | |
319 | def __init__(self, sso_service_class=None): |
320 | - """Create a new SSO login processor.""" |
321 | - if sso_service_class is None: |
322 | - self.sso_service_class = ServiceRoot |
323 | - else: |
324 | - self.sso_service_class = sso_service_class |
325 | - |
326 | - self.service_url = os.environ.get('USSOC_SERVICE_URL', SERVICE_URL) |
327 | - |
328 | - def _valid_email(self, email): |
329 | - """Validate the given email.""" |
330 | - return email is not None and '@' in email |
331 | - |
332 | - def _valid_password(self, password): |
333 | - """Validate the given password.""" |
334 | - res = (len(password) > 7 and # at least 8 characters |
335 | - re.search('[A-Z]', password) and # one upper case |
336 | - re.search('\d+', password)) # one number |
337 | - return res |
338 | - |
339 | - def _format_webservice_errors(self, errdict): |
340 | - """Turn each list of strings in the errdict into a LF separated str.""" |
341 | - result = {} |
342 | - for k, v in errdict.iteritems(): |
343 | - # workaround until bug #624955 is solved |
344 | - if isinstance(v, basestring): |
345 | - result[k] = v |
346 | - else: |
347 | - result[k] = "\n".join(v) |
348 | - return result |
349 | - |
350 | - def generate_captcha(self, filename): |
351 | - """Generate a captcha using the SSO service.""" |
352 | - logger.debug('generate_captcha: requesting captcha, filename: %r', |
353 | - filename) |
354 | - sso_service = self.sso_service_class(None, self.service_url) |
355 | - captcha = sso_service.captchas.new() |
356 | - |
357 | - # download captcha and save to 'filename' |
358 | - logger.debug('generate_captcha: server answered: %r', captcha) |
359 | - try: |
360 | - res = urllib2.urlopen(captcha['image_url']) |
361 | - with open(filename, 'wb') as f: |
362 | - f.write(res.read()) |
363 | - except: |
364 | - msg = 'generate_captcha crashed while downloading the image.' |
365 | - logger.exception(msg) |
366 | - raise |
367 | - |
368 | - return captcha['captcha_id'] |
369 | - |
370 | - def register_user(self, email, password, captcha_id, captcha_solution): |
371 | - """Register a new user with 'email' and 'password'.""" |
372 | - logger.debug('register_user: email: %r password: <hidden>, ' |
373 | - 'captcha_id: %r, captcha_solution: %r', |
374 | - email, captcha_id, captcha_solution) |
375 | - sso_service = self.sso_service_class(None, self.service_url) |
376 | - if not self._valid_email(email): |
377 | - logger.error('register_user: InvalidEmailError for email: %r', |
378 | - email) |
379 | - raise InvalidEmailError() |
380 | - if not self._valid_password(password): |
381 | - logger.error('register_user: InvalidPasswordError') |
382 | - raise InvalidPasswordError() |
383 | - |
384 | - result = sso_service.registrations.register( |
385 | - email=email, password=password, captcha_id=captcha_id, |
386 | - captcha_solution=captcha_solution) |
387 | - logger.info('register_user: email: %r result: %r', email, result) |
388 | - |
389 | - if result['status'] == 'error': |
390 | - errorsdict = self._format_webservice_errors(result['errors']) |
391 | - raise RegistrationError(errorsdict) |
392 | - elif result['status'] != 'ok': |
393 | - raise RegistrationError('Received unknown status: %s' % result) |
394 | - else: |
395 | - return email |
396 | - |
397 | - def login(self, email, password, token_name): |
398 | - """Login a user with 'email' and 'password'.""" |
399 | - logger.debug('login: email: %r password: <hidden>, token_name: %r', |
400 | - email, token_name) |
401 | - basic = BasicHttpAuthorizer(email, password) |
402 | - sso_service = self.sso_service_class(basic, self.service_url) |
403 | - service = sso_service.authentications.authenticate |
404 | - |
405 | - try: |
406 | - credentials = service(token_name=token_name) |
407 | - except HTTPError: |
408 | - logger.exception('login failed with:') |
409 | - raise AuthenticationError() |
410 | - |
411 | - logger.debug('login: authentication successful! consumer_key: %r, ' \ |
412 | - 'token_name: %r', credentials['consumer_key'], token_name) |
413 | - return credentials |
414 | - |
415 | - def validate_email(self, email, password, email_token, token_name): |
416 | - """Validate an email token for user with 'email' and 'password'.""" |
417 | - logger.debug('validate_email: email: %r password: <hidden>, ' |
418 | - 'email_token: %r, token_name: %r.', |
419 | - email, email_token, token_name) |
420 | - token = self.login(email=email, password=password, |
421 | - token_name=token_name) |
422 | - |
423 | - oauth_token = oauth.OAuthToken(token['token'], token['token_secret']) |
424 | - authorizer = OAuthAuthorizer(token['consumer_key'], |
425 | - token['consumer_secret'], |
426 | - oauth_token) |
427 | - sso_service = self.sso_service_class(authorizer, self.service_url) |
428 | - result = sso_service.accounts.validate_email(email_token=email_token) |
429 | - logger.info('validate_email: email: %r result: %r', email, result) |
430 | - if 'errors' in result: |
431 | - errorsdict = self._format_webservice_errors(result['errors']) |
432 | - raise EmailTokenError(errorsdict) |
433 | - elif 'email' in result: |
434 | - return token |
435 | - else: |
436 | - raise EmailTokenError('Received invalid reply: %s' % result) |
437 | - |
438 | - def request_password_reset_token(self, email): |
439 | - """Request a token to reset the password for the account 'email'.""" |
440 | - sso_service = self.sso_service_class(None, self.service_url) |
441 | - service = sso_service.registrations.request_password_reset_token |
442 | - try: |
443 | - result = service(email=email) |
444 | - except HTTPError, e: |
445 | - logger.exception('request_password_reset_token failed with:') |
446 | - raise ResetPasswordTokenError(e.content.split('\n')[0]) |
447 | - |
448 | - if result['status'] == 'ok': |
449 | - return email |
450 | - else: |
451 | - raise ResetPasswordTokenError('Received invalid reply: %s' % |
452 | - result) |
453 | - |
454 | - def set_new_password(self, email, token, new_password): |
455 | - """Set a new password for the account 'email' to be 'new_password'. |
456 | - |
457 | - The 'token' has to be the one resulting from a call to |
458 | - 'request_password_reset_token'. |
459 | - |
460 | - """ |
461 | - sso_service = self.sso_service_class(None, self.service_url) |
462 | - service = sso_service.registrations.set_new_password |
463 | - try: |
464 | - result = service(email=email, token=token, |
465 | - new_password=new_password) |
466 | - except HTTPError, e: |
467 | - logger.exception('set_new_password failed with:') |
468 | - raise NewPasswordError(e.content.split('\n')[0]) |
469 | - |
470 | - if result['status'] == 'ok': |
471 | - return email |
472 | - else: |
473 | - raise NewPasswordError('Received invalid reply: %s' % result) |
474 | + """Create a new SSO Account manager.""" |
475 | + msg = 'Use ubuntu_sso.account.Account instead.' |
476 | + warnings.warn(msg, DeprecationWarning) |
477 | + super(SSOLoginProcessor, self).__init__(sso_service_class) |
478 | |
479 | |
480 | def except_to_errdict(e): |
481 | |
482 | === added file 'ubuntu_sso/tests/test_account.py' |
483 | --- ubuntu_sso/tests/test_account.py 1970-01-01 00:00:00 +0000 |
484 | +++ ubuntu_sso/tests/test_account.py 2010-10-01 17:16:44 +0000 |
485 | @@ -0,0 +1,339 @@ |
486 | +# -*- coding: utf-8 -*- |
487 | +# |
488 | +# Author: Natalia Bidart <natalia.bidart@canonical.com> |
489 | +# |
490 | +# Copyright 2010 Canonical Ltd. |
491 | +# |
492 | +# This program is free software: you can redistribute it and/or modify it |
493 | +# under the terms of the GNU General Public License version 3, as published |
494 | +# by the Free Software Foundation. |
495 | +# |
496 | +# This program is distributed in the hope that it will be useful, but |
497 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
498 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
499 | +# PURPOSE. See the GNU General Public License for more details. |
500 | +# |
501 | +# You should have received a copy of the GNU General Public License along |
502 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
503 | +"""Tests for the SSO account code.""" |
504 | + |
505 | +import os |
506 | + |
507 | +# Unable to import 'lazr.restfulclient.*' |
508 | +# pylint: disable=F0401 |
509 | +from lazr.restfulclient.errors import HTTPError |
510 | +# pylint: enable=F0401 |
511 | +from twisted.trial.unittest import TestCase |
512 | + |
513 | +from ubuntu_sso.account import (Account, AuthenticationError, EmailTokenError, |
514 | + InvalidEmailError, InvalidPasswordError, NewPasswordError, SERVICE_URL, |
515 | + RegistrationError, ResetPasswordTokenError) |
516 | +from ubuntu_sso.tests import (APP_NAME, CAPTCHA_ID, CAPTCHA_PATH, |
517 | + CAPTCHA_SOLUTION, EMAIL, EMAIL_TOKEN, PASSWORD, RESET_PASSWORD_TOKEN, |
518 | + TOKEN, TOKEN_NAME) |
519 | + |
520 | + |
521 | +# Access to a protected member 'yyy' of a client class |
522 | +# pylint: disable=W0212 |
523 | + |
524 | + |
525 | +CANT_RESET_PASSWORD_CONTENT = "CanNotResetPassowrdError: " \ |
526 | + "Can't reset password for this account" |
527 | +RESET_TOKEN_INVALID_CONTENT = "AuthToken matching query does not exist." |
528 | +EMAIL_ALREADY_REGISTERED = 'a@example.com' |
529 | +STATUS_UNKNOWN = {'status': 'yadda-yadda'} |
530 | +STATUS_ERROR = {'status': 'error', 'errors': {'something': ['Bla', 'Ble']}} |
531 | +STATUS_OK = {'status': 'ok'} |
532 | +STATUS_EMAIL_UNKNOWN = {'status': 'yadda-yadda'} |
533 | +STATUS_EMAIL_ERROR = {'errors': {'email_token': ['Error1', 'Error2']}} |
534 | +STATUS_EMAIL_OK = {'email': EMAIL} |
535 | + |
536 | + |
537 | +class FakedCaptchas(object): |
538 | + """Fake the captcha generator.""" |
539 | + |
540 | + def new(self): |
541 | + """Return a fix captcha).""" |
542 | + return {'image_url': 'file://%s' % CAPTCHA_PATH, |
543 | + 'captcha_id': CAPTCHA_ID} |
544 | + |
545 | + |
546 | +class FakedRegistrations(object): |
547 | + """Fake the registrations service.""" |
548 | + |
549 | + def register(self, email, password, captcha_id, captcha_solution): |
550 | + """Fake registration. Return a fix result.""" |
551 | + if email == EMAIL_ALREADY_REGISTERED: |
552 | + return {'status': 'error', |
553 | + 'errors': {'email': 'Email already registered'}} |
554 | + elif captcha_id is None and captcha_solution is None: |
555 | + return STATUS_UNKNOWN |
556 | + elif captcha_id != CAPTCHA_ID or captcha_solution != CAPTCHA_SOLUTION: |
557 | + return STATUS_ERROR |
558 | + else: |
559 | + return STATUS_OK |
560 | + |
561 | + def request_password_reset_token(self, email): |
562 | + """Fake password reset token. Return a fix result.""" |
563 | + if email is None: |
564 | + return STATUS_UNKNOWN |
565 | + elif email != EMAIL: |
566 | + raise HTTPError(response=None, content=CANT_RESET_PASSWORD_CONTENT) |
567 | + else: |
568 | + return STATUS_OK |
569 | + |
570 | + def set_new_password(self, email, token, new_password): |
571 | + """Fake the setting of new password. Return a fix result.""" |
572 | + if email is None and token is None and new_password is None: |
573 | + return STATUS_UNKNOWN |
574 | + elif email != EMAIL or token != RESET_PASSWORD_TOKEN: |
575 | + raise HTTPError(response=None, content=RESET_TOKEN_INVALID_CONTENT) |
576 | + else: |
577 | + return STATUS_OK |
578 | + |
579 | + |
580 | +class FakedAuthentications(object): |
581 | + """Fake the authentications service.""" |
582 | + |
583 | + def authenticate(self, token_name): |
584 | + """Fake authenticate. Return a fix result.""" |
585 | + if not token_name.startswith(TOKEN_NAME): |
586 | + raise HTTPError(response=None, content=None) |
587 | + else: |
588 | + return TOKEN |
589 | + |
590 | + |
591 | +class FakedAccounts(object): |
592 | + """Fake the accounts service.""" |
593 | + |
594 | + def validate_email(self, email_token): |
595 | + """Fake the email validation. Return a fix result.""" |
596 | + if email_token is None: |
597 | + return STATUS_EMAIL_UNKNOWN |
598 | + elif email_token == EMAIL_ALREADY_REGISTERED: |
599 | + return {'status': 'error', |
600 | + 'errors': {'email': 'Email already registered'}} |
601 | + elif email_token != EMAIL_TOKEN: |
602 | + return STATUS_EMAIL_ERROR |
603 | + else: |
604 | + return STATUS_EMAIL_OK |
605 | + |
606 | + |
607 | +class FakedSSOServer(object): |
608 | + """Fake an SSO server.""" |
609 | + |
610 | + def __init__(self, authorizer, service_root): |
611 | + self.captchas = FakedCaptchas() |
612 | + self.registrations = FakedRegistrations() |
613 | + self.authentications = FakedAuthentications() |
614 | + self.accounts = FakedAccounts() |
615 | + |
616 | + |
617 | +class AccountTestCase(TestCase): |
618 | + """Test suite for the SSO login processor.""" |
619 | + |
620 | + def setUp(self): |
621 | + """Init.""" |
622 | + self.processor = Account(sso_service_class=FakedSSOServer) |
623 | + self.register_kwargs = dict(email=EMAIL, password=PASSWORD, |
624 | + captcha_id=CAPTCHA_ID, |
625 | + captcha_solution=CAPTCHA_SOLUTION) |
626 | + self.login_kwargs = dict(email=EMAIL, password=PASSWORD, |
627 | + token_name=TOKEN_NAME) |
628 | + |
629 | + def tearDown(self): |
630 | + """Clean up.""" |
631 | + self.processor = None |
632 | + |
633 | + def test_generate_captcha(self): |
634 | + """Captcha can be generated.""" |
635 | + filename = self.mktemp() |
636 | + self.addCleanup(lambda: os.remove(filename)) |
637 | + captcha_id = self.processor.generate_captcha(filename) |
638 | + self.assertEqual(CAPTCHA_ID, captcha_id, 'captcha id must be correct.') |
639 | + self.assertTrue(os.path.isfile(filename), '%s must exist.' % filename) |
640 | + |
641 | + with open(CAPTCHA_PATH) as f: |
642 | + expected = f.read() |
643 | + with open(filename) as f: |
644 | + actual = f.read() |
645 | + self.assertEqual(expected, actual, 'captcha image must be correct.') |
646 | + |
647 | + def test_register_user_checks_valid_email(self): |
648 | + """Email is validated.""" |
649 | + self.register_kwargs['email'] = 'notavalidemail' |
650 | + self.assertRaises(InvalidEmailError, |
651 | + self.processor.register_user, **self.register_kwargs) |
652 | + |
653 | + def test_register_user_checks_valid_password(self): |
654 | + """Password is validated.""" |
655 | + self.register_kwargs['password'] = '' |
656 | + self.assertRaises(InvalidPasswordError, |
657 | + self.processor.register_user, **self.register_kwargs) |
658 | + |
659 | + # 7 chars, one less than expected |
660 | + self.register_kwargs['password'] = 'tesT3it' |
661 | + self.assertRaises(InvalidPasswordError, |
662 | + self.processor.register_user, **self.register_kwargs) |
663 | + |
664 | + self.register_kwargs['password'] = 'test3it!' # no upper case |
665 | + self.assertRaises(InvalidPasswordError, |
666 | + self.processor.register_user, **self.register_kwargs) |
667 | + |
668 | + self.register_kwargs['password'] = 'testIt!!' # no number |
669 | + self.assertRaises(InvalidPasswordError, |
670 | + self.processor.register_user, **self.register_kwargs) |
671 | + |
672 | + # register |
673 | + |
674 | + def test_register_user_if_status_ok(self): |
675 | + """A user is succesfuy registered into the SSO server.""" |
676 | + result = self.processor.register_user(**self.register_kwargs) |
677 | + self.assertEqual(EMAIL, result, 'registration was successful.') |
678 | + |
679 | + def test_register_user_if_status_error(self): |
680 | + """Proper error is raised if register fails.""" |
681 | + self.register_kwargs['captcha_id'] = CAPTCHA_ID * 2 # incorrect |
682 | + failure = self.assertRaises(RegistrationError, |
683 | + self.processor.register_user, |
684 | + **self.register_kwargs) |
685 | + for k, val in failure.args[0].items(): |
686 | + self.assertIn(k, STATUS_ERROR['errors']) |
687 | + self.assertEqual(val, "\n".join(STATUS_ERROR['errors'][k])) |
688 | + |
689 | + def test_register_user_if_status_error_with_string_message(self): |
690 | + """Proper error is raised if register fails.""" |
691 | + self.register_kwargs['email'] = EMAIL_ALREADY_REGISTERED |
692 | + failure = self.assertRaises(RegistrationError, |
693 | + self.processor.register_user, |
694 | + **self.register_kwargs) |
695 | + for k, val in failure.args[0].items(): |
696 | + self.assertIn(k, {'email': 'Email already registered'}) |
697 | + self.assertEqual(val, 'Email already registered') |
698 | + |
699 | + def test_register_user_if_status_unknown(self): |
700 | + """Proper error is raised if register returns an unknown status.""" |
701 | + self.register_kwargs['captcha_id'] = None |
702 | + self.register_kwargs['captcha_solution'] = None |
703 | + failure = self.assertRaises(RegistrationError, |
704 | + self.processor.register_user, |
705 | + **self.register_kwargs) |
706 | + self.assertIn('Received unknown status: %s' % STATUS_UNKNOWN, failure) |
707 | + |
708 | + # login |
709 | + |
710 | + def test_login_if_http_error(self): |
711 | + """Proper error is raised if authentication fails.""" |
712 | + self.login_kwargs['token_name'] = APP_NAME * 2 # invalid token name |
713 | + self.assertRaises(AuthenticationError, |
714 | + self.processor.login, **self.login_kwargs) |
715 | + |
716 | + def test_login_if_no_error(self): |
717 | + """A user can be succesfully logged in into the SSO service.""" |
718 | + result = self.processor.login(**self.login_kwargs) |
719 | + self.assertEqual(TOKEN, result, 'authentication was successful.') |
720 | + |
721 | + # validate_email |
722 | + |
723 | + def test_validate_email_if_status_ok(self): |
724 | + """A email is succesfuy validated in the SSO server.""" |
725 | + self.login_kwargs['email_token'] = EMAIL_TOKEN # valid email token |
726 | + result = self.processor.validate_email(**self.login_kwargs) |
727 | + self.assertEqual(TOKEN, result, 'email validation was successful.') |
728 | + |
729 | + def test_validate_email_if_status_error(self): |
730 | + """Proper error is raised if email validation fails.""" |
731 | + self.login_kwargs['email_token'] = EMAIL_TOKEN * 2 # invalid token |
732 | + failure = self.assertRaises(EmailTokenError, |
733 | + self.processor.validate_email, |
734 | + **self.login_kwargs) |
735 | + for k, val in failure.args[0].items(): |
736 | + self.assertIn(k, STATUS_EMAIL_ERROR['errors']) |
737 | + self.assertEqual(val, "\n".join(STATUS_EMAIL_ERROR['errors'][k])) |
738 | + |
739 | + def test_validate_email_if_status_error_with_string_message(self): |
740 | + """Proper error is raised if register fails.""" |
741 | + self.login_kwargs['email_token'] = EMAIL_ALREADY_REGISTERED |
742 | + failure = self.assertRaises(EmailTokenError, |
743 | + self.processor.validate_email, |
744 | + **self.login_kwargs) |
745 | + for k, val in failure.args[0].items(): |
746 | + self.assertIn(k, {'email': 'Email already registered'}) |
747 | + self.assertEqual(val, 'Email already registered') |
748 | + |
749 | + def test_validate_email_if_status_unknown(self): |
750 | + """Proper error is raised if email validation returns unknown.""" |
751 | + self.login_kwargs['email_token'] = None |
752 | + failure = self.assertRaises(EmailTokenError, |
753 | + self.processor.validate_email, |
754 | + **self.login_kwargs) |
755 | + self.assertIn('Received invalid reply: %s' % STATUS_UNKNOWN, failure) |
756 | + |
757 | + # reset_password |
758 | + |
759 | + def test_request_password_reset_token_if_status_ok(self): |
760 | + """A reset password token is succesfuly sent.""" |
761 | + result = self.processor.request_password_reset_token(email=EMAIL) |
762 | + self.assertEqual(EMAIL, result, |
763 | + 'password reset token must be successful.') |
764 | + |
765 | + def test_request_password_reset_token_if_http_error(self): |
766 | + """Proper error is raised if password token request fails.""" |
767 | + exc = self.assertRaises(ResetPasswordTokenError, |
768 | + self.processor.request_password_reset_token, |
769 | + email=EMAIL * 2) |
770 | + self.assertIn(CANT_RESET_PASSWORD_CONTENT, exc) |
771 | + |
772 | + def test_request_password_reset_token_if_status_unknown(self): |
773 | + """Proper error is raised if password token request returns unknown.""" |
774 | + exc = self.assertRaises(ResetPasswordTokenError, |
775 | + self.processor.request_password_reset_token, |
776 | + email=None) |
777 | + self.assertIn('Received invalid reply: %s' % STATUS_UNKNOWN, exc) |
778 | + |
779 | + def test_set_new_password_if_status_ok(self): |
780 | + """A new password is succesfuy set.""" |
781 | + result = self.processor.set_new_password(email=EMAIL, |
782 | + token=RESET_PASSWORD_TOKEN, |
783 | + new_password=PASSWORD) |
784 | + self.assertEqual(EMAIL, result, |
785 | + 'new password must be set successfully.') |
786 | + |
787 | + def test_set_new_password_if_http_error(self): |
788 | + """Proper error is raised if setting a new password fails.""" |
789 | + exc = self.assertRaises(NewPasswordError, |
790 | + self.processor.set_new_password, |
791 | + email=EMAIL * 2, |
792 | + token=RESET_PASSWORD_TOKEN * 2, |
793 | + new_password=PASSWORD) |
794 | + self.assertIn(RESET_TOKEN_INVALID_CONTENT, exc) |
795 | + |
796 | + def test_set_new_password_if_status_unknown(self): |
797 | + """Proper error is raised if setting a new password returns unknown.""" |
798 | + exc = self.assertRaises(NewPasswordError, |
799 | + self.processor.set_new_password, |
800 | + email=None, token=None, new_password=None) |
801 | + self.assertIn('Received invalid reply: %s' % STATUS_UNKNOWN, exc) |
802 | + |
803 | + |
804 | +class EnvironOverridesTestCase(TestCase): |
805 | + """Some URLs can be set from the environment for testing/QA purposes.""" |
806 | + |
807 | + def test_override_service_url(self): |
808 | + """The service url can be set from the env var USSOC_SERVICE_URL.""" |
809 | + fake_url = 'this is not really a URL' |
810 | + old_url = os.environ.get('USSOC_SERVICE_URL') |
811 | + os.environ['USSOC_SERVICE_URL'] = fake_url |
812 | + try: |
813 | + proc = Account(sso_service_class=FakedSSOServer) |
814 | + self.assertEqual(proc.service_url, fake_url) |
815 | + finally: |
816 | + if old_url: |
817 | + os.environ['USSOC_SERVICE_URL'] = old_url |
818 | + else: |
819 | + del os.environ['USSOC_SERVICE_URL'] |
820 | + |
821 | + def test_no_override_service_url(self): |
822 | + """If the environ is unset, the default service url is used.""" |
823 | + proc = Account(sso_service_class=FakedSSOServer) |
824 | + self.assertEqual(proc.service_url, SERVICE_URL) |
825 | |
826 | === modified file 'ubuntu_sso/tests/test_main.py' |
827 | --- ubuntu_sso/tests/test_main.py 2010-09-30 21:09:44 +0000 |
828 | +++ ubuntu_sso/tests/test_main.py 2010-10-01 17:16:44 +0000 |
829 | @@ -26,10 +26,6 @@ |
830 | |
831 | import gobject |
832 | |
833 | -# Unable to import 'lazr.restfulclient.*' |
834 | -# pylint: disable=F0401 |
835 | -from lazr.restfulclient.errors import HTTPError |
836 | -# pylint: enable=F0401 |
837 | from mocker import Mocker, MockerTestCase, ARGS, KWARGS, ANY |
838 | from twisted.internet.defer import Deferred |
839 | from twisted.trial.unittest import TestCase |
840 | @@ -39,54 +35,23 @@ |
841 | |
842 | from contrib.testing.testcase import MementoHandler |
843 | from ubuntu_sso import gui |
844 | -from ubuntu_sso.keyring import get_token_name, U1_APP_NAME |
845 | -from ubuntu_sso.main import ( |
846 | - AuthenticationError, blocking, EmailTokenError, |
847 | - except_to_errdict, InvalidEmailError, InvalidPasswordError, |
848 | +from ubuntu_sso.keyring import U1_APP_NAME |
849 | +from ubuntu_sso.main import (blocking, except_to_errdict, |
850 | keyring_get_credentials, keyring_store_credentials, logger, |
851 | - NewPasswordError, PING_URL, SERVICE_URL, |
852 | - RegistrationError, ResetPasswordTokenError, |
853 | - SSOCredentials, SSOLogin, SSOLoginProcessor) |
854 | + PING_URL, SSOCredentials, SSOLogin) |
855 | +from ubuntu_sso.tests import (APP_NAME, TC_URL, HELP_TEXT, CAPTCHA_ID, |
856 | + CAPTCHA_SOLUTION, EMAIL, EMAIL_TOKEN, PASSWORD, TOKEN, TOKEN_NAME, |
857 | + WINDOW_ID) |
858 | |
859 | |
860 | # Access to a protected member 'yyy' of a client class |
861 | # pylint: disable=W0212 |
862 | |
863 | - |
864 | -APP_NAME = 'The Coolest App Ever' |
865 | -CAPTCHA_PATH = os.path.abspath(os.path.join(os.curdir, 'ubuntu_sso', 'tests', |
866 | - 'files', 'captcha.png')) |
867 | -CAPTCHA_ID = 'test' |
868 | -CAPTCHA_SOLUTION = 'william Byrd' |
869 | -CANT_RESET_PASSWORD_CONTENT = "CanNotResetPassowrdError: " \ |
870 | - "Can't reset password for this account" |
871 | -RESET_TOKEN_INVALID_CONTENT = "AuthToken matching query does not exist." |
872 | -EMAIL = 'test@example.com' |
873 | -EMAIL_ALREADY_REGISTERED = 'a@example.com' |
874 | -EMAIL_TOKEN = 'B2Pgtf' |
875 | -HELP = 'help text' |
876 | -PASSWORD = 'be4tiFul' |
877 | -RESET_PASSWORD_TOKEN = '8G5Wtq' |
878 | -TOKEN = {u'consumer_key': u'xQ7xDAz', |
879 | - u'consumer_secret': u'KzCJWCTNbbntwfyCKKjomJDzlgqxLy', |
880 | - u'token_name': u'test', |
881 | - u'token': u'GkInOfSMGwTXAUoVQwLUoPxElEEUdhsLVNTPhxHJDUIeHCPNEo', |
882 | - u'token_secret': u'qFYImEtlczPbsCnYyuwLoPDlPEnvNcIktZphPQklAWrvyfFMV'} |
883 | -TOKEN_NAME = get_token_name(APP_NAME) |
884 | -STATUS_UNKNOWN = {'status': 'yadda-yadda'} |
885 | -STATUS_ERROR = {'status': 'error', 'errors': {'something': ['Bla', 'Ble']}} |
886 | -STATUS_OK = {'status': 'ok'} |
887 | -STATUS_EMAIL_UNKNOWN = {'status': 'yadda-yadda'} |
888 | -STATUS_EMAIL_ERROR = {'errors': {'email_token': ['Error1', 'Error2']}} |
889 | -STATUS_EMAIL_OK = {'email': EMAIL} |
890 | -TC_URL = 'tcurl' |
891 | -WINDOW_ID = 5 |
892 | - |
893 | NO_OP = lambda *args, **kwargs: None |
894 | -LOGIN_OR_REGISTER_ARGS = (APP_NAME, TC_URL, HELP, WINDOW_ID) |
895 | +LOGIN_OR_REGISTER_ARGS = (APP_NAME, TC_URL, HELP_TEXT, WINDOW_ID) |
896 | LOGIN_OR_REGISTER_GUI_ARGS = LOGIN_OR_REGISTER_ARGS + (False,) |
897 | -LOGIN_ONLY_ARGS = (APP_NAME, HELP, WINDOW_ID) |
898 | -LOGIN_ONLY_GUI_ARGS = (APP_NAME, None, HELP, WINDOW_ID, True) |
899 | +LOGIN_ONLY_ARGS = (APP_NAME, HELP_TEXT, WINDOW_ID) |
900 | +LOGIN_ONLY_GUI_ARGS = (APP_NAME, None, HELP_TEXT, WINDOW_ID, True) |
901 | |
902 | |
903 | class FakedResponse(object): |
904 | @@ -97,273 +62,6 @@ |
905 | setattr(self, k, val) |
906 | |
907 | |
908 | -class FakedCaptchas(object): |
909 | - """Fake the captcha generator.""" |
910 | - |
911 | - def new(self): |
912 | - """Return a fix captcha).""" |
913 | - return {'image_url': 'file://%s' % CAPTCHA_PATH, |
914 | - 'captcha_id': CAPTCHA_ID} |
915 | - |
916 | - |
917 | -class FakedRegistrations(object): |
918 | - """Fake the registrations service.""" |
919 | - |
920 | - def register(self, email, password, captcha_id, captcha_solution): |
921 | - """Fake registration. Return a fix result.""" |
922 | - if email == EMAIL_ALREADY_REGISTERED: |
923 | - return {'status': 'error', |
924 | - 'errors': {'email': 'Email already registered'}} |
925 | - elif captcha_id is None and captcha_solution is None: |
926 | - return STATUS_UNKNOWN |
927 | - elif captcha_id != CAPTCHA_ID or captcha_solution != CAPTCHA_SOLUTION: |
928 | - return STATUS_ERROR |
929 | - else: |
930 | - return STATUS_OK |
931 | - |
932 | - def request_password_reset_token(self, email): |
933 | - """Fake password reset token. Return a fix result.""" |
934 | - if email is None: |
935 | - return STATUS_UNKNOWN |
936 | - elif email != EMAIL: |
937 | - raise HTTPError(response=None, content=CANT_RESET_PASSWORD_CONTENT) |
938 | - else: |
939 | - return STATUS_OK |
940 | - |
941 | - def set_new_password(self, email, token, new_password): |
942 | - """Fake the setting of new password. Return a fix result.""" |
943 | - if email is None and token is None and new_password is None: |
944 | - return STATUS_UNKNOWN |
945 | - elif email != EMAIL or token != RESET_PASSWORD_TOKEN: |
946 | - raise HTTPError(response=None, content=RESET_TOKEN_INVALID_CONTENT) |
947 | - else: |
948 | - return STATUS_OK |
949 | - |
950 | - |
951 | -class FakedAuthentications(object): |
952 | - """Fake the authentications service.""" |
953 | - |
954 | - def authenticate(self, token_name): |
955 | - """Fake authenticate. Return a fix result.""" |
956 | - if not token_name.startswith(TOKEN_NAME): |
957 | - raise HTTPError(response=None, content=None) |
958 | - else: |
959 | - return TOKEN |
960 | - |
961 | - |
962 | -class FakedAccounts(object): |
963 | - """Fake the accounts service.""" |
964 | - |
965 | - def validate_email(self, email_token): |
966 | - """Fake the email validation. Return a fix result.""" |
967 | - if email_token is None: |
968 | - return STATUS_EMAIL_UNKNOWN |
969 | - elif email_token == EMAIL_ALREADY_REGISTERED: |
970 | - return {'status': 'error', |
971 | - 'errors': {'email': 'Email already registered'}} |
972 | - elif email_token != EMAIL_TOKEN: |
973 | - return STATUS_EMAIL_ERROR |
974 | - else: |
975 | - return STATUS_EMAIL_OK |
976 | - |
977 | - |
978 | -class FakedSSOServer(object): |
979 | - """Fake an SSO server.""" |
980 | - |
981 | - def __init__(self, authorizer, service_root): |
982 | - self.captchas = FakedCaptchas() |
983 | - self.registrations = FakedRegistrations() |
984 | - self.authentications = FakedAuthentications() |
985 | - self.accounts = FakedAccounts() |
986 | - |
987 | - |
988 | -class SSOLoginProcessorTestCase(TestCase, MockerTestCase): |
989 | - """Test suite for the SSO login processor.""" |
990 | - |
991 | - def setUp(self): |
992 | - """Init.""" |
993 | - self.processor = SSOLoginProcessor(sso_service_class=FakedSSOServer) |
994 | - self.register_kwargs = dict(email=EMAIL, password=PASSWORD, |
995 | - captcha_id=CAPTCHA_ID, |
996 | - captcha_solution=CAPTCHA_SOLUTION) |
997 | - self.login_kwargs = dict(email=EMAIL, password=PASSWORD, |
998 | - token_name=TOKEN_NAME) |
999 | - |
1000 | - def tearDown(self): |
1001 | - """Clean up.""" |
1002 | - self.processor = None |
1003 | - |
1004 | - def test_generate_captcha(self): |
1005 | - """Captcha can be generated.""" |
1006 | - filename = self.mktemp() |
1007 | - self.addCleanup(lambda: os.remove(filename)) |
1008 | - captcha_id = self.processor.generate_captcha(filename) |
1009 | - self.assertEqual(CAPTCHA_ID, captcha_id, 'captcha id must be correct.') |
1010 | - self.assertTrue(os.path.isfile(filename), '%s must exist.' % filename) |
1011 | - |
1012 | - with open(CAPTCHA_PATH) as f: |
1013 | - expected = f.read() |
1014 | - with open(filename) as f: |
1015 | - actual = f.read() |
1016 | - self.assertEqual(expected, actual, 'captcha image must be correct.') |
1017 | - |
1018 | - def test_register_user_checks_valid_email(self): |
1019 | - """Email is validated.""" |
1020 | - self.register_kwargs['email'] = 'notavalidemail' |
1021 | - self.assertRaises(InvalidEmailError, |
1022 | - self.processor.register_user, **self.register_kwargs) |
1023 | - |
1024 | - def test_register_user_checks_valid_password(self): |
1025 | - """Password is validated.""" |
1026 | - self.register_kwargs['password'] = '' |
1027 | - self.assertRaises(InvalidPasswordError, |
1028 | - self.processor.register_user, **self.register_kwargs) |
1029 | - |
1030 | - # 7 chars, one less than expected |
1031 | - self.register_kwargs['password'] = 'tesT3it' |
1032 | - self.assertRaises(InvalidPasswordError, |
1033 | - self.processor.register_user, **self.register_kwargs) |
1034 | - |
1035 | - self.register_kwargs['password'] = 'test3it!' # no upper case |
1036 | - self.assertRaises(InvalidPasswordError, |
1037 | - self.processor.register_user, **self.register_kwargs) |
1038 | - |
1039 | - self.register_kwargs['password'] = 'testIt!!' # no number |
1040 | - self.assertRaises(InvalidPasswordError, |
1041 | - self.processor.register_user, **self.register_kwargs) |
1042 | - |
1043 | - # register |
1044 | - |
1045 | - def test_register_user_if_status_ok(self): |
1046 | - """A user is succesfuy registered into the SSO server.""" |
1047 | - result = self.processor.register_user(**self.register_kwargs) |
1048 | - self.assertEqual(EMAIL, result, 'registration was successful.') |
1049 | - |
1050 | - def test_register_user_if_status_error(self): |
1051 | - """Proper error is raised if register fails.""" |
1052 | - self.register_kwargs['captcha_id'] = CAPTCHA_ID * 2 # incorrect |
1053 | - failure = self.assertRaises(RegistrationError, |
1054 | - self.processor.register_user, |
1055 | - **self.register_kwargs) |
1056 | - for k, val in failure.args[0].items(): |
1057 | - self.assertIn(k, STATUS_ERROR['errors']) |
1058 | - self.assertEqual(val, "\n".join(STATUS_ERROR['errors'][k])) |
1059 | - |
1060 | - def test_register_user_if_status_error_with_string_message(self): |
1061 | - """Proper error is raised if register fails.""" |
1062 | - self.register_kwargs['email'] = EMAIL_ALREADY_REGISTERED |
1063 | - failure = self.assertRaises(RegistrationError, |
1064 | - self.processor.register_user, |
1065 | - **self.register_kwargs) |
1066 | - for k, val in failure.args[0].items(): |
1067 | - self.assertIn(k, {'email': 'Email already registered'}) |
1068 | - self.assertEqual(val, 'Email already registered') |
1069 | - |
1070 | - def test_register_user_if_status_unknown(self): |
1071 | - """Proper error is raised if register returns an unknown status.""" |
1072 | - self.register_kwargs['captcha_id'] = None |
1073 | - self.register_kwargs['captcha_solution'] = None |
1074 | - failure = self.assertRaises(RegistrationError, |
1075 | - self.processor.register_user, |
1076 | - **self.register_kwargs) |
1077 | - self.assertIn('Received unknown status: %s' % STATUS_UNKNOWN, failure) |
1078 | - |
1079 | - # login |
1080 | - |
1081 | - def test_login_if_http_error(self): |
1082 | - """Proper error is raised if authentication fails.""" |
1083 | - self.login_kwargs['token_name'] = APP_NAME * 2 # invalid token name |
1084 | - self.assertRaises(AuthenticationError, |
1085 | - self.processor.login, **self.login_kwargs) |
1086 | - |
1087 | - def test_login_if_no_error(self): |
1088 | - """A user can be succesfully logged in into the SSO service.""" |
1089 | - result = self.processor.login(**self.login_kwargs) |
1090 | - self.assertEqual(TOKEN, result, 'authentication was successful.') |
1091 | - |
1092 | - # validate_email |
1093 | - |
1094 | - def test_validate_email_if_status_ok(self): |
1095 | - """A email is succesfuy validated in the SSO server.""" |
1096 | - self.login_kwargs['email_token'] = EMAIL_TOKEN # valid email token |
1097 | - result = self.processor.validate_email(**self.login_kwargs) |
1098 | - self.assertEqual(TOKEN, result, 'email validation was successful.') |
1099 | - |
1100 | - def test_validate_email_if_status_error(self): |
1101 | - """Proper error is raised if email validation fails.""" |
1102 | - self.login_kwargs['email_token'] = EMAIL_TOKEN * 2 # invalid token |
1103 | - failure = self.assertRaises(EmailTokenError, |
1104 | - self.processor.validate_email, |
1105 | - **self.login_kwargs) |
1106 | - for k, val in failure.args[0].items(): |
1107 | - self.assertIn(k, STATUS_EMAIL_ERROR['errors']) |
1108 | - self.assertEqual(val, "\n".join(STATUS_EMAIL_ERROR['errors'][k])) |
1109 | - |
1110 | - def test_validate_email_if_status_error_with_string_message(self): |
1111 | - """Proper error is raised if register fails.""" |
1112 | - self.login_kwargs['email_token'] = EMAIL_ALREADY_REGISTERED |
1113 | - failure = self.assertRaises(EmailTokenError, |
1114 | - self.processor.validate_email, |
1115 | - **self.login_kwargs) |
1116 | - for k, val in failure.args[0].items(): |
1117 | - self.assertIn(k, {'email': 'Email already registered'}) |
1118 | - self.assertEqual(val, 'Email already registered') |
1119 | - |
1120 | - def test_validate_email_if_status_unknown(self): |
1121 | - """Proper error is raised if email validation returns unknown.""" |
1122 | - self.login_kwargs['email_token'] = None |
1123 | - failure = self.assertRaises(EmailTokenError, |
1124 | - self.processor.validate_email, |
1125 | - **self.login_kwargs) |
1126 | - self.assertIn('Received invalid reply: %s' % STATUS_UNKNOWN, failure) |
1127 | - |
1128 | - # reset_password |
1129 | - |
1130 | - def test_request_password_reset_token_if_status_ok(self): |
1131 | - """A reset password token is succesfuly sent.""" |
1132 | - result = self.processor.request_password_reset_token(email=EMAIL) |
1133 | - self.assertEqual(EMAIL, result, |
1134 | - 'password reset token must be successful.') |
1135 | - |
1136 | - def test_request_password_reset_token_if_http_error(self): |
1137 | - """Proper error is raised if password token request fails.""" |
1138 | - exc = self.assertRaises(ResetPasswordTokenError, |
1139 | - self.processor.request_password_reset_token, |
1140 | - email=EMAIL * 2) |
1141 | - self.assertIn(CANT_RESET_PASSWORD_CONTENT, exc) |
1142 | - |
1143 | - def test_request_password_reset_token_if_status_unknown(self): |
1144 | - """Proper error is raised if password token request returns unknown.""" |
1145 | - exc = self.assertRaises(ResetPasswordTokenError, |
1146 | - self.processor.request_password_reset_token, |
1147 | - email=None) |
1148 | - self.assertIn('Received invalid reply: %s' % STATUS_UNKNOWN, exc) |
1149 | - |
1150 | - def test_set_new_password_if_status_ok(self): |
1151 | - """A new password is succesfuy set.""" |
1152 | - result = self.processor.set_new_password(email=EMAIL, |
1153 | - token=RESET_PASSWORD_TOKEN, |
1154 | - new_password=PASSWORD) |
1155 | - self.assertEqual(EMAIL, result, |
1156 | - 'new password must be set successfully.') |
1157 | - |
1158 | - def test_set_new_password_if_http_error(self): |
1159 | - """Proper error is raised if setting a new password fails.""" |
1160 | - exc = self.assertRaises(NewPasswordError, |
1161 | - self.processor.set_new_password, |
1162 | - email=EMAIL * 2, |
1163 | - token=RESET_PASSWORD_TOKEN * 2, |
1164 | - new_password=PASSWORD) |
1165 | - self.assertIn(RESET_TOKEN_INVALID_CONTENT, exc) |
1166 | - |
1167 | - def test_set_new_password_if_status_unknown(self): |
1168 | - """Proper error is raised if setting a new password returns unknown.""" |
1169 | - exc = self.assertRaises(NewPasswordError, |
1170 | - self.processor.set_new_password, |
1171 | - email=None, token=None, new_password=None) |
1172 | - self.assertIn('Received invalid reply: %s' % STATUS_UNKNOWN, exc) |
1173 | - |
1174 | - |
1175 | class BlockingSampleException(Exception): |
1176 | """The exception that will be thrown by the fake blocking.""" |
1177 | |
1178 | @@ -1391,22 +1089,3 @@ |
1179 | """If the environ is unset, the default ping url is used.""" |
1180 | creds = SSOCredentials(None) |
1181 | self.assertEqual(creds.ping_url, PING_URL) |
1182 | - |
1183 | - def test_override_service_url(self): |
1184 | - """The service url can be set from the env var USSOC_SERVICE_URL.""" |
1185 | - fake_url = 'this is not really a URL' |
1186 | - old_url = os.environ.get('USSOC_SERVICE_URL') |
1187 | - os.environ['USSOC_SERVICE_URL'] = fake_url |
1188 | - try: |
1189 | - proc = SSOLoginProcessor(sso_service_class=FakedSSOServer) |
1190 | - self.assertEqual(proc.service_url, fake_url) |
1191 | - finally: |
1192 | - if old_url: |
1193 | - os.environ['USSOC_SERVICE_URL'] = old_url |
1194 | - else: |
1195 | - del os.environ['USSOC_SERVICE_URL'] |
1196 | - |
1197 | - def test_no_override_service_url(self): |
1198 | - """If the environ is unset, the default service url is used.""" |
1199 | - proc = SSOLoginProcessor(sso_service_class=FakedSSOServer) |
1200 | - self.assertEqual(proc.service_url, SERVICE_URL) |
can I sugest firing a DeprecationWarning in the __init__ of SSOLoginProcessor?