|
|
|
import pytest
|
|
|
|
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
from pyramid.testing import DummyRequest
|
|
|
|
|
|
|
|
from .. import app_config, dbsession, get_example_user # noqa: F401
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
'key,result', [('NEW', 'role:new'), ('USER', 'role:user')]
|
|
|
|
)
|
|
|
|
def test_role_principal(key, result):
|
|
|
|
''' test the principal representation of a role '''
|
|
|
|
from ordr.models.account import Role
|
|
|
|
subject = Role[key]
|
|
|
|
assert subject.principal == result
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
'key,result', [('NEW', 'New'), ('USER', 'User')]
|
|
|
|
)
|
|
|
|
def test_role__str__(key, result):
|
|
|
|
''' test the string representation of a role '''
|
|
|
|
from ordr.models.account import Role
|
|
|
|
subject = Role[key]
|
|
|
|
assert str(subject) == result
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('id_', [1, 2, 5, 123])
|
|
|
|
def test_user_principal(id_):
|
|
|
|
''' test the principal representation of a user '''
|
|
|
|
from ordr.models.account import User
|
|
|
|
user = User(id=id_)
|
|
|
|
assert user.principal == f'user:{id_}'
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
'name, principals', [
|
|
|
|
('UNVALIDATED', ['role:unvalidated']),
|
|
|
|
('NEW', ['role:new']),
|
|
|
|
('USER', ['role:user']),
|
|
|
|
('PURCHASER', ['role:purchaser', 'role:user']),
|
|
|
|
('ADMIN', ['role:admin', 'role:purchaser', 'role:user']),
|
|
|
|
('INACTIVE', ['role:inactive']),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
def test_user_principals(name, principals):
|
|
|
|
''' test all principals of a user '''
|
|
|
|
from ordr.models.account import User, Role
|
|
|
|
|
|
|
|
user = User(id=1, role=Role[name])
|
|
|
|
expected = ['user:1']
|
|
|
|
expected.extend(principals)
|
|
|
|
|
|
|
|
assert expected == user.principals
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
'name, expected', [
|
|
|
|
('UNVALIDATED', False),
|
|
|
|
('NEW', False),
|
|
|
|
('USER', True),
|
|
|
|
('PURCHASER', True),
|
|
|
|
('ADMIN', True),
|
|
|
|
('INACTIVE', False),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
def test_user_is_active(name, expected):
|
|
|
|
''' test the calculated property 'active' of a user '''
|
|
|
|
from ordr.models.account import User, Role
|
|
|
|
user = User(id=1, role=Role[name])
|
|
|
|
assert expected == user.is_active
|
|
|
|
|
|
|
|
|
|
|
|
def test_user_set_password():
|
|
|
|
''' test 'set_password()' method of a user '''
|
|
|
|
from ordr.models.account import User
|
|
|
|
from ordr.security import password_context
|
|
|
|
|
|
|
|
password_context.update(schemes=['argon2'])
|
|
|
|
user = User()
|
|
|
|
assert user.password_hash is None
|
|
|
|
|
|
|
|
user.set_password('password')
|
|
|
|
assert user.password_hash.startswith('$argon2')
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
'password,expected', [
|
|
|
|
('', False),
|
|
|
|
('wrong', False),
|
|
|
|
('password', True),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
def test_user_check_password(password, expected):
|
|
|
|
''' test the 'check_password()' method of a user '''
|
|
|
|
from ordr.models.account import User
|
|
|
|
from ordr.security import password_context
|
|
|
|
|
|
|
|
password_context.update(schemes=['argon2'])
|
|
|
|
hash = ('$argon2i$v=19$m=512,t=2,p=2$'
|
|
|
|
'YcyZMyak9D7nvFfKmVOq1Q$fnzNh58HWfvxHvRDGjhTqA'
|
|
|
|
)
|
|
|
|
user = User(password_hash=hash)
|
|
|
|
|
|
|
|
assert user.check_password(password) == expected
|
|
|
|
|
|
|
|
|
|
|
|
def test_user_check_password_updates_old_sheme():
|
|
|
|
''' test that 'check_password()' updates the hash off an old scheme '''
|
|
|
|
from ordr.models.account import User
|
|
|
|
from ordr.security import password_context
|
|
|
|
|
|
|
|
password_context.update(
|
|
|
|
schemes=['argon2', 'bcrypt'],
|
|
|
|
default='argon2',
|
|
|
|
deprecated='auto'
|
|
|
|
)
|
|
|
|
old_hash = '$2b$12$6ljSfpLaXBeEVOeaP1scUe6IAa0cztM.UBbjc1PdrI4j0vwgoYgpi'
|
|
|
|
user = User(password_hash=old_hash)
|
|
|
|
|
|
|
|
assert user.check_password('password')
|
|
|
|
assert user.password_hash.startswith('$argon2')
|
|
|
|
assert user.check_password('password')
|
|
|
|
|
|
|
|
|
|
|
|
def test_user__str__():
|
|
|
|
''' test the string representation of a user '''
|
|
|
|
from ordr.models.account import User
|
|
|
|
user = User(username='Eric Idle')
|
|
|
|
assert str(user) == 'Eric Idle'
|
|
|
|
|
|
|
|
|
|
|
|
def test_user_issue_token(app_config): # noqa: F811
|
|
|
|
''' test the 'issue_token()' method of a user '''
|
|
|
|
from ordr.models.account import User, Token, TokenSubject
|
|
|
|
|
|
|
|
request = DummyRequest()
|
|
|
|
user = User()
|
|
|
|
token = user.issue_token(request, TokenSubject.REGISTRATION, {'foo': 1})
|
|
|
|
|
|
|
|
assert isinstance(token, Token)
|
|
|
|
assert token.hash is not None
|
|
|
|
assert token.subject == TokenSubject.REGISTRATION
|
|
|
|
assert token.payload == {'foo': 1}
|
|
|
|
assert token.owner == user
|
|
|
|
|
|
|
|
|
|
|
|
def test_token_issue_token(app_config): # noqa: F811
|
|
|
|
''' test the 'issue()' class method of the token class '''
|
|
|
|
from ordr.models.account import User, Token, TokenSubject
|
|
|
|
|
|
|
|
request = DummyRequest()
|
|
|
|
user = User()
|
|
|
|
token = Token.issue(request, user, TokenSubject.REGISTRATION, {'foo': 1})
|
|
|
|
expected_expires = datetime.utcnow() + timedelta(minutes=5)
|
|
|
|
|
|
|
|
assert isinstance(token, Token)
|
|
|
|
assert token.hash is not None
|
|
|
|
assert token.subject == TokenSubject.REGISTRATION
|
|
|
|
assert token.payload == {'foo': 1}
|
|
|
|
assert token.owner == user
|
|
|
|
assert token.expires.timestamp() == pytest.approx(
|
|
|
|
expected_expires.timestamp(),
|
|
|
|
abs=1
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize( # noqa: F811
|
|
|
|
'subject,delta', [('REGISTRATION', 5), ('RESET_PASSWORD', 10)]
|
|
|
|
)
|
|
|
|
def test_token_issue_token_time_from_settings(app_config, subject, delta):
|
|
|
|
''' test that 'issue()' uses the exiration time from setting '''
|
|
|
|
from ordr.models.account import User, Token, TokenSubject
|
|
|
|
|
|
|
|
request = DummyRequest()
|
|
|
|
request.registry.settings['token_expiry.reset_password'] = 10
|
|
|
|
user = User()
|
|
|
|
token_subject = TokenSubject[subject]
|
|
|
|
token = Token.issue(request, user, token_subject, None)
|
|
|
|
expected_expires = datetime.utcnow() + timedelta(minutes=delta)
|
|
|
|
|
|
|
|
assert token.expires.timestamp() == pytest.approx(
|
|
|
|
expected_expires.timestamp(),
|
|
|
|
abs=1
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('use_subject', [True, False]) # noqa: F811
|
|
|
|
def test_registration_token_retrieve_ok(dbsession, use_subject):
|
|
|
|
''' test 'retrieve()' class method returns token instance '''
|
|
|
|
from ordr.models.account import Role, Token, TokenSubject
|
|
|
|
|
|
|
|
request = DummyRequest(dbsession=dbsession)
|
|
|
|
user = get_example_user(Role.NEW)
|
|
|
|
token = user.issue_token(request, TokenSubject.REGISTRATION)
|
|
|
|
dbsession.add(user)
|
|
|
|
dbsession.flush()
|
|
|
|
|
|
|
|
subject = TokenSubject.REGISTRATION if use_subject else None
|
|
|
|
result = Token.retrieve(request, token.hash, subject=subject)
|
|
|
|
|
|
|
|
assert result == token
|
|
|
|
|
|
|
|
|
|
|
|
def test_registration_token_retrieve_not_found(dbsession): # noqa: F811
|
|
|
|
''' test 'retrieve()' class method returns None if token not found '''
|
|
|
|
from ordr.models.account import Role, Token, TokenSubject
|
|
|
|
|
|
|
|
request = DummyRequest(dbsession=dbsession)
|
|
|
|
user = get_example_user(Role.NEW)
|
|
|
|
user.issue_token(request, TokenSubject.REGISTRATION)
|
|
|
|
dbsession.add(user)
|
|
|
|
dbsession.flush()
|
|
|
|
|
|
|
|
result = Token.retrieve(request, 'unknown hash')
|
|
|
|
|
|
|
|
assert result is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_registration_token_retrieve_wrong_subject(dbsession): # noqa: F811
|
|
|
|
''' test 'retrieve()' class method returns None if wrong subject used '''
|
|
|
|
from ordr.models.account import Role, Token, TokenSubject
|
|
|
|
|
|
|
|
request = DummyRequest(dbsession=dbsession)
|
|
|
|
user = get_example_user(Role.NEW)
|
|
|
|
token = user.issue_token(request, TokenSubject.REGISTRATION)
|
|
|
|
dbsession.add(user)
|
|
|
|
dbsession.flush()
|
|
|
|
|
|
|
|
result = Token.retrieve(
|
|
|
|
request,
|
|
|
|
token.hash,
|
|
|
|
subject=TokenSubject.RESET_PASSWORD
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_registration_token_expired_raises_exception(dbsession): # noqa: F811
|
|
|
|
''' test 'retrieve()' class method raises exception if token is expired '''
|
|
|
|
from ordr.models.account import Role, Token, TokenSubject, TokenExpired
|
|
|
|
|
|
|
|
request = DummyRequest(dbsession=dbsession)
|
|
|
|
user = get_example_user(Role.NEW)
|
|
|
|
token = user.issue_token(request, TokenSubject.REGISTRATION)
|
|
|
|
token.expires = datetime.utcnow() - timedelta(weeks=1)
|
|
|
|
dbsession.add(user)
|
|
|
|
dbsession.flush()
|
|
|
|
|
|
|
|
with pytest.raises(TokenExpired):
|
|
|
|
Token.retrieve(request, token.hash)
|
|
|
|
|
|
|
|
dbsession.flush()
|
|
|
|
assert dbsession.query(Token).count() == 0
|