pyramid-fullauth 0.3.0__py2.7.egg

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. EGG-INFO/PKG-INFO +176 -0
  2. EGG-INFO/SOURCES.txt +91 -0
  3. EGG-INFO/dependency_links.txt +1 -0
  4. EGG-INFO/not-zip-safe +1 -0
  5. EGG-INFO/requires.txt +17 -0
  6. EGG-INFO/top_level.txt +2 -0
  7. pyramid_fullauth/__init__.py +105 -0
  8. pyramid_fullauth/__init__.pyc +0 -0
  9. pyramid_fullauth/auth.py +66 -0
  10. pyramid_fullauth/auth.pyc +0 -0
  11. pyramid_fullauth/events.py +267 -0
  12. pyramid_fullauth/events.pyc +0 -0
  13. pyramid_fullauth/exceptions.py +47 -0
  14. pyramid_fullauth/exceptions.pyc +0 -0
  15. pyramid_fullauth/models/__init__.py +189 -0
  16. pyramid_fullauth/models/__init__.pyc +0 -0
  17. pyramid_fullauth/models/mixins/__init__.py +9 -0
  18. pyramid_fullauth/models/mixins/__init__.pyc +0 -0
  19. pyramid_fullauth/models/mixins/email.py +81 -0
  20. pyramid_fullauth/models/mixins/email.pyc +0 -0
  21. pyramid_fullauth/models/mixins/password.py +141 -0
  22. pyramid_fullauth/models/mixins/password.pyc +0 -0
  23. pyramid_fullauth/request.py +69 -0
  24. pyramid_fullauth/request.pyc +0 -0
  25. pyramid_fullauth/resources/helpers/social.mako +17 -0
  26. pyramid_fullauth/resources/locale/pyramid_fullauth.pot +216 -0
  27. pyramid_fullauth/resources/templates/403.mako +11 -0
  28. pyramid_fullauth/resources/templates/_form.login.mako +44 -0
  29. pyramid_fullauth/resources/templates/_form.register.mako +47 -0
  30. pyramid_fullauth/resources/templates/_social.login.mako +17 -0
  31. pyramid_fullauth/resources/templates/activate.mako +14 -0
  32. pyramid_fullauth/resources/templates/email_change.mako +33 -0
  33. pyramid_fullauth/resources/templates/layout.mako +13 -0
  34. pyramid_fullauth/resources/templates/login.mako +14 -0
  35. pyramid_fullauth/resources/templates/register.mako +22 -0
  36. pyramid_fullauth/resources/templates/reset.mako +34 -0
  37. pyramid_fullauth/resources/templates/reset.proceed.mako +41 -0
  38. pyramid_fullauth/routing/__init__.py +5 -0
  39. pyramid_fullauth/routing/__init__.pyc +0 -0
  40. pyramid_fullauth/routing/predicates.py +86 -0
  41. pyramid_fullauth/routing/predicates.pyc +0 -0
  42. pyramid_fullauth/tools.py +66 -0
  43. pyramid_fullauth/tools.pyc +0 -0
  44. pyramid_fullauth/views/__init__.py +15 -0
  45. pyramid_fullauth/views/__init__.pyc +0 -0
  46. pyramid_fullauth/views/basic/__init__.py +5 -0
  47. pyramid_fullauth/views/basic/__init__.pyc +0 -0
  48. pyramid_fullauth/views/basic/activate.py +44 -0
  49. pyramid_fullauth/views/basic/activate.pyc +0 -0
  50. pyramid_fullauth/views/basic/forbidden.py +47 -0
  51. pyramid_fullauth/views/basic/forbidden.pyc +0 -0
  52. pyramid_fullauth/views/basic/login.py +128 -0
  53. pyramid_fullauth/views/basic/login.pyc +0 -0
  54. pyramid_fullauth/views/basic/logout.py +28 -0
  55. pyramid_fullauth/views/basic/logout.pyc +0 -0
  56. pyramid_fullauth/views/basic/profile/__init__.py +5 -0
  57. pyramid_fullauth/views/basic/profile/__init__.pyc +0 -0
  58. pyramid_fullauth/views/basic/profile/email.py +107 -0
  59. pyramid_fullauth/views/basic/profile/email.pyc +0 -0
  60. pyramid_fullauth/views/basic/profile/password.py +128 -0
  61. pyramid_fullauth/views/basic/profile/password.pyc +0 -0
  62. pyramid_fullauth/views/basic/register.py +110 -0
  63. pyramid_fullauth/views/basic/register.pyc +0 -0
  64. pyramid_fullauth/views/social.py +218 -0
  65. pyramid_fullauth/views/social.pyc +0 -0
  66. tests/__init__.py +1 -0
  67. tests/__init__.pyc +0 -0
  68. tests/conftest.py +190 -0
  69. tests/conftest.pyc +0 -0
  70. tests/tools.py +54 -0
  71. tests/tools.pyc +0 -0
  72. tests/unit/test_default_settings.py +15 -0
  73. tests/unit/test_default_settings.pyc +0 -0
  74. tests/unit/test_groupfinder.py +20 -0
  75. tests/unit/test_groupfinder.pyc +0 -0
  76. tests/unit/test_social_view.py +65 -0
  77. tests/unit/test_social_view.pyc +0 -0
  78. tests/unit/test_tools.py +24 -0
  79. tests/unit/test_tools.pyc +0 -0
  80. tests/unit/test_user_active.py +31 -0
  81. tests/unit/test_user_active.pyc +0 -0
  82. tests/unit/test_user_admin.py +61 -0
  83. tests/unit/test_user_admin.pyc +0 -0
  84. tests/unit/test_user_email.py +37 -0
  85. tests/unit/test_user_email.pyc +0 -0
  86. tests/unit/test_user_password.py +52 -0
  87. tests/unit/test_user_password.pyc +0 -0
  88. tests/unit/test_user_providers.py +24 -0
  89. tests/unit/test_user_providers.pyc +0 -0
  90. tests/unit/test_user_repr.py +29 -0
  91. tests/unit/test_user_repr.pyc +0 -0
  92. tests/unit/test_validators.py +44 -0
  93. tests/unit/test_validators.pyc +0 -0
  94. tests/views/__init__.py +1 -0
  95. tests/views/__init__.pyc +0 -0
  96. tests/views/conftest.py +15 -0
  97. tests/views/conftest.pyc +0 -0
  98. tests/views/test_activation.py +83 -0
  99. tests/views/test_activation.pyc +0 -0
  100. tests/views/test_email.py +175 -0
  101. tests/views/test_email.pyc +0 -0
  102. tests/views/test_events.py +546 -0
  103. tests/views/test_events.pyc +0 -0
  104. tests/views/test_login.py +151 -0
  105. tests/views/test_login.pyc +0 -0
  106. tests/views/test_login_social.py +254 -0
  107. tests/views/test_login_social.pyc +0 -0
  108. tests/views/test_logout.py +42 -0
  109. tests/views/test_logout.pyc +0 -0
  110. tests/views/test_register.py +134 -0
  111. tests/views/test_register.pyc +0 -0
  112. tests/views/test_reset.py +100 -0
  113. tests/views/test_reset.pyc +0 -0
