281 lines
9.2 KiB
Python
281 lines
9.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import pytest
|
|
import hashlib
|
|
import re
|
|
import shutil
|
|
from quixote import cleanup
|
|
|
|
from wcs.qommon import force_str
|
|
from wcs.qommon.http_request import HTTPRequest
|
|
from wcs.qommon.ident.password_accounts import PasswordAccount
|
|
|
|
from utilities import get_app, create_temporary_pub, clean_temporary_pub
|
|
|
|
def pytest_generate_tests(metafunc):
|
|
if 'pub' in metafunc.fixturenames:
|
|
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
|
|
|
|
@pytest.fixture
|
|
def pub(request):
|
|
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
|
|
|
|
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
|
|
pub.set_app_dir(req)
|
|
pub.cfg['misc'] = {'charset': 'utf-8'}
|
|
pub.cfg['identification'] = {'methods': ['password']}
|
|
pub.cfg['identities'] = {'creation': 'self'}
|
|
pub.write_cfg()
|
|
|
|
return pub
|
|
|
|
def teardown_module(module):
|
|
clean_temporary_pub()
|
|
|
|
def test_no_user_registration(pub):
|
|
# makes sure the page is not published unless configured
|
|
app = get_app(pub)
|
|
pub.cfg['identification'] = {'methods': ['password']}
|
|
pub.cfg['identities'] = {'creation': 'admin'}
|
|
pub.write_cfg()
|
|
app.get('/register/', status=404)
|
|
pub.cfg['identities'] = {'creation': 'self'}
|
|
pub.write_cfg()
|
|
|
|
def test_link_on_login_page(pub):
|
|
app = get_app(pub)
|
|
page = app.get('/login/')
|
|
assert '/register/' in page.text
|
|
|
|
def test_no_password(pub):
|
|
app = get_app(pub)
|
|
page = app.get('/register/')
|
|
register_form = page.forms[0]
|
|
assert 'username' in register_form.fields
|
|
assert 'password' not in register_form.fields
|
|
|
|
def test_user_registration_mismatch(pub):
|
|
pub.cfg['passwords'] = {'generate': False}
|
|
pub.write_cfg()
|
|
app = get_app(pub)
|
|
page = app.get('/register/')
|
|
register_form = page.forms[0]
|
|
register_form['username'] = 'foo'
|
|
register_form['password$pwd1'] = 'bar'
|
|
register_form['password$pwd2'] = 'baz'
|
|
resp = register_form.submit()
|
|
assert 'Passwords do not match' in resp.text
|
|
|
|
def do_user_registration(pub, username='foo', password='bar'):
|
|
initial_user_count = pub.user_class.count()
|
|
initial_account_count = PasswordAccount.count()
|
|
app = get_app(pub)
|
|
page = app.get('/register/')
|
|
register_form = page.forms[0]
|
|
register_form['username'] = username
|
|
if password is not None:
|
|
register_form['password$pwd1'] = password
|
|
register_form['password$pwd2'] = password
|
|
resp = register_form.submit()
|
|
assert resp.status_int == 302
|
|
assert resp.location == 'http://example.net/login/'
|
|
|
|
assert pub.user_class.count() == initial_user_count + 1
|
|
assert PasswordAccount.count() == initial_account_count + 1
|
|
|
|
account = PasswordAccount.get(username)
|
|
user = account.get_user()
|
|
if password is not None:
|
|
user2 = PasswordAccount.get_with_credentials(username, password)
|
|
assert user.id == user2.id
|
|
|
|
def test_user_registration(pub):
|
|
pub.user_class.wipe()
|
|
PasswordAccount.wipe()
|
|
pub.cfg['passwords'] = {'generate': False}
|
|
pub.write_cfg()
|
|
do_user_registration(pub)
|
|
|
|
account = PasswordAccount.get('foo')
|
|
assert account.password == 'bar' # check it's in clear text
|
|
|
|
def test_user_password_hashing(pub):
|
|
pub.user_class.wipe()
|
|
PasswordAccount.wipe()
|
|
pub.cfg['passwords'] = {'generate': False, 'hashing_algo': 'sha256'}
|
|
pub.write_cfg()
|
|
do_user_registration(pub)
|
|
|
|
account = PasswordAccount.get('foo')
|
|
assert account.password == hashlib.sha256(b'bar').hexdigest()
|
|
|
|
def test_user_password_accents(pub):
|
|
pub.user_class.wipe()
|
|
PasswordAccount.wipe()
|
|
pub.cfg['passwords'] = {'generate': False, 'hashing_algo': None}
|
|
pub.write_cfg()
|
|
password = force_str(u'fooë')
|
|
do_user_registration(pub, password=password)
|
|
|
|
account = PasswordAccount.get('foo')
|
|
assert account.password == password
|
|
|
|
def test_admin_notification(pub, emails):
|
|
pub.cfg['identities'] = {'creation': 'self', 'notify-on-register': True}
|
|
pub.write_cfg()
|
|
pub.user_class.wipe()
|
|
PasswordAccount.wipe()
|
|
user = pub.user_class(name='admin')
|
|
user.is_admin = True
|
|
user.email = 'admin@localhost'
|
|
user.store()
|
|
|
|
pub.cfg['passwords'] = {'generate': False}
|
|
pub.write_cfg()
|
|
do_user_registration(pub)
|
|
|
|
assert emails.get('New Registration')
|
|
assert emails.get('New Registration').get('email_rcpt') == ['admin@localhost']
|
|
|
|
def test_user_notification(pub, emails):
|
|
pub.cfg['identities'] = {'creation': 'self', 'notify-on-register': False,
|
|
'email-as-username': True}
|
|
pub.write_cfg()
|
|
pub.user_class.wipe()
|
|
PasswordAccount.wipe()
|
|
user = pub.user_class(name='admin')
|
|
user.is_admin = True
|
|
user.email = 'admin@localhost'
|
|
user.store()
|
|
|
|
pub.cfg['passwords'] = {'generate': True}
|
|
pub.write_cfg()
|
|
do_user_registration(pub, username='foo@localhost', password=None)
|
|
|
|
account = PasswordAccount.get('foo@localhost')
|
|
|
|
assert emails.get('Welcome to example.net')
|
|
assert emails.get('Welcome to example.net').get('to') == 'foo@localhost'
|
|
assert account.password in emails.get('Welcome to example.net').get('payload')
|
|
|
|
def test_user_login(pub):
|
|
pub.cfg['identities'] = {'creation': 'self', 'notify-on-register': False}
|
|
pub.user_class.wipe()
|
|
PasswordAccount.wipe()
|
|
pub.cfg['passwords'] = {'generate': False, 'hashing_algo': 'sha256'}
|
|
pub.write_cfg()
|
|
do_user_registration(pub)
|
|
|
|
# wrong password
|
|
app = get_app(pub)
|
|
resp = app.get('/login/')
|
|
resp.forms[0]['username'] = 'foo'
|
|
resp.forms[0]['password'] = 'foo'
|
|
resp = resp.forms[0].submit()
|
|
assert 'Invalid credentials' in resp.text
|
|
|
|
# correct passwod
|
|
app = get_app(pub)
|
|
resp = app.get('/login/')
|
|
resp.forms[0]['username'] = 'foo'
|
|
resp.forms[0]['password'] = 'bar'
|
|
resp = resp.forms[0].submit()
|
|
assert resp.location == 'http://example.net/'
|
|
|
|
def test_forgotten(pub, emails):
|
|
pub.cfg['identities'] = {'creation': 'self', 'notify-on-register': False}
|
|
pub.user_class.wipe()
|
|
PasswordAccount.wipe()
|
|
pub.cfg['passwords'] = {'generate': False, 'hashing_algo': 'sha256'}
|
|
pub.write_cfg()
|
|
do_user_registration(pub)
|
|
user_id = pub.user_class.select()[0].id
|
|
|
|
app = get_app(pub)
|
|
resp = app.get('/login/')
|
|
assert '/ident/password/forgotten' in resp.text
|
|
|
|
resp = app.get('/ident/password/forgotten')
|
|
resp.forms[0]['username'] = 'bar' # this account doesn't exist
|
|
resp = resp.forms[0].submit()
|
|
assert 'There is no user with that name or it has no email contact.'
|
|
|
|
resp = app.get('/ident/password/forgotten')
|
|
resp.forms[0]['username'] = 'foo' # this account doesn't have an email
|
|
resp = resp.forms[0].submit()
|
|
assert 'There is no user with that name or it has no email contact.'
|
|
|
|
user = pub.user_class.get(user_id)
|
|
user.email = 'foo@localhost'
|
|
user.store()
|
|
|
|
resp = app.get('/ident/password/forgotten')
|
|
resp.forms[0]['username'] = 'foo'
|
|
resp = resp.forms[0].submit()
|
|
assert 'A token for changing your password has been emailed to you.' in resp.text
|
|
|
|
assert emails.get('Change Password Request')
|
|
assert emails.get('Change Password Request')['to'] == 'foo@localhost'
|
|
body = emails.get('Change Password Request')['payload']
|
|
|
|
confirm_urls = re.findall(r'http://.*\w', body)
|
|
assert 'a=cfmpw' in confirm_urls[0]
|
|
assert 'a=cxlpw' in confirm_urls[1]
|
|
|
|
# cancel request
|
|
resp = app.get(confirm_urls[1])
|
|
assert 'Your request has been cancelled' in resp.text
|
|
|
|
resp = app.get(confirm_urls[1])
|
|
assert 'The token you submitted does not exist' in resp.text
|
|
|
|
# new forgotten request
|
|
resp = app.get('/ident/password/forgotten')
|
|
resp.forms[0]['username'] = 'foo'
|
|
resp = resp.forms[0].submit()
|
|
assert 'A token for changing your password has been emailed to you.' in resp.text
|
|
|
|
body = emails.get('Change Password Request')['payload']
|
|
confirm_urls = re.findall(r'http://.*\w', body)
|
|
assert 'a=cfmpw' in confirm_urls[0]
|
|
assert 'a=cxlpw' in confirm_urls[1]
|
|
|
|
resp = app.get(confirm_urls[0])
|
|
assert 'New password sent by email' in resp.text
|
|
assert emails.get('Your new password')
|
|
|
|
# check new password is working
|
|
new_password = re.findall('password: (.*)\n', emails.get('Your new password')['payload'])[0]
|
|
resp = app.get('/login/')
|
|
resp.forms[0]['username'] = 'foo'
|
|
resp.forms[0]['password'] = new_password
|
|
resp = resp.forms[0].submit()
|
|
assert resp.status_int == 302
|
|
|
|
# check forgotten page when user can choose the password
|
|
pub.cfg['passwords'] = {'generate': False, 'can_change': True}
|
|
pub.write_cfg()
|
|
|
|
resp = app.get('/ident/password/forgotten')
|
|
resp.forms[0]['username'] = 'foo'
|
|
resp = resp.forms[0].submit()
|
|
assert 'A token for changing your password has been emailed to you.' in resp.text
|
|
|
|
body = emails.get('Change Password Request')['payload']
|
|
confirm_urls = re.findall(r'http://.*\w', body)
|
|
assert 'a=cfmpw' in confirm_urls[0]
|
|
assert 'a=cxlpw' in confirm_urls[1]
|
|
|
|
resp = app.get(confirm_urls[0])
|
|
resp.forms[0]['new_password$pwd1'] = 'foo'
|
|
resp.forms[0]['new_password$pwd2'] = 'foo'
|
|
resp = resp.forms[0].submit()
|
|
assert resp.status_int == 302
|
|
|
|
# check new password is working
|
|
resp = app.get('/login/')
|
|
resp.forms[0]['username'] = 'foo'
|
|
resp.forms[0]['password'] = 'foo'
|
|
resp = resp.forms[0].submit()
|
|
assert resp.status_int == 302
|