pyramid-fullauth 0.4.0__py3.4.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.
- EGG-INFO/PKG-INFO +184 -0
- EGG-INFO/SOURCES.txt +93 -0
- EGG-INFO/dependency_links.txt +1 -0
- EGG-INFO/not-zip-safe +1 -0
- EGG-INFO/requires.txt +13 -0
- EGG-INFO/top_level.txt +2 -0
- pyramid_fullauth/__init__.py +106 -0
- pyramid_fullauth/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/auth.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/events.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/exceptions.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/request.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/tools.cpython-34.pyc +0 -0
- pyramid_fullauth/auth.py +67 -0
- pyramid_fullauth/config/default.yaml +26 -0
- pyramid_fullauth/events.py +281 -0
- pyramid_fullauth/exceptions.py +47 -0
- pyramid_fullauth/models/__init__.py +190 -0
- pyramid_fullauth/models/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/models/extensions/__init__.py +39 -0
- pyramid_fullauth/models/extensions/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/models/mixins/__init__.py +9 -0
- pyramid_fullauth/models/mixins/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/models/mixins/__pycache__/email.cpython-34.pyc +0 -0
- pyramid_fullauth/models/mixins/__pycache__/password.cpython-34.pyc +0 -0
- pyramid_fullauth/models/mixins/email.py +128 -0
- pyramid_fullauth/models/mixins/password.py +141 -0
- pyramid_fullauth/request.py +70 -0
- pyramid_fullauth/resources/helpers/social.mako +17 -0
- pyramid_fullauth/resources/locale/pyramid_fullauth.pot +216 -0
- pyramid_fullauth/resources/templates/403.mako +11 -0
- pyramid_fullauth/resources/templates/_form.login.mako +44 -0
- pyramid_fullauth/resources/templates/_form.register.mako +47 -0
- pyramid_fullauth/resources/templates/_social.login.mako +17 -0
- pyramid_fullauth/resources/templates/activate.mako +14 -0
- pyramid_fullauth/resources/templates/email_change.mako +33 -0
- pyramid_fullauth/resources/templates/layout.mako +13 -0
- pyramid_fullauth/resources/templates/login.mako +17 -0
- pyramid_fullauth/resources/templates/register.mako +22 -0
- pyramid_fullauth/resources/templates/reset.mako +34 -0
- pyramid_fullauth/resources/templates/reset.proceed.mako +41 -0
- pyramid_fullauth/routing/__init__.py +5 -0
- pyramid_fullauth/routing/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/routing/__pycache__/predicates.cpython-34.pyc +0 -0
- pyramid_fullauth/routing/predicates.py +86 -0
- pyramid_fullauth/tools.py +69 -0
- pyramid_fullauth/views/__init__.py +15 -0
- pyramid_fullauth/views/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/views/__pycache__/social.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__init__.py +5 -0
- pyramid_fullauth/views/basic/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/activate.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/forbidden.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/login.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/logout.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/register.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/activate.py +44 -0
- pyramid_fullauth/views/basic/forbidden.py +46 -0
- pyramid_fullauth/views/basic/login.py +128 -0
- pyramid_fullauth/views/basic/logout.py +28 -0
- pyramid_fullauth/views/basic/profile/__init__.py +5 -0
- pyramid_fullauth/views/basic/profile/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/profile/__pycache__/email.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/profile/__pycache__/password.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/profile/email.py +108 -0
- pyramid_fullauth/views/basic/profile/password.py +129 -0
- pyramid_fullauth/views/basic/register.py +111 -0
- pyramid_fullauth/views/social.py +221 -0
- tests/__init__.py +1 -0
- tests/__pycache__/__init__.cpython-34.pyc +0 -0
- tests/__pycache__/conftest.cpython-34.pyc +0 -0
- tests/__pycache__/tools.cpython-34.pyc +0 -0
- tests/conftest.py +201 -0
- tests/tools.py +54 -0
- tests/unit/__pycache__/test_default_settings.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_groupfinder.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_social_view.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_tools.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_active.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_admin.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_email.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_password.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_providers.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_repr.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_validators.cpython-34.pyc +0 -0
- tests/unit/test_default_settings.py +15 -0
- tests/unit/test_groupfinder.py +20 -0
- tests/unit/test_social_view.py +69 -0
- tests/unit/test_tools.py +24 -0
- tests/unit/test_user_active.py +31 -0
- tests/unit/test_user_admin.py +61 -0
- tests/unit/test_user_email.py +37 -0
- tests/unit/test_user_password.py +52 -0
- tests/unit/test_user_providers.py +24 -0
- tests/unit/test_user_repr.py +29 -0
- tests/unit/test_validators.py +44 -0
- tests/views/__init__.py +1 -0
- tests/views/__pycache__/__init__.cpython-34.pyc +0 -0
- tests/views/__pycache__/conftest.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_activation.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_email.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_events.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_login.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_login_social.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_logout.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_register.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_reset.cpython-34.pyc +0 -0
- tests/views/conftest.py +20 -0
- tests/views/test_activation.py +86 -0
- tests/views/test_email.py +175 -0
- tests/views/test_events.py +558 -0
- tests/views/test_login.py +172 -0
- tests/views/test_login_social.py +289 -0
- tests/views/test_logout.py +42 -0
- tests/views/test_register.py +138 -0
- tests/views/test_reset.py +105 -0
tests/conftest.py
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""Most of the fixtures needed."""
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from mock import Mock
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
import transaction
|
|
8
|
+
from sqlalchemy import create_engine
|
|
9
|
+
from sqlalchemy.orm import scoped_session, sessionmaker
|
|
10
|
+
from sqlalchemy.pool import NullPool
|
|
11
|
+
from zope.sqlalchemy import ZopeTransactionExtension
|
|
12
|
+
|
|
13
|
+
from pyramid.compat import text_type
|
|
14
|
+
from pytest_pyramid import factories
|
|
15
|
+
import pyramid_basemodel
|
|
16
|
+
|
|
17
|
+
py2only = pytest.mark.skipif(
|
|
18
|
+
sys.version_info.major > 2,
|
|
19
|
+
reason='oauth2-python and velruse does not support python3')
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture
|
|
23
|
+
def web_request():
|
|
24
|
+
"""Mocked web request for views testing."""
|
|
25
|
+
request = Mock()
|
|
26
|
+
config = Mock()
|
|
27
|
+
config.configure_mock(
|
|
28
|
+
**{'fullauth.register.password':
|
|
29
|
+
{'length_min': 8, 'confirm': True},
|
|
30
|
+
'POST': {'confirm_password': '987654321'}
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def _(message, *args, **kwargs):
|
|
35
|
+
return message
|
|
36
|
+
request._ = Mock(side_effect=_)
|
|
37
|
+
request.configure_mock(
|
|
38
|
+
**{'registry': {'config': config}}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
return request
|
|
42
|
+
|
|
43
|
+
if sys.version_info.major == 2:
|
|
44
|
+
databases = ['sqlite', 'mysql', 'postgresql']
|
|
45
|
+
else:
|
|
46
|
+
databases = ['sqlite']
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@pytest.fixture(scope='function', params=databases)
|
|
50
|
+
def db_session(request):
|
|
51
|
+
"""SQLAlchemy session."""
|
|
52
|
+
from pyramid_fullauth.models import Base
|
|
53
|
+
|
|
54
|
+
if request.param == 'sqlite':
|
|
55
|
+
connection = 'sqlite:///fullauth.sqlite'
|
|
56
|
+
elif request.param == 'mysql':
|
|
57
|
+
request.getfuncargvalue('mysqldb') # takes care of creating database
|
|
58
|
+
connection = 'mysql+mysqldb://root:@127.0.0.1:3307/tests?charset=utf8'
|
|
59
|
+
elif request.param == 'postgresql':
|
|
60
|
+
request.getfuncargvalue('postgresql') # takes care of creating database
|
|
61
|
+
connection = 'postgresql+psycopg2://postgres:@127.0.0.1:5433/tests'
|
|
62
|
+
|
|
63
|
+
engine = create_engine(connection, echo=False, poolclass=NullPool)
|
|
64
|
+
pyramid_basemodel.Session = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
|
|
65
|
+
pyramid_basemodel.bind_engine(engine, pyramid_basemodel.Session, should_drop=True)
|
|
66
|
+
|
|
67
|
+
def destroy():
|
|
68
|
+
transaction.commit()
|
|
69
|
+
Base.metadata.drop_all(engine)
|
|
70
|
+
|
|
71
|
+
request.addfinalizer(destroy)
|
|
72
|
+
|
|
73
|
+
return pyramid_basemodel.Session
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@pytest.fixture
|
|
77
|
+
def user(db_session):
|
|
78
|
+
"""Default user."""
|
|
79
|
+
from pyramid_fullauth.models import User
|
|
80
|
+
from tests.tools import DEFAULT_USER
|
|
81
|
+
user = User(**DEFAULT_USER)
|
|
82
|
+
db_session.add(user)
|
|
83
|
+
transaction.commit()
|
|
84
|
+
return user
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@pytest.fixture
|
|
88
|
+
def active_user(user, db_session):
|
|
89
|
+
"""Active user."""
|
|
90
|
+
user = db_session.merge(user)
|
|
91
|
+
user.is_active = True
|
|
92
|
+
transaction.commit()
|
|
93
|
+
return user
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@pytest.fixture(params=[
|
|
97
|
+
# (an @ character must separate the local and domain parts)
|
|
98
|
+
text_type('Abc.example.com'),
|
|
99
|
+
# (character dot(.) is last in local part)
|
|
100
|
+
text_type('Abc.@example.com'),
|
|
101
|
+
# (character dot(.) is double)
|
|
102
|
+
text_type('Abc..123@example.com'),
|
|
103
|
+
# (only one @ is allowed outside quotation marks)
|
|
104
|
+
text_type('A@b@c@example.com'),
|
|
105
|
+
# (none of the special characters in this local part is allowed outside quotation marks)
|
|
106
|
+
text_type('a"b(c)d,e:f;g<h>i[j\k]l@example.com'),
|
|
107
|
+
# (quoted strings must be dot separated, or the only element making up the local-part)
|
|
108
|
+
text_type('just"not"right@example.com'),
|
|
109
|
+
# (spaces, quotes, and backslashes may only exist when within quoted strings and preceded by a backslash)
|
|
110
|
+
text_type('this is"not\allowed@example.com'),
|
|
111
|
+
# (even if escaped (preceded by a backslash), spaces, quotes, and backslashes must still be contained by quotes)
|
|
112
|
+
text_type('this\ still\"not\\allowed@example.com'),
|
|
113
|
+
text_type('bad-mail'),
|
|
114
|
+
])
|
|
115
|
+
def invalid_email(request):
|
|
116
|
+
"""Parametrized fixture with all the incorrect emails."""
|
|
117
|
+
return request.param
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
default_config = factories.pyramid_config({
|
|
121
|
+
'pyramid.includes': [
|
|
122
|
+
'pyramid_tm',
|
|
123
|
+
'pyramid_fullauth'
|
|
124
|
+
]
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
extended_config = factories.pyramid_config({
|
|
129
|
+
'pyramid.includes': [
|
|
130
|
+
'pyramid_tm',
|
|
131
|
+
'pyramid_fullauth',
|
|
132
|
+
'tests.tools.include_views'
|
|
133
|
+
]
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
short_config = factories.pyramid_config({
|
|
138
|
+
'yml.location': 'tests:config/short_memory.yaml',
|
|
139
|
+
'pyramid.includes': [
|
|
140
|
+
'pyramid_tm',
|
|
141
|
+
'tzf.pyramid_yml',
|
|
142
|
+
'pyramid_fullauth',
|
|
143
|
+
'tests.tools.include_views'
|
|
144
|
+
]
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
social_config = factories.pyramid_config({
|
|
149
|
+
'yml.location': 'tests:config/social.yaml',
|
|
150
|
+
'pyramid.includes': [
|
|
151
|
+
'pyramid_tm',
|
|
152
|
+
'tzf.pyramid_yml',
|
|
153
|
+
'pyramid_fullauth',
|
|
154
|
+
'tests.tools.include_views'
|
|
155
|
+
]
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
authable_config = factories.pyramid_config({
|
|
160
|
+
'yml.location': 'tests:config',
|
|
161
|
+
'env': 'login',
|
|
162
|
+
'pyramid.includes': [
|
|
163
|
+
'pyramid_tm',
|
|
164
|
+
'tzf.pyramid_yml',
|
|
165
|
+
'pyramid_fullauth',
|
|
166
|
+
'tests.tools.include_views'
|
|
167
|
+
]
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
nopassconfirm_config = factories.pyramid_config({
|
|
172
|
+
'yml.location': 'tests:config/no_password_confirm.yaml',
|
|
173
|
+
'env': 'login',
|
|
174
|
+
'pyramid.includes': [
|
|
175
|
+
'pyramid_tm',
|
|
176
|
+
'tzf.pyramid_yml',
|
|
177
|
+
'pyramid_fullauth',
|
|
178
|
+
'tests.tools.include_views'
|
|
179
|
+
]
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
nopassregister_config = factories.pyramid_config({
|
|
184
|
+
'yml.location': 'tests:config/no_password_register.yaml',
|
|
185
|
+
'env': 'login',
|
|
186
|
+
'pyramid.includes': [
|
|
187
|
+
'pyramid_tm',
|
|
188
|
+
'tzf.pyramid_yml',
|
|
189
|
+
'pyramid_fullauth',
|
|
190
|
+
'tests.tools.include_views'
|
|
191
|
+
]
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
default_app = factories.pyramid_app('default_config')
|
|
196
|
+
extended_app = factories.pyramid_app('extended_config')
|
|
197
|
+
short_app = factories.pyramid_app('short_config')
|
|
198
|
+
social_app = factories.pyramid_app('social_config')
|
|
199
|
+
authable_app = factories.pyramid_app('authable_config')
|
|
200
|
+
nopassconfirm_app = factories.pyramid_app('nopassconfirm_config')
|
|
201
|
+
nopassregister_app = factories.pyramid_app('nopassregister_config')
|
tests/tools.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Tools used for fullauth tests."""
|
|
2
|
+
from pyramid.view import view_config
|
|
3
|
+
from pyramid.compat import text_type
|
|
4
|
+
|
|
5
|
+
DEFAULT_USER = {
|
|
6
|
+
'username': text_type('u1'),
|
|
7
|
+
'password': text_type('password1'),
|
|
8
|
+
'email': text_type('email@example.com'),
|
|
9
|
+
'address_ip': text_type('127.0.0.1')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def authenticate(app, email=DEFAULT_USER['email'],
|
|
14
|
+
password=DEFAULT_USER['password'],
|
|
15
|
+
remember=False,
|
|
16
|
+
response_code=303):
|
|
17
|
+
"""Authenticate user."""
|
|
18
|
+
res = app.get('/login')
|
|
19
|
+
form = res.form
|
|
20
|
+
|
|
21
|
+
form['email'] = email
|
|
22
|
+
form['password'] = password
|
|
23
|
+
if remember:
|
|
24
|
+
form['remember'] = 1
|
|
25
|
+
|
|
26
|
+
res = form.submit()
|
|
27
|
+
|
|
28
|
+
# We've been redirected after log in
|
|
29
|
+
assert res.status_code == response_code
|
|
30
|
+
|
|
31
|
+
return res
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def is_user_logged(app):
|
|
35
|
+
"""Check for auth_tkt cookies beeing set to see if user is logged in."""
|
|
36
|
+
cookies = app.cookies
|
|
37
|
+
if 'auth_tkt' in cookies and cookies['auth_tkt']:
|
|
38
|
+
|
|
39
|
+
return True
|
|
40
|
+
return False
|
|
41
|
+
|
|
42
|
+
# this below are additional views crafted for tests.
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def include_views(config):
|
|
46
|
+
"""Dummy pyramid 'plugin' adding dummy secret view."""
|
|
47
|
+
config.add_route('secret', '/secret')
|
|
48
|
+
config.scan('tests.tools')
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@view_config(route_name="secret", permission="super_high", renderer='json')
|
|
52
|
+
def secret_view(request):
|
|
53
|
+
"""Dummy view with redirect to login."""
|
|
54
|
+
return {}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Test for recognizing default settings.
|
|
3
|
+
|
|
4
|
+
Also helps to keeping them in line.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_defaults(default_config):
|
|
9
|
+
"""Load defaults config for fullauth."""
|
|
10
|
+
# Config should get created based on fullauth defaults
|
|
11
|
+
assert 'fullauth' in default_config.registry['config']
|
|
12
|
+
# csrf should be turned on by default
|
|
13
|
+
assert default_config.registry['config']['fullauth']['check_csrf'] is True
|
|
14
|
+
# also hashalg should be anything but not md5 by default.
|
|
15
|
+
assert default_config.registry['config']['fullauth']['AuthTkt']['hashalg'] is not 'md5'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Test groupfinder."""
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from pyramid_fullauth.auth import groupfinder
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.mark.parametrize(['is_admin', 'is_active', 'groups'],
|
|
8
|
+
[(True, True, ['s:superadmin', 's:user']),
|
|
9
|
+
(True, False, ['s:superadmin', 's:inactive']),
|
|
10
|
+
(False, True, ['s:user']),
|
|
11
|
+
(False, False, ['s:inactive'])])
|
|
12
|
+
def test_groupfinder(web_request, db_session, user, is_admin, is_active, groups):
|
|
13
|
+
"""Return special group assigned for user."""
|
|
14
|
+
user = db_session.merge(user)
|
|
15
|
+
user.is_admin = is_admin
|
|
16
|
+
user.is_active = is_active
|
|
17
|
+
|
|
18
|
+
web_request.user = user
|
|
19
|
+
assigned_groups = groupfinder(user.id, web_request)
|
|
20
|
+
assert groups == assigned_groups
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Unittest for social login view."""
|
|
2
|
+
import pytest
|
|
3
|
+
import mock
|
|
4
|
+
from pyramid.compat import text_type
|
|
5
|
+
|
|
6
|
+
from pyramid_fullauth.views.social import SocialLoginViews
|
|
7
|
+
from tests.conftest import py2only
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@py2only
|
|
11
|
+
@pytest.mark.parametrize('profile, email', [
|
|
12
|
+
(
|
|
13
|
+
{
|
|
14
|
+
'accounts': [{'domain': text_type('facebook.com'), 'userid': text_type('2343')}],
|
|
15
|
+
'displayName': text_type('teddy'),
|
|
16
|
+
'verifiedEmail': text_type('verified@email.co.uk'),
|
|
17
|
+
'preferredUsername': text_type('teddy'),
|
|
18
|
+
'emails': [{'value': text_type('aasd@bwwqwe.pl')}],
|
|
19
|
+
'name': text_type('ted')
|
|
20
|
+
},
|
|
21
|
+
'verified@email.co.uk'
|
|
22
|
+
), (
|
|
23
|
+
{
|
|
24
|
+
'accounts': [{'domain': text_type('facebook.com'), 'userid': text_type('2343')}],
|
|
25
|
+
'displayName': text_type('teddy'),
|
|
26
|
+
'preferredUsername': text_type('teddy'),
|
|
27
|
+
'emails': [{'value': text_type('aasd@bwwqwe.pl')}],
|
|
28
|
+
'name': text_type('ted')
|
|
29
|
+
},
|
|
30
|
+
'aasd@bwwqwe.pl'
|
|
31
|
+
), (
|
|
32
|
+
{
|
|
33
|
+
'accounts': [{'domain': text_type('facebook.com'), 'userid': text_type('2343')}],
|
|
34
|
+
'displayName': text_type('teddy'),
|
|
35
|
+
'preferredUsername': text_type('teddy'),
|
|
36
|
+
'emails': [{}],
|
|
37
|
+
'name': text_type('ted')
|
|
38
|
+
},
|
|
39
|
+
'2343@facebook.com'
|
|
40
|
+
), (
|
|
41
|
+
{
|
|
42
|
+
'accounts': [{'domain': text_type('facebook.com'), 'userid': text_type('2343')}],
|
|
43
|
+
'displayName': text_type('teddy'),
|
|
44
|
+
'preferredUsername': text_type('teddy'),
|
|
45
|
+
'emails': [],
|
|
46
|
+
'name': text_type('ted')
|
|
47
|
+
},
|
|
48
|
+
'2343@facebook.com'
|
|
49
|
+
), (
|
|
50
|
+
{
|
|
51
|
+
'accounts': [{'domain': text_type('facebook.com'), 'userid': text_type('2343')}],
|
|
52
|
+
'displayName': text_type('teddy'),
|
|
53
|
+
'preferredUsername': text_type('teddy'),
|
|
54
|
+
'name': text_type('ted')
|
|
55
|
+
},
|
|
56
|
+
'2343@facebook.com'
|
|
57
|
+
),
|
|
58
|
+
])
|
|
59
|
+
def test_email_from_context(profile, email):
|
|
60
|
+
"""Test email_from_context email getting method."""
|
|
61
|
+
from velruse import AuthenticationComplete
|
|
62
|
+
context = AuthenticationComplete(
|
|
63
|
+
profile,
|
|
64
|
+
{'oauthAccessToken': '7897048593434'},
|
|
65
|
+
text_type('facebook'),
|
|
66
|
+
text_type('facebook')
|
|
67
|
+
)
|
|
68
|
+
view = SocialLoginViews(mock.MagicMock())
|
|
69
|
+
assert view._email_from_context(context) == email
|
tests/unit/test_tools.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Test fullauth's tools."""
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from pyramid_fullauth.tools import validate_passsword, password_generator
|
|
5
|
+
from pyramid_fullauth.exceptions import (
|
|
6
|
+
EmptyError, ShortPasswordError, PasswordConfirmMismatchError
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.mark.parametrize(('password', 'exception'),
|
|
11
|
+
[('', EmptyError),
|
|
12
|
+
('1234', ShortPasswordError),
|
|
13
|
+
('123456789', PasswordConfirmMismatchError)
|
|
14
|
+
])
|
|
15
|
+
def test_raises_errors(web_request, password, exception):
|
|
16
|
+
"""Test validate_passsword possible exceptions."""
|
|
17
|
+
with pytest.raises(exception):
|
|
18
|
+
validate_passsword(web_request, password)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.mark.parametrize('length', [5, 6])
|
|
22
|
+
def test_password_generator(length):
|
|
23
|
+
"""Test password_generator generating proper length of a random password."""
|
|
24
|
+
assert len(password_generator(length)) == length
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""User active method tests."""
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from pyramid_fullauth.models import User
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_is_active_error():
|
|
8
|
+
"""is_active can only be modified on object in session."""
|
|
9
|
+
with pytest.raises(AttributeError):
|
|
10
|
+
user = User()
|
|
11
|
+
user.is_active = True
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_is_active(db_session, user):
|
|
15
|
+
"""
|
|
16
|
+
Test is_active attribute.
|
|
17
|
+
|
|
18
|
+
Setting is_active to True, should result in change of activated_at date being set
|
|
19
|
+
Setting to false, should set deactivated_at.
|
|
20
|
+
"""
|
|
21
|
+
user = db_session.merge(user)
|
|
22
|
+
|
|
23
|
+
assert not user.is_active
|
|
24
|
+
assert not user.activated_at
|
|
25
|
+
user.is_active = True
|
|
26
|
+
assert user.is_active
|
|
27
|
+
assert user.activated_at
|
|
28
|
+
assert not user.deactivated_at
|
|
29
|
+
user.is_active = False
|
|
30
|
+
assert not user.is_active
|
|
31
|
+
assert user.deactivated_at
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Test admin related behaviour on user model."""
|
|
2
|
+
import pytest
|
|
3
|
+
import transaction
|
|
4
|
+
from pyramid.compat import text_type
|
|
5
|
+
|
|
6
|
+
from pyramid_fullauth.models import User
|
|
7
|
+
from pyramid_fullauth.exceptions import DeleteException
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_regular_user_not_admin(db_session, user):
|
|
11
|
+
"""Regular user is_admin flag test."""
|
|
12
|
+
user = db_session.merge(user)
|
|
13
|
+
|
|
14
|
+
# Default user should not be an admin
|
|
15
|
+
assert not user.is_admin
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_remove_last_admin(db_session, user):
|
|
19
|
+
"""
|
|
20
|
+
Admin user is_admin flag test.
|
|
21
|
+
|
|
22
|
+
At least one admin needed.
|
|
23
|
+
"""
|
|
24
|
+
user = db_session.merge(user)
|
|
25
|
+
user.is_admin = True
|
|
26
|
+
transaction.commit()
|
|
27
|
+
user = db_session.merge(user)
|
|
28
|
+
|
|
29
|
+
with pytest.raises(AttributeError):
|
|
30
|
+
user.is_admin = False
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_delete_admin(db_session, user):
|
|
34
|
+
"""Admin user soft delete behaviour - more than one admins present."""
|
|
35
|
+
user = db_session.merge(user)
|
|
36
|
+
user2 = User(
|
|
37
|
+
email=text_type('test2@example.com'),
|
|
38
|
+
address_ip='127.0.0.1',
|
|
39
|
+
password='pass',
|
|
40
|
+
is_admin=True
|
|
41
|
+
)
|
|
42
|
+
db_session.add(user2)
|
|
43
|
+
user.is_admin = True
|
|
44
|
+
transaction.commit()
|
|
45
|
+
user = db_session.merge(user)
|
|
46
|
+
|
|
47
|
+
user.delete()
|
|
48
|
+
|
|
49
|
+
assert user.deleted_at
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_delete_last_admin(db_session, user):
|
|
53
|
+
"""Admin user soft delete - only one admin, no deleting possible."""
|
|
54
|
+
user = db_session.merge(user)
|
|
55
|
+
|
|
56
|
+
user.is_admin = True
|
|
57
|
+
transaction.commit()
|
|
58
|
+
user = db_session.merge(user)
|
|
59
|
+
|
|
60
|
+
with pytest.raises(DeleteException):
|
|
61
|
+
user.delete()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Test email related User methods."""
|
|
2
|
+
from pyramid.compat import text_type
|
|
3
|
+
from pyramid_fullauth.models import User
|
|
4
|
+
|
|
5
|
+
NEW_EMAIL = text_type('new@example.com')
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_set_new_email():
|
|
9
|
+
"""
|
|
10
|
+
Test User.set_new_email method.
|
|
11
|
+
|
|
12
|
+
setting new email should result in setting new_email field,
|
|
13
|
+
and key used to activate the change.
|
|
14
|
+
"""
|
|
15
|
+
user = User()
|
|
16
|
+
assert user.email_change_key is None
|
|
17
|
+
assert user.new_email is None
|
|
18
|
+
user.set_new_email(NEW_EMAIL)
|
|
19
|
+
|
|
20
|
+
assert user.new_email == NEW_EMAIL
|
|
21
|
+
assert user.email_change_key
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_change_email():
|
|
25
|
+
"""
|
|
26
|
+
Test User.change_email method.
|
|
27
|
+
|
|
28
|
+
Calling it should copy new email set by set_new_email method
|
|
29
|
+
into regular email field.
|
|
30
|
+
"""
|
|
31
|
+
user = User()
|
|
32
|
+
assert not user.email
|
|
33
|
+
user.set_new_email(NEW_EMAIL)
|
|
34
|
+
user.change_email()
|
|
35
|
+
|
|
36
|
+
assert not user.email_change_key
|
|
37
|
+
assert user.email == NEW_EMAIL
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Password related user model behaviour."""
|
|
2
|
+
import pytest
|
|
3
|
+
from pyramid.compat import text_type
|
|
4
|
+
import transaction
|
|
5
|
+
|
|
6
|
+
from pyramid_fullauth.models import User
|
|
7
|
+
from pyramid_fullauth.exceptions import EmptyError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_hash_checkout(db_session, user):
|
|
11
|
+
"""User.check_password correct one."""
|
|
12
|
+
user = db_session.merge(user)
|
|
13
|
+
assert user.check_password(text_type('password1')) is True
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_hash_checkout_bad(db_session, user):
|
|
17
|
+
"""User.check_password() wrong password."""
|
|
18
|
+
user = db_session.merge(user)
|
|
19
|
+
assert user.check_password(text_type('password2')) is False
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.mark.parametrize('password', ['haselko', 'haselko' * 1000])
|
|
23
|
+
def test_password_change(db_session, user, password):
|
|
24
|
+
"""User password change."""
|
|
25
|
+
new_password = text_type(password)
|
|
26
|
+
|
|
27
|
+
user = db_session.merge(user)
|
|
28
|
+
old_password = user.password
|
|
29
|
+
old_salt = user._salt
|
|
30
|
+
user.password = new_password
|
|
31
|
+
transaction.commit()
|
|
32
|
+
|
|
33
|
+
user = db_session.query(User).filter(User.username == text_type('u1')).one()
|
|
34
|
+
assert not user.password == old_password
|
|
35
|
+
assert not user._salt == old_salt
|
|
36
|
+
assert user.check_password(new_password)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_password_empty(db_session, user):
|
|
40
|
+
"""User try to set empty password."""
|
|
41
|
+
user = db_session.merge(user)
|
|
42
|
+
|
|
43
|
+
with pytest.raises(EmptyError):
|
|
44
|
+
user.password = text_type('')
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_set_reset(db_session, user):
|
|
48
|
+
"""User.set_reset - generates reset key for those who forgot their password. """
|
|
49
|
+
user = db_session.merge(user)
|
|
50
|
+
assert not user.reset_key
|
|
51
|
+
user.set_reset()
|
|
52
|
+
assert user.reset_key
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Test provider related user methods."""
|
|
2
|
+
from pyramid.compat import text_type
|
|
3
|
+
import transaction
|
|
4
|
+
|
|
5
|
+
from pyramid_fullauth.models import User
|
|
6
|
+
from pyramid_fullauth.models import AuthenticationProvider
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_user_provider_id(db_session, user):
|
|
10
|
+
"""User provider_id returns proper provider identification."""
|
|
11
|
+
user = db_session.merge(user)
|
|
12
|
+
email = user.email
|
|
13
|
+
# Provider does not exists yet
|
|
14
|
+
assert not user.provider_id('email')
|
|
15
|
+
|
|
16
|
+
provider = AuthenticationProvider()
|
|
17
|
+
provider.provider = text_type('email')
|
|
18
|
+
provider.provider_id = email
|
|
19
|
+
user.providers.append(provider)
|
|
20
|
+
transaction.commit()
|
|
21
|
+
|
|
22
|
+
user = db_session.query(User).filter(User.email == email).one()
|
|
23
|
+
# Provider exists
|
|
24
|
+
assert user.provider_id('email') == email
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Test user representation."""
|
|
2
|
+
from pyramid.compat import text_type
|
|
3
|
+
|
|
4
|
+
from pyramid_fullauth.models import User
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_introduce_email():
|
|
8
|
+
"""user gets introduced by e-mail only."""
|
|
9
|
+
user = User()
|
|
10
|
+
user.email = text_type('test@test.pl')
|
|
11
|
+
# To string should return concatenated email
|
|
12
|
+
assert str(user) == 'test@...'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_introduce_username():
|
|
16
|
+
"""user gets introduced by username."""
|
|
17
|
+
user = User()
|
|
18
|
+
# 'User not saved should be represented by \'None\'')
|
|
19
|
+
assert str(user) == 'None'
|
|
20
|
+
user.id = 1
|
|
21
|
+
# if id is set, user should be presented with it
|
|
22
|
+
assert str(user) == '1'
|
|
23
|
+
|
|
24
|
+
user.email = text_type('test@test.pl')
|
|
25
|
+
user.username = text_type('testowy')
|
|
26
|
+
# To string should return username
|
|
27
|
+
assert str(user) == 'testowy'
|
|
28
|
+
# User should be represented by "<User (\'1\')>"
|
|
29
|
+
assert user.__repr__() == "<User ('1')>"
|