pyramid-fullauth 0.4.0__py3.3.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 (116) hide show
  1. EGG-INFO/PKG-INFO +184 -0
  2. EGG-INFO/SOURCES.txt +93 -0
  3. EGG-INFO/dependency_links.txt +1 -0
  4. EGG-INFO/not-zip-safe +1 -0
  5. EGG-INFO/requires.txt +13 -0
  6. EGG-INFO/top_level.txt +2 -0
  7. pyramid_fullauth/__init__.py +106 -0
  8. pyramid_fullauth/__pycache__/__init__.cpython-33.pyc +0 -0
  9. pyramid_fullauth/__pycache__/auth.cpython-33.pyc +0 -0
  10. pyramid_fullauth/__pycache__/events.cpython-33.pyc +0 -0
  11. pyramid_fullauth/__pycache__/exceptions.cpython-33.pyc +0 -0
  12. pyramid_fullauth/__pycache__/request.cpython-33.pyc +0 -0
  13. pyramid_fullauth/__pycache__/tools.cpython-33.pyc +0 -0
  14. pyramid_fullauth/auth.py +67 -0
  15. pyramid_fullauth/config/default.yaml +26 -0
  16. pyramid_fullauth/events.py +281 -0
  17. pyramid_fullauth/exceptions.py +47 -0
  18. pyramid_fullauth/models/__init__.py +190 -0
  19. pyramid_fullauth/models/__pycache__/__init__.cpython-33.pyc +0 -0
  20. pyramid_fullauth/models/extensions/__init__.py +39 -0
  21. pyramid_fullauth/models/extensions/__pycache__/__init__.cpython-33.pyc +0 -0
  22. pyramid_fullauth/models/mixins/__init__.py +9 -0
  23. pyramid_fullauth/models/mixins/__pycache__/__init__.cpython-33.pyc +0 -0
  24. pyramid_fullauth/models/mixins/__pycache__/email.cpython-33.pyc +0 -0
  25. pyramid_fullauth/models/mixins/__pycache__/password.cpython-33.pyc +0 -0
  26. pyramid_fullauth/models/mixins/email.py +128 -0
  27. pyramid_fullauth/models/mixins/password.py +141 -0
  28. pyramid_fullauth/request.py +70 -0
  29. pyramid_fullauth/resources/helpers/social.mako +17 -0
  30. pyramid_fullauth/resources/locale/pyramid_fullauth.pot +216 -0
  31. pyramid_fullauth/resources/templates/403.mako +11 -0
  32. pyramid_fullauth/resources/templates/_form.login.mako +44 -0
  33. pyramid_fullauth/resources/templates/_form.register.mako +47 -0
  34. pyramid_fullauth/resources/templates/_social.login.mako +17 -0
  35. pyramid_fullauth/resources/templates/activate.mako +14 -0
  36. pyramid_fullauth/resources/templates/email_change.mako +33 -0
  37. pyramid_fullauth/resources/templates/layout.mako +13 -0
  38. pyramid_fullauth/resources/templates/login.mako +17 -0
  39. pyramid_fullauth/resources/templates/register.mako +22 -0
  40. pyramid_fullauth/resources/templates/reset.mako +34 -0
  41. pyramid_fullauth/resources/templates/reset.proceed.mako +41 -0
  42. pyramid_fullauth/routing/__init__.py +5 -0
  43. pyramid_fullauth/routing/__pycache__/__init__.cpython-33.pyc +0 -0
  44. pyramid_fullauth/routing/__pycache__/predicates.cpython-33.pyc +0 -0
  45. pyramid_fullauth/routing/predicates.py +86 -0
  46. pyramid_fullauth/tools.py +69 -0
  47. pyramid_fullauth/views/__init__.py +15 -0
  48. pyramid_fullauth/views/__pycache__/__init__.cpython-33.pyc +0 -0
  49. pyramid_fullauth/views/__pycache__/social.cpython-33.pyc +0 -0
  50. pyramid_fullauth/views/basic/__init__.py +5 -0
  51. pyramid_fullauth/views/basic/__pycache__/__init__.cpython-33.pyc +0 -0
  52. pyramid_fullauth/views/basic/__pycache__/activate.cpython-33.pyc +0 -0
  53. pyramid_fullauth/views/basic/__pycache__/forbidden.cpython-33.pyc +0 -0
  54. pyramid_fullauth/views/basic/__pycache__/login.cpython-33.pyc +0 -0
  55. pyramid_fullauth/views/basic/__pycache__/logout.cpython-33.pyc +0 -0
  56. pyramid_fullauth/views/basic/__pycache__/register.cpython-33.pyc +0 -0
  57. pyramid_fullauth/views/basic/activate.py +44 -0
  58. pyramid_fullauth/views/basic/forbidden.py +46 -0
  59. pyramid_fullauth/views/basic/login.py +128 -0
  60. pyramid_fullauth/views/basic/logout.py +28 -0
  61. pyramid_fullauth/views/basic/profile/__init__.py +5 -0
  62. pyramid_fullauth/views/basic/profile/__pycache__/__init__.cpython-33.pyc +0 -0
  63. pyramid_fullauth/views/basic/profile/__pycache__/email.cpython-33.pyc +0 -0
  64. pyramid_fullauth/views/basic/profile/__pycache__/password.cpython-33.pyc +0 -0
  65. pyramid_fullauth/views/basic/profile/email.py +108 -0
  66. pyramid_fullauth/views/basic/profile/password.py +129 -0
  67. pyramid_fullauth/views/basic/register.py +111 -0
  68. pyramid_fullauth/views/social.py +221 -0
  69. tests/__init__.py +1 -0
  70. tests/__pycache__/__init__.cpython-33.pyc +0 -0
  71. tests/__pycache__/conftest.cpython-33.pyc +0 -0
  72. tests/__pycache__/tools.cpython-33.pyc +0 -0
  73. tests/conftest.py +201 -0
  74. tests/tools.py +54 -0
  75. tests/unit/__pycache__/test_default_settings.cpython-33.pyc +0 -0
  76. tests/unit/__pycache__/test_groupfinder.cpython-33.pyc +0 -0
  77. tests/unit/__pycache__/test_social_view.cpython-33.pyc +0 -0
  78. tests/unit/__pycache__/test_tools.cpython-33.pyc +0 -0
  79. tests/unit/__pycache__/test_user_active.cpython-33.pyc +0 -0
  80. tests/unit/__pycache__/test_user_admin.cpython-33.pyc +0 -0
  81. tests/unit/__pycache__/test_user_email.cpython-33.pyc +0 -0
  82. tests/unit/__pycache__/test_user_password.cpython-33.pyc +0 -0
  83. tests/unit/__pycache__/test_user_providers.cpython-33.pyc +0 -0
  84. tests/unit/__pycache__/test_user_repr.cpython-33.pyc +0 -0
  85. tests/unit/__pycache__/test_validators.cpython-33.pyc +0 -0
  86. tests/unit/test_default_settings.py +15 -0
  87. tests/unit/test_groupfinder.py +20 -0
  88. tests/unit/test_social_view.py +69 -0
  89. tests/unit/test_tools.py +24 -0
  90. tests/unit/test_user_active.py +31 -0
  91. tests/unit/test_user_admin.py +61 -0
  92. tests/unit/test_user_email.py +37 -0
  93. tests/unit/test_user_password.py +52 -0
  94. tests/unit/test_user_providers.py +24 -0
  95. tests/unit/test_user_repr.py +29 -0
  96. tests/unit/test_validators.py +44 -0
  97. tests/views/__init__.py +1 -0
  98. tests/views/__pycache__/__init__.cpython-33.pyc +0 -0
  99. tests/views/__pycache__/conftest.cpython-33.pyc +0 -0
  100. tests/views/__pycache__/test_activation.cpython-33.pyc +0 -0
  101. tests/views/__pycache__/test_email.cpython-33.pyc +0 -0
  102. tests/views/__pycache__/test_events.cpython-33.pyc +0 -0
  103. tests/views/__pycache__/test_login.cpython-33.pyc +0 -0
  104. tests/views/__pycache__/test_login_social.cpython-33.pyc +0 -0
  105. tests/views/__pycache__/test_logout.cpython-33.pyc +0 -0
  106. tests/views/__pycache__/test_register.cpython-33.pyc +0 -0
  107. tests/views/__pycache__/test_reset.cpython-33.pyc +0 -0
  108. tests/views/conftest.py +20 -0
  109. tests/views/test_activation.py +86 -0
  110. tests/views/test_email.py +175 -0
  111. tests/views/test_events.py +558 -0
  112. tests/views/test_login.py +172 -0
  113. tests/views/test_login_social.py +289 -0
  114. tests/views/test_logout.py +42 -0
  115. tests/views/test_register.py +138 -0
  116. tests/views/test_reset.py +105 -0