@@ -0,0 +1,546 @@
1
+ """All events related tests."""
2
+ import pytest
3
+ import transaction
4
+ from mock import MagicMock
5
+ from pyramid import testing
6
+ from pyramid.view import view_config
7
+ from pyramid.httpexceptions import HTTPFound
8
+ from velruse import AuthenticationComplete
9
+ from sqlalchemy.orm.exc import NoResultFound
10
+ from pytest_pyramid import factories
11
+
12
+
13
+ from pyramid_fullauth.models import User
14
+ from pyramid_fullauth.views.social import SocialLoginViews
15
+ from pyramid_fullauth.events import (
16
+ BeforeLogIn, AfterLogIn, AlreadyLoggedIn,
17
+ BeforeEmailChange, AfterEmailChange, AfterEmailChangeActivation,
18
+ BeforeReset, AfterResetRequest, AfterReset,
19
+ AfterSocialRegister, AfterSocialLogIn, SocialAccountAlreadyConnected,
20
+ AfterActivate,
21
+ BeforeRegister, AfterRegister
22
+ )
23
+ from tests.tools import authenticate, is_user_logged, DEFAULT_USER
24
+
25
+ EVENT_PATH = '/event?event={0.__name__}'
26
+ EVENT_URL = 'http://localhost' + EVENT_PATH
27
+
28
+
29
+ evented_config = factories.pyramid_config({
30
+ 'yml.location': 'tests:config',
31
+ 'env': 'login',
32
+ 'pyramid.includes': [
33
+ 'pyramid_tm',
34
+ 'pyramid_fullauth',
35
+ 'tests.tools.include_views',
36
+ 'tests.views.test_events.include_views'
37
+ ]
38
+ })
39
+
40
+
41
+ def include_views(config):
42
+ """Dummy pyramid plugin including events."""
43
+ config.add_route('event', '/event')
44
+ config.scan('tests.views.test_events')
45
+ # config.add_subscriber(raise_attribute_error, BeforeLogIn)
46
+
47
+
48
+ @view_config(route_name="event", renderer='json')
49
+ def event_view(request):
50
+ """Dummy view."""
51
+ return {'event', request.GET.get('event')}
52
+
53
+
54
+ def redirect_to_secret(event):
55
+ """Redirect to event page with event name set as query event attribute."""
56
+ raise HTTPFound(
57
+ event.request.route_path(
58
+ 'event', _query=(('event', event.__class__.__name__),)
59
+ ))
60
+
61
+
62
+ def raise_attribute_error(event):
63
+ """Raise attribute error with message being the event class name."""
64
+ if event.user:
65
+ raise AttributeError(event.__class__.__name__)
66
+
67
+
68
+ @pytest.fixture
69
+ def alreadyloggedin_config(evented_config):
70
+ """Add AlreadyLoggedIn event subscriber that redirects to event page."""
71
+ evented_config.add_subscriber(redirect_to_secret, AlreadyLoggedIn)
72
+ return evented_config
73
+
74
+ alreadyloggedin_app = factories.pyramid_app('alreadyloggedin_config')
75
+
76
+
77
+ def test_default_login_redirect_from_event(active_user, alreadyloggedin_app):
78
+ """After successful login, access to login page should result in redirect."""
79
+ authenticate(alreadyloggedin_app)
80
+ res = alreadyloggedin_app.get('/login', status=302)
81
+ assert res.location == EVENT_URL.format(AlreadyLoggedIn)
82
+
83
+
84
+ @pytest.fixture
85
+ def beforelogin_config(evented_config):
86
+ """Add BeforeLogIn event that raises AttributeError with event class name."""
87
+ evented_config.add_subscriber(raise_attribute_error, BeforeLogIn)
88
+ return evented_config
89
+
90
+ beforelogin_app = factories.pyramid_app('beforelogin_config')
91
+
92
+
93
+ def test_error_beforelogin(active_user, beforelogin_app):
94
+ """Test errors from BeforeLogIn event."""
95
+ res = beforelogin_app.get('/login')
96
+ post_data = {
97
+ 'email': DEFAULT_USER['email'],
98
+ 'password': DEFAULT_USER['password'],
99
+ 'csrf_token': res.form['csrf_token'].value
100
+ }
101
+ res = beforelogin_app.post('/login', post_data, xhr=True)
102
+ assert res.json['status'] is False
103
+ assert res.json['msg'] == 'BeforeLogIn'
104
+
105
+
106
+ @pytest.fixture
107
+ def afterlogin_config(evented_config):
108
+ """Add AfterLogIn event subscriber that redirects to event page."""
109
+ evented_config.add_subscriber(redirect_to_secret, AfterLogIn)
110
+ return evented_config
111
+
112
+ afterlogin_app = factories.pyramid_app('afterlogin_config')
113
+
114
+
115
+ def test_login_redirect(active_user, afterlogin_app):
116
+ """Log in and test redirect from AfterLogIn."""
117
+ assert is_user_logged(afterlogin_app) is False
118
+
119
+ res = authenticate(afterlogin_app)
120
+ assert res.location == EVENT_URL.format(AfterLogIn)
121
+
122
+ assert is_user_logged(afterlogin_app) is True
123
+
124
+
125
+ @pytest.fixture
126
+ def afterloginerror_config(evented_config):
127
+ """Add AfterLogIn event subscriber that raises AttributeError."""
128
+ evented_config.add_subscriber(raise_attribute_error, AfterLogIn)
129
+ return evented_config
130
+
131
+ afterloginerror_app = factories.pyramid_app('afterloginerror_config')
132
+
133
+
134
+ def test_error_afterlogin(active_user, afterloginerror_app):
135
+ """Test errors from BeforeLogIn event."""
136
+ res = afterloginerror_app.get('/login')
137
+ post_data = {
138
+ 'email': DEFAULT_USER['email'],
139
+ 'password': DEFAULT_USER['password'],
140
+ 'csrf_token': res.form['csrf_token'].value
141
+ }
142
+ res = afterloginerror_app.post('/login', post_data, xhr=True)
143
+ assert res.json['status'] is False
144
+ assert res.json['msg'] == 'AfterLogIn'
145
+
146
+ assert is_user_logged(afterloginerror_app) is False
147
+
148
+
149
+ @pytest.fixture
150
+ def beforeemailchange_config(evented_config):
151
+ """Add BeforeEmailChange event subscriber that raises AttributeError."""
152
+ evented_config.add_subscriber(raise_attribute_error, BeforeEmailChange)
153
+ return evented_config
154
+
155
+ beforeemailchange_app = factories.pyramid_app('beforeemailchange_config')
156
+
157
+
158
+ def test_beforeemailchange_error(active_user, beforeemailchange_app):
159
+ """Raise AttributeError from BeforeEmailChange event."""
160
+ app = beforeemailchange_app
161
+
162
+ authenticate(app)
163
+ new_email = 'email@email.com'
164
+
165
+ res = app.get('/email/change')
166
+ res = app.post(
167
+ '/email/change',
168
+ {
169
+ 'csrf_token': res.form['csrf_token'].value,
170
+ 'email': new_email},
171
+ xhr=True)
172
+ assert res.json['status'] is False
173
+ assert res.json['msg'] == 'BeforeEmailChange'
174
+
175
+
176
+ @pytest.fixture
177
+ def afteremailchange_config(evented_config):
178
+ """Add AfterEmailChange, AfterEmailChangeActivation event subscriber that redirects to event page."""
179
+ evented_config.add_subscriber(redirect_to_secret, AfterEmailChange)
180
+ evented_config.add_subscriber(redirect_to_secret, AfterEmailChangeActivation)
181
+ return evented_config
182
+
183
+ afteremailchange_app = factories.pyramid_app('afteremailchange_config')
184
+
185
+
186
+ def test_afteremailchange(db_session, active_user, afteremailchange_app):
187
+ """Redirect after successful email change request."""
188
+ app = afteremailchange_app
189
+
190
+ authenticate(app)
191
+ email = DEFAULT_USER['email']
192
+ new_email = 'email@email.com'
193
+
194
+ user = db_session.query(User).filter(User.email == email).one()
195
+
196
+ res = app.get('/email/change')
197
+ form = res.form
198
+ form['email'] = new_email
199
+ res = form.submit()
200
+ assert res.location == EVENT_URL.format(AfterEmailChange)
201
+
202
+ transaction.commit()
203
+
204
+ user = db_session.query(User).filter(User.email == email).one()
205
+ assert user.new_email == new_email
206
+ assert user.email == email
207
+ assert user.email_change_key is not None
208
+
209
+
210
+ def test_afteremailchange_xhr(db_session, active_user, afteremailchange_app):
211
+ """Change email with valid data."""
212
+ app = afteremailchange_app
213
+
214
+ authenticate(app)
215
+ email = DEFAULT_USER['email']
216
+ new_email = 'email@email.com'
217
+
218
+ user = db_session.query(User).filter(User.email == email).one()
219
+
220
+ res = app.get('/email/change')
221
+ res = app.post(
222
+ '/email/change',
223
+ {
224
+ 'csrf_token': res.form['csrf_token'].value,
225
+ 'email': new_email},
226
+ xhr=True)
227
+ assert res.json['status'] is True
228
+ assert res.json['url'] == EVENT_PATH.format(AfterEmailChange)
229
+
230
+ transaction.commit()
231
+
232
+ user = db_session.query(User).filter(User.email == email).one()
233
+ assert user.new_email == new_email
234
+ assert user.email == email
235
+ assert user.email_change_key is not None
236
+
237
+
238
+ def test_afteremailchangeactivation(db_session, active_user, afteremailchange_app):
239
+ """Confirm email change view with redirect from AfterEmailChangeActivation."""
240
+ app = afteremailchange_app
241
+ # login user
242
+ authenticate(app)
243
+
244
+ email = DEFAULT_USER['email']
245
+ user = db_session.query(User).filter(User.email == email).one()
246
+
247
+ new_email = u'email2@email.com'
248
+ user.set_new_email(new_email)
249
+ transaction.commit()
250
+
251
+ user = db_session.merge(user)
252
+ res = app.get('/email/change/' + user.email_change_key)
253
+ assert res.status_code == 302
254
+ assert res.location == EVENT_URL.format(AfterEmailChangeActivation)
255
+
256
+ with pytest.raises(NoResultFound):
257
+ # there is no user with old email
258
+ db_session.query(User).filter(User.email == email).one()
259
+
260
+ user = db_session.query(User).filter(User.email == new_email).one()
261
+ assert not user.email_change_key
262
+
263
+
264
+ @pytest.fixture
265
+ def afterreset_config(evented_config):
266
+ """Add AfterReset, AfterResetRequest event subscriber that redirects to event page."""
267
+ evented_config.add_subscriber(redirect_to_secret, AfterResetRequest)
268
+ evented_config.add_subscriber(redirect_to_secret, AfterReset)
269
+ return evented_config
270
+
271
+ afterreset_app = factories.pyramid_app('afterreset_config')
272
+
273
+
274
+ def test_afterresetrequest(user, db_session, afterreset_app):
275
+ """Successful password reset request with redirect from AfterResetRequest."""
276
+ user = db_session.merge(user)
277
+ assert user.reset_key is None
278
+
279
+ res = afterreset_app.get('/password/reset')
280
+ res.form['email'] = user.email
281
+ res = res.form.submit()
282
+ assert res.location == EVENT_URL.format(AfterResetRequest)
283
+
284
+ transaction.commit()
285
+
286
+ user = db_session.query(User).filter(User.email == user.email).one()
287
+ assert user.reset_key is not None
288
+
289
+
290
+ def test_afterreset(user, db_session, afterreset_app):
291
+ """Actually change password with redirect from AfterReset."""
292
+ user = db_session.merge(user)
293
+ user.set_reset()
294
+ transaction.commit()
295
+
296
+ user = db_session.merge(user)
297
+ res = afterreset_app.get('/password/reset/' + user.reset_key)
298
+
299
+ res.form['password'] = 'YouShallPass'
300
+ res.form['confirm_password'] = 'YouShallPass'
301
+ res = res.form.submit()
302
+ assert res.location == EVENT_URL.format(AfterReset)
303
+
304
+ user = db_session.query(User).filter(User.email == user.email).one()
305
+ assert user.reset_key is None
306
+ assert user.check_password('YouShallPass') is True
307
+
308
+
309
+ @pytest.fixture
310
+ def beforereset_config(evented_config):
311
+ """Add BeforeReset event subscriber that raises AttributeError."""
312
+ evented_config.add_subscriber(raise_attribute_error, BeforeReset)
313
+ return evented_config
314
+
315
+ beforereset_app = factories.pyramid_app('beforereset_config')
316
+
317
+
318
+ def test_beforereset(user, db_session, beforereset_app):
319
+ """Error thrown from BeforeReset event."""
320
+ user = db_session.merge(user)
321
+ user.set_reset()
322
+ transaction.commit()
323
+
324
+ user = db_session.merge(user)
325
+ res = beforereset_app.get('/password/reset/' + user.reset_key)
326
+
327
+ res.form['password'] = 'YouShallPass'
328
+ res.form['confirm_password'] = 'YouShallPass'
329
+ res = res.form.submit()
330
+ assert 'Error! BeforeReset' in res.body
331
+
332
+
333
+ @pytest.fixture
334
+ def aftersocialregister_config(evented_config):
335
+ """Add AfterSocialRegister event subscriber that redirects to event page."""
336
+ evented_config.add_subscriber(redirect_to_secret, AfterSocialRegister)
337
+ return evented_config
338
+
339
+ aftersocialregister_app = factories.pyramid_app('aftersocialregister_config')
340
+
341
+
342
+ def test_aftersocialregister(aftersocialregister_config, aftersocialregister_app, db_session):
343
+ """Register fresh user and logs him in and check response if redirect from AfterSocialRegister."""
344
+ profile = {
345
+ 'accounts': [{'domain': u'facebook.com', 'userid': u'2343'}],
346
+ 'displayName': u'teddy',
347
+ 'verifiedEmail': u'we@po.pl',
348
+ 'preferredUsername': u'teddy',
349
+ 'emails': [{'value': u'aasd@bwwqwe.pl'}],
350
+ 'name': u'ted'
351
+ }
352
+ credentials = {'oauthAccessToken': '7897048593434'}
353
+ provider_name = u'facebook'
354
+ provider_type = u'facebook'
355
+ request = testing.DummyRequest()
356
+ request.user = None
357
+ request.registry = aftersocialregister_config.registry
358
+ request.remote_addr = u'127.0.0.123'
359
+ request.context = AuthenticationComplete(profile, credentials, provider_name, provider_type)
360
+
361
+ request.login_perform = MagicMock(name='login_perform')
362
+ request.login_perform.return_value = {'status': True}
363
+ view = SocialLoginViews(request)
364
+ out = view()
365
+ assert out.location == EVENT_PATH.format(AfterSocialRegister)
366
+ transaction.commit()
367
+
368
+ # read first new account
369
+ user = db_session.query(User).one()
370
+ assert user.is_active
371
+ assert user.provider_id('facebook') == profile['accounts'][0]['userid']
372
+
373
+
374
+ @pytest.fixture
375
+ def aftersociallogin_config(evented_config):
376
+ """Add AfterSocialLogIn event subscriber that redirects to event page."""
377
+ evented_config.add_subscriber(redirect_to_secret, AfterSocialLogIn)
378
+ return evented_config
379
+
380
+ aftersociallogin_app = factories.pyramid_app('aftersociallogin_config')
381
+
382
+
383
+ def test_aftersociallogin(aftersociallogin_config, aftersociallogin_app, db_session):
384
+ """Register fresh user and logs him in and check response if redirect from AfterSocialLogIn."""
385
+ profile = {
386
+ 'accounts': [{'domain': u'facebook.com', 'userid': u'2343'}],
387
+ 'displayName': u'teddy',
388
+ 'verifiedEmail': u'we@po.pl',
389
+ 'preferredUsername': u'teddy',
390
+ 'emails': [{'value': u'aasd@bwwqwe.pl'}],
391
+ 'name': u'ted'
392
+ }
393
+ credentials = {'oauthAccessToken': '7897048593434'}
394
+ provider_name = u'facebook'
395
+ provider_type = u'facebook'
396
+ request = testing.DummyRequest()
397
+ request.user = None
398
+ request.registry = aftersociallogin_config.registry
399
+ request.remote_addr = u'127.0.0.123'
400
+ request.context = AuthenticationComplete(profile, credentials, provider_name, provider_type)
401
+
402
+ def login_perform(*args, **kwargs):
403
+ return HTTPFound(location=kwargs['location'])
404
+ request.login_perform = login_perform
405
+ view = SocialLoginViews(request)
406
+ out = view()
407
+ assert out.location == EVENT_PATH.format(AfterSocialLogIn)
408
+ transaction.commit()
409
+
410
+ # read first new account
411
+ user = db_session.query(User).one()
412
+ assert user.is_active
413
+ assert user.provider_id('facebook') == profile['accounts'][0]['userid']
414
+
415
+
416
+ @pytest.fixture
417
+ def alreadyconnected_config(evented_config):
418
+ """Add SocialAccountAlreadyConnected event subscriber that redirects to event page."""
419
+ evented_config.add_subscriber(redirect_to_secret, SocialAccountAlreadyConnected)
420
+ return evented_config
421
+
422
+ alreadyconnected_app = factories.pyramid_app('alreadyconnected_config')
423
+
424
+
425
+ def test_alreadyconnected(alreadyconnected_config, alreadyconnected_app, facebook_user, db_session):
426
+ """Try to connect facebook account to logged in user used by other user check redirect from SocialAccountAlreadyConnected."""
427
+ # this user will be logged and trying to connect facebook's user account.
428
+ fresh_user = User(
429
+ email='new@user.pl',
430
+ password='somepassword',
431
+ address_ip='127.0.0.1')
432
+ db_session.add(fresh_user)
433
+ transaction.commit()
434
+ user = db_session.merge(facebook_user)
435
+ fresh_user = db_session.merge(fresh_user)
436
+
437
+ # mock request
438
+ profile = {
439
+ 'accounts': [{'domain': u'facebook.com', 'userid': user.provider_id('facebook')}],
440
+ 'displayName': u'teddy',
441
+ 'preferredUsername': u'teddy',
442
+ 'emails': [{'value': u'aasd@basd.pl'}],
443
+ 'name': u'ted'
444
+ }
445
+ credentials = {'oauthAccessToken': '7897048593434'}
446
+ provider_name = u'facebook'
447
+ provider_type = u'facebook'
448
+ request = testing.DummyRequest()
449
+ request.user = fresh_user
450
+ request.registry = alreadyconnected_config.registry
451
+ request.remote_addr = u'127.0.0.123'
452
+ request.context = AuthenticationComplete(profile, credentials, provider_name, provider_type)
453
+ request._ = lambda msg, *args, **kwargs: msg
454
+
455
+ request.login_perform = MagicMock(name='login_perform')
456
+ request.login_perform.return_value = {'status': True}
457
+ # call!
458
+ view = SocialLoginViews(request)
459
+ out = view()
460
+ assert out.location == EVENT_PATH.format(SocialAccountAlreadyConnected)
461
+ transaction.begin()
462
+ fresh_user = db_session.merge(fresh_user)
463
+ assert fresh_user.provider_id('facebook') is None
464
+
465
+
466
+ @pytest.fixture
467
+ def afteractivate_config(evented_config):
468
+ """Add AfterActivate event subscriber that redirects to event page."""
469
+ evented_config.add_subscriber(redirect_to_secret, AfterActivate)
470
+ return evented_config
471
+
472
+ afteractivate_app = factories.pyramid_app('afteractivate_config')
473
+
474
+
475
+ def test_afteractivate(user, db_session, afteractivate_app):
476
+ """Activate user adn check redirect through AfterActivate."""
477
+ user = db_session.merge(user)
478
+
479
+ res = afteractivate_app.get('/register/activate/' + user.activate_key)
480
+ assert res.location == EVENT_URL.format(AfterActivate)
481
+ transaction.commit()
482
+ user = db_session.query(User).filter(User.email == user.email).one()
483
+
484
+ assert not user.activate_key
485
+ assert user.is_active
486
+ assert user.activated_at
487
+
488
+ authenticate(afteractivate_app)
489
+ assert is_user_logged(afteractivate_app) is True
490
+
491
+
492
+ @pytest.fixture
493
+ def beforeregister_config(evented_config):
494
+ """Add BeforeRegister event subscriber that raises AttributeError."""
495
+ evented_config.add_subscriber(raise_attribute_error, BeforeRegister)
496
+ return evented_config
497
+
498
+ beforeregister_app = factories.pyramid_app('beforeregister_config')
499
+
500
+
501
+ def test_beforeregister(db_session, beforeregister_app):
502
+ """Register user check eror catching from BeforeRegister event."""
503
+ assert db_session.query(User).count() == 0
504
+
505
+ res = beforeregister_app.get('/register')
506
+ res = beforeregister_app.post(
507
+ '/register',
508
+ {
509
+ 'csrf_token': res.form['csrf_token'].value,
510
+ 'email': 'test@test.co.uk',
511
+ 'password': 'passmeplease',
512
+ 'confirm_password': 'passmeplease'
513
+ },
514
+ extra_environ={'REMOTE_ADDR': '0.0.0.0'},
515
+ xhr=True)
516
+ assert res.json['errors']['msg'] == 'BeforeRegister'
517
+
518
+
519
+ @pytest.fixture
520
+ def afterregister_config(evented_config):
521
+ """Add AfterRegister event subscriber that redirects to event page."""
522
+ evented_config.add_subscriber(redirect_to_secret, AfterRegister)
523
+ return evented_config
524
+
525
+ afteraregister_app = factories.pyramid_app('afterregister_config')
526
+
527
+
528
+ def test_afterregister(db_session, afteraregister_app):
529
+ """Register user check eror catching from BeforeRegister event."""
530
+ assert db_session.query(User).count() == 0
531
+ email = 'test@test.co.uk'
532
+ password = 'passmeplease'
533
+
534
+ res = afteraregister_app.get('/register')
535
+ res.form['email'] = email
536
+ res.form['password'] = password
537
+ res.form['confirm_password'] = password
538
+ res = res.form.submit(extra_environ={'REMOTE_ADDR': '0.0.0.0'})
539
+ assert res.location == EVENT_URL.format(AfterRegister)
540
+ transaction.commit()
541
+
542
+ user = db_session.query(User).filter(User.email == email).one()
543
+
544
+ # User should not have active account at this moment
545
+ assert user.is_active is not None
546
+ assert user.check_password(password)
Binary file
@@ -0,0 +1,151 @@
1
+ """Log in related test."""
2
+ import pytest
3
+ from tests.tools import authenticate, is_user_logged, DEFAULT_USER
4
+
5
+
6
+ def test_login_view(default_app):
7
+ """Login view."""
8
+ res = default_app.get('/login')
9
+ assert res.form
10
+ assert 'email' in res.form.fields
11
+ assert 'password' in res.form.fields
12
+ assert 'remember' in res.form.fields
13
+
14
+
15
+ def test_login_view_secret(extended_app):
16
+ """Login:Form displayed after redirect from protected view."""
17
+ res = extended_app.get('/secret', status=302)
18
+ # check if redirect is correct
19
+ assert res.headers['Location'] == 'http://localhost/login?after=%2Fsecret'
20
+ # redirecting
21
+ res = extended_app.get(res.headers['Location'])
22
+ assert res.form
23
+ assert 'email' in res.form.fields
24
+
25
+
26
+ def test_login(active_user, extended_app):
27
+ """Actually log in test."""
28
+ res = extended_app.get('/secret', status=302)
29
+ res = res.follow()
30
+ res = extended_app.get('/login?after=%2Fsecret')
31
+
32
+ assert is_user_logged(extended_app) is False
33
+
34
+ res = authenticate(extended_app)
35
+ assert 'Max-Age=' not in str(res)
36
+
37
+ assert is_user_logged(extended_app) is True
38
+
39
+
40
+ def test_login_remember(active_user, extended_app):
41
+ """Login user and mark remember me field."""
42
+ res = extended_app.get('/login')
43
+ assert is_user_logged(extended_app) is False
44
+
45
+ res = authenticate(extended_app, remember=True)
46
+
47
+ assert is_user_logged(extended_app) is True
48
+ assert 'Max-Age=' in str(res)
49
+
50
+
51
+ def test_login_inactive(user, extended_app):
52
+ """Log in inactive user."""
53
+ assert is_user_logged(extended_app) is False
54
+
55
+ authenticate(extended_app)
56
+
57
+ assert is_user_logged(extended_app) is True
58
+
59
+
60
+ def test_login_redirects(active_user, extended_app):
61
+ """Login with redirects."""
62
+ res = extended_app.get('/secret', status=302)
63
+ assert res.status_code == 302
64
+ res = res.follow()
65
+ res.form['email'] = DEFAULT_USER['email']
66
+ res.form['password'] = DEFAULT_USER['password']
67
+ res = res.form.submit()
68
+
69
+ assert is_user_logged(extended_app) is True
70
+ assert res.status_code == 302
71
+
72
+
73
+ @pytest.mark.parametrize('user_kwargs', (
74
+ {'password': 'wrong password'},
75
+ {'email': 'not@registered.py'}
76
+ ))
77
+ def test_login_wrong(active_user, user_kwargs, extended_app):
78
+ """Use wrong password during authentication."""
79
+ res = authenticate(extended_app, response_code=200, **user_kwargs)
80
+
81
+ assert 'Error! Wrong e-mail or password.' in res
82
+ assert res
83
+
84
+
85
+ @pytest.mark.parametrize('post_data', (
86
+ {
87
+ 'email': DEFAULT_USER['email'],
88
+ 'password': DEFAULT_USER['password'],
89
+ }, {
90
+ 'email': DEFAULT_USER['email'],
91
+ 'password': DEFAULT_USER['password'],
92
+ 'csrf_token': '8934798289723789347892397832789432789'
93
+ }
94
+
95
+ ))
96
+ def test_login_csrf_error(active_user, extended_app, post_data):
97
+ """Try to log in with erroneus csrf token."""
98
+ res = extended_app.get('/login', status=200)
99
+ assert res
100
+ res = extended_app.post('/login', post_data, status=401)
101
+
102
+ assert is_user_logged(extended_app) is False
103
+
104
+
105
+ def test_login_success_xhr(active_user, extended_app):
106
+ """Test xhr authentication."""
107
+ res = extended_app.get('/login')
108
+ post_data = {
109
+ 'email': DEFAULT_USER['email'],
110
+ 'password': DEFAULT_USER['password'],
111
+ 'csrf_token': res.form['csrf_token'].value
112
+ }
113
+ extended_app.get('/secret', status=302)
114
+ res = extended_app.post('/login?after=%2Fsecret',
115
+ post_data,
116
+ xhr=True,
117
+ expect_errors=True)
118
+
119
+ assert res.content_type == 'application/json'
120
+ assert res.json['status'] is True
121
+ assert 'after' in res.json
122
+ assert is_user_logged(extended_app) is True
123
+
124
+ # second call
125
+ res = extended_app.post('/login?after=%2Fsecret',
126
+ post_data,
127
+ xhr=True,
128
+ expect_errors=True)
129
+ assert res.json['status'] is True
130
+ assert res.json['msg'] == 'Already logged in!'
131
+
132
+
133
+ def test_default_login_forbidden(active_user, authable_app):
134
+ """After successful login, user should get 403 on secret page."""
135
+ authable_app.get('/secret', status=302)
136
+ forbidden = authable_app.get('/secret', xhr=True, status=403)
137
+ assert forbidden.json['status'] is False
138
+ authenticate(authable_app)
139
+ authable_app.get('/secret', status=403)
140
+ # go back to secret page
141
+ forbidden = authable_app.get('/secret', xhr=True, status=403)
142
+ # no permission, but logged.
143
+ assert forbidden.json['status'] is False
144
+ assert 'login_url' not in forbidden.json
145
+
146
+
147
+ def test_default_login_redirectaway(active_user, authable_app):
148
+ """After successful login, access to login page should result in redirect."""
149
+ authenticate(authable_app)
150
+ res = authable_app.get('/login', status=302)
151
+ assert res.location == 'http://localhost/'
Binary file