@@ -0,0 +1,172 @@
1
+ """Log in related test."""
2
+ import pytest
3
+ import transaction
4
+
5
+ from tests.tools import authenticate, is_user_logged, DEFAULT_USER
6
+
7
+
8
+ def test_login_view(default_app):
9
+ """Login view."""
10
+ res = default_app.get('/login')
11
+ assert res.form
12
+ assert 'email' in res.form.fields
13
+ assert 'password' in res.form.fields
14
+ assert 'remember' in res.form.fields
15
+
16
+
17
+ def test_login_view_secret(extended_app):
18
+ """Login:Form displayed after redirect from protected view."""
19
+ res = extended_app.get('/secret', status=302)
20
+ # check if redirect is correct
21
+ assert res.headers['Location'] == 'http://localhost/login?after=%2Fsecret'
22
+ # redirecting
23
+ res = extended_app.get(res.headers['Location'])
24
+ assert res.form
25
+ assert 'email' in res.form.fields
26
+
27
+
28
+ @pytest.mark.parametrize('email', (
29
+ DEFAULT_USER['email'].lower(),
30
+ DEFAULT_USER['email'].upper()
31
+ ))
32
+ def test_login_ok(active_user, extended_app, email):
33
+ """Actually log in test."""
34
+ res = extended_app.get('/secret', status=302)
35
+ res = res.follow()
36
+ res = extended_app.get('/login?after=%2Fsecret')
37
+
38
+ assert is_user_logged(extended_app) is False
39
+
40
+ res = authenticate(extended_app, email=email)
41
+ assert 'Max-Age=' not in str(res)
42
+
43
+ assert is_user_logged(extended_app) is True
44
+
45
+
46
+ def test_login_remember(active_user, extended_app):
47
+ """Login user and mark remember me field."""
48
+ res = extended_app.get('/login')
49
+ assert is_user_logged(extended_app) is False
50
+
51
+ res = authenticate(extended_app, remember=True)
52
+
53
+ assert is_user_logged(extended_app) is True
54
+ assert 'Max-Age=' in str(res)
55
+
56
+
57
+ def test_login_inactive(user, extended_app):
58
+ """Log in inactive user."""
59
+ assert is_user_logged(extended_app) is False
60
+
61
+ authenticate(extended_app)
62
+
63
+ assert is_user_logged(extended_app) is True
64
+
65
+
66
+ def test_login_redirects(active_user, extended_app):
67
+ """Login with redirects."""
68
+ res = extended_app.get('/secret', status=302)
69
+ assert res.status_code == 302
70
+ res = res.follow()
71
+ res.form['email'] = DEFAULT_USER['email']
72
+ res.form['password'] = DEFAULT_USER['password']
73
+ res = res.form.submit()
74
+
75
+ assert is_user_logged(extended_app) is True
76
+ assert res.status_code == 303
77
+
78
+
79
+ @pytest.mark.parametrize('user_kwargs', (
80
+ {'password': 'wrong password'},
81
+ {'email': 'not@registered.py'}
82
+ ))
83
+ def test_login_wrong(active_user, user_kwargs, extended_app):
84
+ """Use wrong password during authentication."""
85
+ res = authenticate(extended_app, response_code=200, **user_kwargs)
86
+
87
+ assert 'Error! Wrong e-mail or password.' in res
88
+ assert res
89
+
90
+
91
+ @pytest.mark.parametrize('post_data', (
92
+ {
93
+ 'email': DEFAULT_USER['email'],
94
+ 'password': DEFAULT_USER['password'],
95
+ }, {
96
+ 'email': DEFAULT_USER['email'],
97
+ 'password': DEFAULT_USER['password'],
98
+ 'csrf_token': '8934798289723789347892397832789432789'
99
+ }
100
+
101
+ ))
102
+ def test_login_csrf_error(active_user, extended_app, post_data):
103
+ """Try to log in with erroneus csrf token."""
104
+ res = extended_app.get('/login', status=200)
105
+ assert res
106
+ res = extended_app.post('/login', post_data, status=401)
107
+
108
+ assert is_user_logged(extended_app) is False
109
+
110
+
111
+ def test_login_success_xhr(active_user, extended_app):
112
+ """Test xhr authentication."""
113
+ res = extended_app.get('/login')
114
+ post_data = {
115
+ 'email': DEFAULT_USER['email'],
116
+ 'password': DEFAULT_USER['password'],
117
+ 'csrf_token': res.form['csrf_token'].value
118
+ }
119
+ extended_app.get('/secret', status=302)
120
+ res = extended_app.post('/login?after=%2Fsecret',
121
+ post_data,
122
+ xhr=True,
123
+ expect_errors=True)
124
+
125
+ assert res.content_type == 'application/json'
126
+ assert res.json['status'] is True
127
+ assert 'after' in res.json
128
+ assert is_user_logged(extended_app) is True
129
+
130
+ # second call
131
+ res = extended_app.post('/login?after=%2Fsecret',
132
+ post_data,
133
+ xhr=True,
134
+ expect_errors=True)
135
+ assert res.json['status'] is True
136
+ assert res.json['msg'] == 'Already logged in!'
137
+
138
+
139
+ def test_default_login_forbidden(active_user, authable_app):
140
+ """After successful login, user should get 403 on secret page."""
141
+ authable_app.get('/secret', status=302)
142
+ forbidden = authable_app.get('/secret', xhr=True, status=403)
143
+ assert forbidden.json['status'] is False
144
+ authenticate(authable_app)
145
+ authable_app.get('/secret', status=403)
146
+ # go back to secret page
147
+ forbidden = authable_app.get('/secret', xhr=True, status=403)
148
+ # no permission, but logged.
149
+ assert forbidden.json['status'] is False
150
+ assert 'login_url' not in forbidden.json
151
+
152
+
153
+ def test_default_login_redirectaway(active_user, authable_app):
154
+ """After successful login, access to login page should result in redirect."""
155
+ authenticate(authable_app)
156
+ res = authable_app.get('/login', status=303)
157
+ assert res.location == 'http://localhost/'
158
+
159
+
160
+ def test_login_invalid_cookie(db_session, active_user, extended_app):
161
+ """Test access login page by deleted user."""
162
+ res = authenticate(extended_app)
163
+ assert 'Max-Age=' not in str(res)
164
+
165
+ assert is_user_logged(extended_app) is True
166
+
167
+ db_session.delete(active_user)
168
+ transaction.commit()
169
+
170
+ # will rise Attribute error
171
+ res = extended_app.get('/login')
172
+ assert res.status_code == 200, "Should stay since user is no longer valid!"
@@ -0,0 +1,289 @@
1
+ """Social network login test."""
2
+ import transaction
3
+ from pyramid import testing
4
+ from pyramid.compat import text_type
5
+ from mock import MagicMock
6
+
7
+ try:
8
+ from velruse import AuthenticationComplete
9
+ from pyramid_fullauth.views.social import SocialLoginViews
10
+ except ImportError:
11
+ # tests will be skipped anyway
12
+ pass
13
+
14
+ from pyramid_fullauth.models import User
15
+
16
+ from tests.conftest import py2only
17
+ from tests.views.conftest import mock_translate
18
+
19
+
20
+ @py2only
21
+ def test_social_login_link(social_app):
22
+ """Login:Form displayed social form."""
23
+ res = social_app.get('/login')
24
+ assert ('Connect with facebook</a>' in res.body.decode('unicode_escape'))
25
+
26
+
27
+ @py2only
28
+ def test_social_click_link(social_app):
29
+ """Click social login link."""
30
+ res = social_app.get('/login/facebook?scope=email%2Coffline_access', status=302)
31
+ assert (res.headers['Location'].startswith(
32
+ 'https://www.facebook.com/dialog/oauth/?scope=email%2Coffline_access&state='))
33
+
34
+
35
+ @py2only
36
+ def test_social_login_register(social_config, db_session):
37
+ """Register fresh user and logs him in."""
38
+ profile = {
39
+ 'accounts': [{'domain': text_type('facebook.com'), 'userid': text_type('2343')}],
40
+ 'displayName': text_type('teddy'),
41
+ 'verifiedEmail': text_type('we@po.pl'),
42
+ 'preferredUsername': text_type('teddy'),
43
+ 'emails': [{'value': text_type('aasd@bwwqwe.pl')}],
44
+ 'name': text_type('ted')
45
+ }
46
+ credentials = {'oauthAccessToken': '7897048593434'}
47
+ provider_name = text_type('facebook')
48
+ provider_type = text_type('facebook')
49
+ request = testing.DummyRequest()
50
+ request.user = None
51
+ request.registry = social_config.registry
52
+ request.remote_addr = text_type('127.0.0.123')
53
+ request.context = AuthenticationComplete(profile, credentials, provider_name, provider_type)
54
+
55
+ request.login_perform = MagicMock(name='login_perform')
56
+ request.login_perform.return_value = {'status': True}
57
+ view = SocialLoginViews(request)
58
+ out = view()
59
+ assert out == {'status': True}
60
+ transaction.commit()
61
+
62
+ # read first new account
63
+ user = db_session.query(User).one()
64
+ assert user.is_active
65
+ assert user.provider_id('facebook') == profile['accounts'][0]['userid']
66
+
67
+
68
+ @py2only
69
+ def test_login_different_social_account(social_config, db_session, facebook_user):
70
+ """
71
+ Login with different social account than connected from same provider.
72
+
73
+ System should let user in, but not change connection.
74
+ """
75
+ # profile mock response
76
+ profile = {
77
+ # facebook user id is different than user's
78
+ 'accounts': [{'domain': text_type('facebook.com'), 'userid': text_type('2343')}],
79
+ 'displayName': text_type('teddy'),
80
+ 'verifiedEmail': facebook_user.email,
81
+ 'preferredUsername': text_type('teddy'),
82
+ 'emails': [{'value': text_type('aasd@bwwqwe.pl')}],
83
+ 'name': text_type('ted')
84
+ }
85
+ request = testing.DummyRequest()
86
+ request.user = None
87
+ request.registry = social_config.registry
88
+ request.remote_addr = text_type('127.0.0.123')
89
+ request.context = AuthenticationComplete(
90
+ profile,
91
+ {'oauthAccessToken': '7897048593434'},
92
+ text_type('facebook'),
93
+ text_type('facebook'))
94
+
95
+ request.login_perform = MagicMock(name='login_perform')
96
+ request.login_perform.return_value = {'status': True}
97
+ view = SocialLoginViews(request)
98
+ out = view()
99
+ # user should be authenticated recognized by email!
100
+ assert out['status'] is True
101
+ assert facebook_user.provider_id('facebook') is not profile['accounts'][0]['userid']
102
+
103
+
104
+ @py2only
105
+ def test_login_social_connect(social_config, active_user, db_session):
106
+ """Connect and logs user in."""
107
+ user = db_session.merge(active_user)
108
+
109
+ profile = {
110
+ 'accounts': [{'domain': text_type('facebook.com'), 'userid': text_type('2343')}],
111
+ 'displayName': text_type('teddy'),
112
+ 'preferredUsername': text_type('teddy'),
113
+ 'emails': [{'value': user.email}],
114
+ 'name': text_type('ted')
115
+ }
116
+ credentials = {'oauthAccessToken': '7897048593434'}
117
+ provider_name = text_type('facebook')
118
+ provider_type = text_type('facebook')
119
+ user = None
120
+ request = testing.DummyRequest()
121
+ request.user = user
122
+ request.registry = social_config.registry
123
+ request.remote_addr = text_type('127.0.0.123')
124
+ request.context = AuthenticationComplete(profile, credentials, provider_name, provider_type)
125
+
126
+ request.login_perform = MagicMock(name='login_perform')
127
+ request.login_perform.return_value = {'status': True}
128
+ view = SocialLoginViews(request)
129
+ out = view()
130
+ assert out == {'status': True}
131
+
132
+
133
+ @py2only
134
+ def test_logged_social_connect_account(social_config, active_user, db_session):
135
+ """Connect facebook account to logged in user."""
136
+ user = db_session.merge(active_user)
137
+
138
+ profile = {
139
+ 'accounts': [{'domain': text_type('facebook.com'), 'userid': text_type('2343')}],
140
+ 'displayName': text_type('teddy'),
141
+ 'preferredUsername': text_type('teddy'),
142
+ 'emails': [{'value': text_type('aasd@basd.pl')}],
143
+ 'name': text_type('ted')
144
+ }
145
+ credentials = {'oauthAccessToken': '7897048593434'}
146
+ provider_name = text_type('facebook')
147
+ provider_type = text_type('facebook')
148
+ request = testing.DummyRequest()
149
+ request.user = user
150
+ request.registry = social_config.registry
151
+ request.remote_addr = text_type('127.0.0.123')
152
+ request.context = AuthenticationComplete(profile, credentials, provider_name, provider_type)
153
+ request._ = mock_translate
154
+
155
+ request.login_perform = MagicMock(name='login_perform')
156
+ request.login_perform.return_value = {'status': True}
157
+ view = SocialLoginViews(request)
158
+ out = view()
159
+ assert out['status'] is True
160
+
161
+ transaction.commit()
162
+ user = db_session.merge(user)
163
+ assert user.provider_id('facebook') == profile['accounts'][0]['userid']
164
+
165
+
166
+ @py2only
167
+ def test_logged_social_connect_self(social_config, facebook_user, db_session):
168
+ """Connect self."""
169
+ user = db_session.merge(facebook_user)
170
+
171
+ profile = {
172
+ 'accounts': [{'domain': text_type('facebook.com'), 'userid': user.provider_id('facebook')}],
173
+ 'displayName':
174
+ text_type('teddy'),
175
+ 'preferredUsername':
176
+ text_type('teddy'),
177
+ 'emails':
178
+ [{'value': user.email}],
179
+ 'name':
180
+ text_type('ted')
181
+ }
182
+ credentials = {'oauthAccessToken':
183
+ '7897048593434'}
184
+ provider_name = text_type('facebook')
185
+ provider_type = text_type('facebook')
186
+ request = testing.DummyRequest()
187
+ request.user = user
188
+ request.registry = social_config.registry
189
+ request.remote_addr = text_type('127.0.0.123')
190
+ request.context = AuthenticationComplete(profile, credentials, provider_name, provider_type)
191
+ request._ = mock_translate
192
+
193
+ request.login_perform = MagicMock(name='login_perform')
194
+ request.login_perform.return_value = {'status': True}
195
+ view = SocialLoginViews(request)
196
+ out = view()
197
+ assert out['status'] is True
198
+
199
+ user = db_session.merge(facebook_user)
200
+ assert user.provider_id('facebook') == profile['accounts'][0]['userid']
201
+
202
+
203
+ @py2only
204
+ def test_logged_social_connect_second_account(social_config, facebook_user, db_session):
205
+ """Connect second facebook account to logged in user."""
206
+ user = db_session.merge(facebook_user)
207
+
208
+ # mock request
209
+ profile = {
210
+ 'accounts':
211
+ [{'domain': text_type('facebook.com'), 'userid': text_type('2343')}],
212
+ 'displayName':
213
+ text_type('teddy'),
214
+ 'preferredUsername':
215
+ text_type('teddy'),
216
+ 'emails':
217
+ [{'value': text_type('aasd@basd.pl')}],
218
+ 'name':
219
+ text_type('ted')
220
+ }
221
+ credentials = {'oauthAccessToken':
222
+ '7897048593434'}
223
+ provider_name = text_type('facebook')
224
+ provider_type = text_type('facebook')
225
+ request = testing.DummyRequest()
226
+ request.user = user
227
+ request.registry = social_config.registry
228
+ request.remote_addr = text_type('127.0.0.123')
229
+ request.context = AuthenticationComplete(profile, credentials, provider_name, provider_type)
230
+ request._ = mock_translate
231
+
232
+ request.login_perform = MagicMock(name='login_perform')
233
+ request.login_perform.return_value = {'status': True}
234
+ view = SocialLoginViews(request)
235
+ out = view()
236
+ # status should be false
237
+ assert out['status'] is False
238
+ assert out['msg'] == 'Your account is already connected to other ${provider} account.'
239
+ assert user.provider_id('facebook') is not profile['accounts'][0]['userid']
240
+
241
+
242
+ @py2only
243
+ def test_logged_social_connect_used_account(social_config, facebook_user, db_session):
244
+ """Try to connect facebook account to logged in user used by other user."""
245
+ # this user will be logged and trying to connect facebook's user account.
246
+ fresh_user = User(
247
+ email=text_type('new@user.pl'),
248
+ password=text_type('somepassword'),
249
+ address_ip=text_type('127.0.0.1')
250
+ )
251
+ db_session.add(fresh_user)
252
+ transaction.commit()
253
+ user = db_session.merge(facebook_user)
254
+ fresh_user = db_session.merge(fresh_user)
255
+
256
+ # mock request
257
+ profile = {
258
+ 'accounts':
259
+ [{'domain': text_type('facebook.com'), 'userid': user.provider_id('facebook')}],
260
+ 'displayName':
261
+ text_type('teddy'),
262
+ 'preferredUsername':
263
+ text_type('teddy'),
264
+ 'emails':
265
+ [{'value': text_type('aasd@basd.pl')}],
266
+ 'name':
267
+ text_type('ted')
268
+ }
269
+ credentials = {'oauthAccessToken': '7897048593434'}
270
+ provider_name = text_type('facebook')
271
+ provider_type = text_type('facebook')
272
+ request = testing.DummyRequest()
273
+ request.user = fresh_user
274
+ request.registry = social_config.registry
275
+ request.remote_addr = text_type('127.0.0.123')
276
+ request.context = AuthenticationComplete(profile, credentials, provider_name, provider_type)
277
+ request._ = mock_translate
278
+
279
+ request.login_perform = MagicMock(name='login_perform')
280
+ request.login_perform.return_value = {'status': True}
281
+ # call!
282
+ view = SocialLoginViews(request)
283
+ out = view()
284
+ # status should be false
285
+ assert out['status'] is False
286
+ assert out['msg'] == 'This ${provider} account is already connected with other account.'
287
+ transaction.begin()
288
+ fresh_user = db_session.merge(fresh_user)
289
+ assert fresh_user.provider_id('facebook') is None
@@ -0,0 +1,42 @@
1
+ """Logout related tests."""
2
+ import time
3
+
4
+ from tests.tools import authenticate, is_user_logged
5
+
6
+
7
+ def test_logout(active_user, extended_app):
8
+ """Check logout action."""
9
+ authenticate(extended_app)
10
+ assert is_user_logged(extended_app) is True
11
+
12
+ extended_app.get('/logout', status=303)
13
+ assert is_user_logged(extended_app) is False
14
+ res = extended_app.get('/secret', status=302)
15
+ assert res.status_code == 302
16
+
17
+
18
+ def test_logout_login(active_user, extended_config, extended_app):
19
+ """Check logout action with configured logout redirection."""
20
+ extended_config.registry['config'].fullauth.redirects.logout = 'login'
21
+ authenticate(extended_app)
22
+ assert is_user_logged(extended_app) is True
23
+
24
+ res = extended_app.get('/logout', status=303)
25
+ assert is_user_logged(extended_app) is False
26
+ # redirection should be done to login page.
27
+ assert '/login' in res.location
28
+ res = extended_app.get('/secret', status=302)
29
+ assert res.status_code == 302
30
+
31
+
32
+ def test_automatic_logout(active_user, short_config, short_app):
33
+ """Test automatic logout."""
34
+ timeout = short_config.registry['config']['fullauth']['AuthTkt']['timeout'] + 1
35
+
36
+ authenticate(short_app)
37
+ # Simulating inactivity
38
+ time.sleep(timeout)
39
+ res = short_app.get('/email/change')
40
+ assert res.headers['Location'] == 'http://localhost/login?after=%2Femail%2Fchange'
41
+ res = res.follow()
42
+ assert res.form
@@ -0,0 +1,138 @@
1
+ """Registration related tests."""
2
+ try:
3
+ from HTMLParser import HTMLParser
4
+ except ImportError:
5
+ from html.parser import HTMLParser
6
+
7
+ import pytest
8
+ import transaction
9
+ from pyramid.compat import text_type
10
+ from sqlalchemy.orm.exc import NoResultFound
11
+
12
+ from pyramid_fullauth.models import User
13
+ from tests.tools import DEFAULT_USER
14
+
15
+
16
+ def test_register_view(default_app):
17
+ """Display register form."""
18
+ res = default_app.get('/register')
19
+ assert res.form
20
+
21
+
22
+ @pytest.mark.parametrize('email, password', (
23
+ # casual
24
+ (DEFAULT_USER['email'], DEFAULT_USER['password']),
25
+ # loooong password
26
+ (DEFAULT_USER['email'], DEFAULT_USER['password'] * 10000),
27
+ ))
28
+ def test_register_success(db_session, default_app, email, password):
29
+ """Register user successfully."""
30
+ assert db_session.query(User).count() == 0
31
+
32
+ res = default_app.get('/register')
33
+ res.form['email'] = email
34
+ res.form['password'] = password
35
+ res.form['confirm_password'] = password
36
+ res = res.form.submit(extra_environ={'REMOTE_ADDR': '0.0.0.0'})
37
+ transaction.commit()
38
+
39
+ user = db_session.query(User).filter(User.email == email).one()
40
+
41
+ # User should not have active account at this moment
42
+ assert user.is_active is not None
43
+ assert user.check_password(password)
44
+
45
+
46
+ def test_register_user_exists(db_session, user, default_app):
47
+ """Trying to register existing user."""
48
+ res = default_app.get('/register')
49
+ res.form['email'] = DEFAULT_USER['email']
50
+ res.form['password'] = DEFAULT_USER['password']
51
+ res.form['confirm_password'] = DEFAULT_USER['password']
52
+ res = res.form.submit(extra_environ={'REMOTE_ADDR': '0.0.0.0'})
53
+ transaction.commit()
54
+
55
+ assert 'User with given e-mail already exists' in res.body.decode('unicode_escape')
56
+
57
+
58
+ @pytest.mark.parametrize('email, password, confirm_password, error', (
59
+ # no email
60
+ (None, DEFAULT_USER['password'], DEFAULT_USER['password'],
61
+ 'E-mail is empty'),
62
+ # empty email
63
+ ('', DEFAULT_USER['password'], DEFAULT_USER['password'],
64
+ 'E-mail is empty'),
65
+ # not matching passwords
66
+ (DEFAULT_USER['email'], DEFAULT_USER['password'], DEFAULT_USER['password'] + 'Typo',
67
+ 'Passwords don\'t match'),
68
+ # long, incorect email
69
+ (text_type('email') * 100 + text_type('@wap.pl'), DEFAULT_USER['password'], DEFAULT_USER['password'],
70
+ 'Incorrect e-mail format'),
71
+ # too short password
72
+ (DEFAULT_USER['email'], '12', '12',
73
+ 'Password is too short'),
74
+ # empty password
75
+ (DEFAULT_USER['email'], '', '', 'Please enter your password'),
76
+ ))
77
+ def test_register_error(db_session, default_app, email, password, confirm_password, error):
78
+ """Error in registration process."""
79
+ assert db_session.query(User).count() == 0
80
+
81
+ res = default_app.get('/register')
82
+ if email is not None:
83
+ res.form['email'] = email
84
+ res.form['password'] = password
85
+ res.form['confirm_password'] = confirm_password
86
+ res = res.form.submit(extra_environ={'REMOTE_ADDR': '0.0.0.0'})
87
+ transaction.commit()
88
+
89
+ assert error in HTMLParser().unescape(res.body.decode('unicode_escape'))
90
+ assert db_session.query(User).count() == 0
91
+
92
+
93
+ def test_register_wrong_csrf(db_session, default_app):
94
+ """CSRF error during registration."""
95
+ assert db_session.query(User).count() == 0
96
+
97
+ res = default_app.get('/register')
98
+ res.form['email'] = DEFAULT_USER['email']
99
+ res.form['password'] = DEFAULT_USER['password']
100
+ res.form['confirm_password'] = DEFAULT_USER['password']
101
+ res.form['csrf_token'] = 'wrong_token'
102
+ res = res.form.submit(extra_environ={'REMOTE_ADDR': '0.0.0.0'},
103
+ status=401)
104
+ transaction.commit()
105
+
106
+ assert db_session.query(User).count() == 0
107
+
108
+
109
+ def test_no_pass_confirm(db_session, nopassconfirm_app):
110
+ """Register without password confirm option."""
111
+ assert db_session.query(User).count() == 0
112
+
113
+ res = nopassconfirm_app.get('/register')
114
+ res.form['email'] = DEFAULT_USER['email']
115
+ res.form['password'] = DEFAULT_USER['password']
116
+ res = res.form.submit(extra_environ={'REMOTE_ADDR': '0.0.0.0'})
117
+
118
+ assert 'Passwords don\'t match!' not in HTMLParser().unescape(res.body.decode('unicode_escape'))
119
+ transaction.commit()
120
+
121
+ user = db_session.query(User).filter(User.email == DEFAULT_USER['email']).one()
122
+
123
+ # User should not have active account at this moment
124
+ assert user.is_active is not None
125
+ assert user.check_password(DEFAULT_USER['password'])
126
+
127
+
128
+ def test_register_action_no_password_required(db_session, nopassregister_app):
129
+ """Register without password required."""
130
+ with pytest.raises(NoResultFound):
131
+ db_session.query(User).filter(User.email == DEFAULT_USER['email']).one()
132
+
133
+ res = nopassregister_app.get('/register')
134
+ res.form['email'] = DEFAULT_USER['email']
135
+ res = res.form.submit(extra_environ={'REMOTE_ADDR': '0.0.0.0'})
136
+ transaction.commit()
137
+
138
+ db_session.query(User).filter(User.email == DEFAULT_USER['email']).one()